cmd: Use CRT's popen instead of rewriting it.
[wine.git] / dlls / dwrite / tests / font.c
blobe2b5b9163f1c17e40544e30b748a2eca5ea123e8
1 /*
2 * Font related tests
4 * Copyright 2012, 2014-2020 Nikolay Sivov for CodeWeavers
5 * Copyright 2014 Aric Stewart for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <math.h>
23 #include <limits.h>
25 #define COBJMACROS
27 #include "windows.h"
28 #include "winternl.h"
29 #include "dwrite_3.h"
30 #include "initguid.h"
31 #include "d2d1.h"
33 #include "wine/test.h"
35 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
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_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
40 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
41 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
42 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
43 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
44 #define MS_KERN_TAG DWRITE_MAKE_OPENTYPE_TAG('k','e','r','n')
45 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
46 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
47 #define MS_CFF2_TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F','2')
48 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
49 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
50 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
51 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
52 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
54 /* 'sbix' formats */
55 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
56 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
57 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
59 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
60 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
62 #ifdef WORDS_BIGENDIAN
63 #define GET_BE_WORD(x) (x)
64 #define GET_BE_DWORD(x) (x)
65 #define GET_LE_WORD(x) RtlUshortByteSwap(x)
66 #define GET_LE_DWORD(x) RtlUlongByteSwap(x)
67 #else
68 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
69 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
70 #define GET_LE_WORD(x) (x)
71 #define GET_LE_DWORD(x) (x)
72 #endif
74 #define DEFINE_EXPECT(func) \
75 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
77 #define SET_EXPECT(func) \
78 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
80 #define CHECK_EXPECT2(func) \
81 do { \
82 ok(expect_ ##func, "unexpected call " #func "\n"); \
83 called_ ## func = TRUE; \
84 }while(0)
86 #define CHECK_EXPECT(func) \
87 do { \
88 CHECK_EXPECT2(func); \
89 expect_ ## func = FALSE; \
90 }while(0)
92 #define CHECK_CALLED(func) \
93 do { \
94 ok(called_ ## func, "expected " #func "\n"); \
95 expect_ ## func = called_ ## func = FALSE; \
96 }while(0)
98 #define CLEAR_CALLED(func) \
99 expect_ ## func = called_ ## func = FALSE
101 DEFINE_EXPECT(setfillmode);
103 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
104 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
106 ULONG rc;
107 IUnknown_AddRef(obj);
108 rc = IUnknown_Release(obj);
109 ok_(__FILE__,line)(rc == ref, "expected refcount %ld, got %ld\n", ref, rc);
112 #define EXPECT_REF_BROKEN(obj,ref,brokenref) _expect_ref_broken((IUnknown*)obj, ref, brokenref, __LINE__)
113 static void _expect_ref_broken(IUnknown* obj, ULONG ref, ULONG brokenref, int line)
115 ULONG rc;
116 IUnknown_AddRef(obj);
117 rc = IUnknown_Release(obj);
118 ok_(__FILE__,line)(rc == ref || broken(rc == brokenref), "expected refcount %ld, got %ld\n", ref, rc);
121 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, void *);
123 static const WCHAR test_fontfile[] = L"wine_test_font.ttf";
125 /* PANOSE is 10 bytes in size, need to pack the structure properly */
126 #include "pshpack2.h"
127 typedef struct
129 USHORT majorVersion;
130 USHORT minorVersion;
131 ULONG revision;
132 ULONG checksumadj;
133 ULONG magic;
134 USHORT flags;
135 USHORT unitsPerEm;
136 ULONGLONG created;
137 ULONGLONG modified;
138 SHORT xMin;
139 SHORT yMin;
140 SHORT xMax;
141 SHORT yMax;
142 USHORT macStyle;
143 USHORT lowestRecPPEM;
144 SHORT direction_hint;
145 SHORT index_format;
146 SHORT glyphdata_format;
147 } TT_HEAD;
149 enum TT_HEAD_MACSTYLE
151 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
152 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
153 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
154 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
155 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
156 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
157 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
160 struct tt_os2
162 USHORT version;
163 SHORT xAvgCharWidth;
164 USHORT usWeightClass;
165 USHORT usWidthClass;
166 SHORT fsType;
167 SHORT ySubscriptXSize;
168 SHORT ySubscriptYSize;
169 SHORT ySubscriptXOffset;
170 SHORT ySubscriptYOffset;
171 SHORT ySuperscriptXSize;
172 SHORT ySuperscriptYSize;
173 SHORT ySuperscriptXOffset;
174 SHORT ySuperscriptYOffset;
175 SHORT yStrikeoutSize;
176 SHORT yStrikeoutPosition;
177 SHORT sFamilyClass;
178 PANOSE panose;
179 ULONG ulUnicodeRange1;
180 ULONG ulUnicodeRange2;
181 ULONG ulUnicodeRange3;
182 ULONG ulUnicodeRange4;
183 CHAR achVendID[4];
184 USHORT fsSelection;
185 USHORT usFirstCharIndex;
186 USHORT usLastCharIndex;
187 /* According to the Apple spec, original version didn't have the below fields,
188 * version numbers were taken from the OpenType spec.
190 /* version 0 (TrueType 1.5) */
191 USHORT sTypoAscender;
192 USHORT sTypoDescender;
193 USHORT sTypoLineGap;
194 USHORT usWinAscent;
195 USHORT usWinDescent;
196 /* version 1 (TrueType 1.66) */
197 ULONG ulCodePageRange1;
198 ULONG ulCodePageRange2;
199 /* version 2 (OpenType 1.2) */
200 SHORT sxHeight;
201 SHORT sCapHeight;
202 USHORT usDefaultChar;
203 USHORT usBreakChar;
204 USHORT usMaxContext;
207 enum OS2_FSSELECTION {
208 OS2_FSSELECTION_ITALIC = 1 << 0,
209 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
210 OS2_FSSELECTION_NEGATIVE = 1 << 2,
211 OS2_FSSELECTION_OUTLINED = 1 << 3,
212 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
213 OS2_FSSELECTION_BOLD = 1 << 5,
214 OS2_FSSELECTION_REGULAR = 1 << 6,
215 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
216 OS2_FSSELECTION_WWS = 1 << 8,
217 OS2_FSSELECTION_OBLIQUE = 1 << 9
220 typedef struct {
221 ULONG Version;
222 ULONG italicAngle;
223 SHORT underlinePosition;
224 SHORT underlineThickness;
225 ULONG fixed_pitch;
226 ULONG minmemType42;
227 ULONG maxmemType42;
228 ULONG minmemType1;
229 ULONG maxmemType1;
230 } TT_POST;
232 typedef struct {
233 USHORT majorVersion;
234 USHORT minorVersion;
235 SHORT ascender;
236 SHORT descender;
237 SHORT linegap;
238 USHORT advanceWidthMax;
239 SHORT minLeftSideBearing;
240 SHORT minRightSideBearing;
241 SHORT xMaxExtent;
242 SHORT caretSlopeRise;
243 SHORT caretSlopeRun;
244 SHORT caretOffset;
245 SHORT reserved[4];
246 SHORT metricDataFormat;
247 USHORT numberOfHMetrics;
248 } TT_HHEA;
250 typedef struct {
251 DWORD version;
252 WORD ScriptList;
253 WORD FeatureList;
254 WORD LookupList;
255 } GSUB_Header;
257 typedef struct {
258 CHAR FeatureTag[4];
259 WORD Feature;
260 } OT_FeatureRecord;
262 typedef struct {
263 WORD FeatureCount;
264 OT_FeatureRecord FeatureRecord[1];
265 } OT_FeatureList;
267 typedef struct {
268 WORD FeatureParams;
269 WORD LookupCount;
270 WORD LookupListIndex[1];
271 } OT_Feature;
273 typedef struct {
274 WORD LookupCount;
275 WORD Lookup[1];
276 } OT_LookupList;
278 typedef struct {
279 WORD LookupType;
280 WORD LookupFlag;
281 WORD SubTableCount;
282 WORD SubTable[1];
283 } OT_LookupTable;
285 typedef struct {
286 WORD SubstFormat;
287 WORD Coverage;
288 WORD DeltaGlyphID;
289 } GSUB_SingleSubstFormat1;
291 typedef struct {
292 WORD SubstFormat;
293 WORD Coverage;
294 WORD GlyphCount;
295 WORD Substitute[1];
296 } GSUB_SingleSubstFormat2;
298 typedef struct {
299 WORD SubstFormat;
300 WORD ExtensionLookupType;
301 DWORD ExtensionOffset;
302 } GSUB_ExtensionPosFormat1;
304 typedef struct {
305 WORD version;
306 WORD flags;
307 DWORD numStrikes;
308 DWORD strikeOffset[1];
309 } sbix_header;
311 typedef struct {
312 WORD ppem;
313 WORD ppi;
314 DWORD glyphDataOffsets[1];
315 } sbix_strike;
317 typedef struct {
318 WORD originOffsetX;
319 WORD originOffsetY;
320 DWORD graphicType;
321 BYTE data[1];
322 } sbix_glyph_data;
324 struct cblc_header
326 WORD majorVersion;
327 WORD minorVersion;
328 DWORD numSizes;
331 typedef struct {
332 BYTE res[12];
333 } sbitLineMetrics;
335 typedef struct {
336 DWORD indexSubTableArrayOffset;
337 DWORD indexTablesSize;
338 DWORD numberofIndexSubTables;
339 DWORD colorRef;
340 sbitLineMetrics hori;
341 sbitLineMetrics vert;
342 WORD startGlyphIndex;
343 WORD endGlyphIndex;
344 BYTE ppemX;
345 BYTE ppemY;
346 BYTE bitDepth;
347 BYTE flags;
348 } CBLCBitmapSizeTable;
350 typedef struct {
351 DWORD version;
352 WORD numGlyphs;
353 } maxp;
355 struct WOFFHeader
357 ULONG signature;
358 ULONG flavor;
359 ULONG length;
360 USHORT numTables;
361 USHORT reserved;
362 ULONG totalSfntSize;
363 USHORT majorVersion;
364 USHORT minorVersion;
365 ULONG metaOffset;
366 ULONG metaLength;
367 ULONG metaOrigLength;
368 ULONG privOffset;
369 ULONG privLength;
372 struct WOFFHeader2
374 ULONG signature;
375 ULONG flavor;
376 ULONG length;
377 USHORT numTables;
378 USHORT reserved;
379 ULONG totalSfntSize;
380 ULONG totalCompressedSize;
381 USHORT majorVersion;
382 USHORT minorVersion;
383 ULONG metaOffset;
384 ULONG metaLength;
385 ULONG metaOrigLength;
386 ULONG privOffset;
387 ULONG privLength;
390 struct cmap_encoding_record
392 WORD platformID;
393 WORD encodingID;
394 DWORD offset;
397 struct cmap_header
399 WORD version;
400 WORD num_tables;
401 struct cmap_encoding_record tables[1];
404 struct cmap_segmented_coverage_group
406 DWORD startCharCode;
407 DWORD endCharCode;
408 DWORD startGlyphID;
411 struct cmap_segmented_coverage
413 WORD format;
414 WORD reserved;
415 DWORD length;
416 DWORD language;
417 DWORD nGroups;
418 struct cmap_segmented_coverage_group groups[1];
421 struct cmap_segmented_mapping_0
423 WORD format;
424 WORD length;
425 WORD language;
426 WORD segCountX2;
427 WORD searchRange;
428 WORD entrySelector;
429 WORD rangeShift;
430 WORD endCode[1];
433 enum opentype_cmap_table_platform
435 OPENTYPE_CMAP_TABLE_PLATFORM_WIN = 3,
438 enum opentype_cmap_table_encoding
440 OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL = 0,
441 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP = 1,
442 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL = 10,
445 enum opentype_cmap_table_format
447 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
448 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12,
451 #include "poppack.h"
453 static void *create_factory_iid(REFIID riid)
455 IUnknown *factory = NULL;
456 DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, riid, &factory);
457 return factory;
460 static IDWriteFactory *create_factory(void)
462 IDWriteFactory *factory = create_factory_iid(&IID_IDWriteFactory);
463 ok(factory != NULL, "Failed to create factory.\n");
464 return factory;
467 static IDWriteFontFace *create_fontface(IDWriteFactory *factory)
469 IDWriteGdiInterop *interop;
470 IDWriteFontFace *fontface;
471 IDWriteFont *font;
472 LOGFONTW logfont;
473 HRESULT hr;
475 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
476 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
478 memset(&logfont, 0, sizeof(logfont));
479 logfont.lfHeight = 12;
480 logfont.lfWidth = 12;
481 logfont.lfWeight = FW_NORMAL;
482 logfont.lfItalic = 1;
483 lstrcpyW(logfont.lfFaceName, L"Tahoma");
485 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
486 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
488 hr = IDWriteFont_CreateFontFace(font, &fontface);
489 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
491 IDWriteFont_Release(font);
492 IDWriteGdiInterop_Release(interop);
494 return fontface;
497 static IDWriteFont *get_font(IDWriteFactory *factory, const WCHAR *name, DWRITE_FONT_STYLE style)
499 IDWriteFontCollection *collection;
500 IDWriteFontFamily *family;
501 IDWriteFont *font = NULL;
502 UINT32 index;
503 BOOL exists;
504 HRESULT hr;
506 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
507 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
509 index = ~0;
510 exists = FALSE;
511 hr = IDWriteFontCollection_FindFamilyName(collection, name, &index, &exists);
512 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
513 if (!exists) goto not_found;
515 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
516 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
518 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
519 DWRITE_FONT_STRETCH_NORMAL, style, &font);
520 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
522 IDWriteFontFamily_Release(family);
523 not_found:
524 IDWriteFontCollection_Release(collection);
525 return font;
528 static IDWriteFont *get_tahoma_instance(IDWriteFactory *factory, DWRITE_FONT_STYLE style)
530 IDWriteFont *font = get_font(factory, L"Tahoma", style);
531 ok(font != NULL, "failed to get Tahoma\n");
532 return font;
535 static WCHAR *create_testfontfile(const WCHAR *filename)
537 static WCHAR pathW[MAX_PATH];
538 DWORD written;
539 HANDLE file;
540 HRSRC res;
541 void *ptr;
543 GetTempPathW(ARRAY_SIZE(pathW), pathW);
544 lstrcatW(pathW, filename);
546 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
547 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", wine_dbgstr_w(pathW),
548 GetLastError());
550 res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
551 ok( res != 0, "couldn't find resource\n" );
552 ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
553 WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
554 ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
555 CloseHandle( file );
557 return pathW;
560 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
561 static void _delete_testfontfile(const WCHAR *filename, int line)
563 BOOL ret = DeleteFileW(filename);
564 ok_(__FILE__,line)(ret, "failed to delete file %s, error %ld\n", wine_dbgstr_w(filename), GetLastError());
567 static void get_combined_font_name(const WCHAR *familyW, const WCHAR *faceW, WCHAR *nameW)
569 lstrcpyW(nameW, familyW);
570 lstrcatW(nameW, L" ");
571 lstrcatW(nameW, faceW);
574 static BOOL has_face_variations(IDWriteFontFace *fontface)
576 IDWriteFontFace5 *fontface5;
577 BOOL ret = FALSE;
579 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5))) {
580 ret = IDWriteFontFace5_HasVariations(fontface5);
581 IDWriteFontFace5_Release(fontface5);
584 return ret;
587 #define check_familymodel(a,b) _check_familymodel(a,b,__LINE__)
588 static void _check_familymodel(void *iface_ptr, DWRITE_FONT_FAMILY_MODEL expected_model, unsigned int line)
590 IDWriteFontCollection2 *collection;
591 DWRITE_FONT_FAMILY_MODEL model;
593 if (SUCCEEDED(IUnknown_QueryInterface((IUnknown *)iface_ptr, &IID_IDWriteFontCollection2, (void **)&collection)))
595 model = IDWriteFontCollection2_GetFontFamilyModel(collection);
596 ok_(__FILE__,line)(model == expected_model, "Unexpected family model %d, expected %d.\n", model, expected_model);
597 IDWriteFontCollection2_Release(collection);
601 struct test_fontenumerator
603 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
604 LONG ref;
606 DWORD index;
607 IDWriteFontFile *font_file;
610 static inline struct test_fontenumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
612 return CONTAINING_RECORD(iface, struct test_fontenumerator, IDWriteFontFileEnumerator_iface);
615 static HRESULT WINAPI singlefontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
617 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
619 *obj = iface;
620 IDWriteFontFileEnumerator_AddRef(iface);
621 return S_OK;
623 return E_NOINTERFACE;
626 static ULONG WINAPI singlefontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
628 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
629 return InterlockedIncrement(&This->ref);
632 static ULONG WINAPI singlefontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
634 struct test_fontenumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
635 ULONG ref = InterlockedDecrement(&enumerator->ref);
636 if (!ref)
638 IDWriteFontFile_Release(enumerator->font_file);
639 free(enumerator);
641 return ref;
644 static HRESULT WINAPI singlefontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **font_file)
646 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
647 IDWriteFontFile_AddRef(This->font_file);
648 *font_file = This->font_file;
649 return S_OK;
652 static HRESULT WINAPI singlefontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
654 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
656 if (This->index > 1) {
657 *current = FALSE;
658 return S_OK;
661 This->index++;
662 *current = TRUE;
663 return S_OK;
666 static const struct IDWriteFontFileEnumeratorVtbl singlefontfileenumeratorvtbl =
668 singlefontfileenumerator_QueryInterface,
669 singlefontfileenumerator_AddRef,
670 singlefontfileenumerator_Release,
671 singlefontfileenumerator_MoveNext,
672 singlefontfileenumerator_GetCurrentFontFile
675 static HRESULT create_enumerator(IDWriteFontFile *font_file, IDWriteFontFileEnumerator **ret)
677 struct test_fontenumerator *enumerator;
679 if (!(enumerator = calloc(1, sizeof(*enumerator))))
680 return E_OUTOFMEMORY;
682 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &singlefontfileenumeratorvtbl;
683 enumerator->ref = 1;
684 enumerator->index = 0;
685 enumerator->font_file = font_file;
686 IDWriteFontFile_AddRef(font_file);
688 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
689 return S_OK;
692 struct test_fontcollectionloader
694 IDWriteFontCollectionLoader IDWriteFontFileCollectionLoader_iface;
695 IDWriteFontFileLoader *loader;
698 static inline struct test_fontcollectionloader *impl_from_IDWriteFontFileCollectionLoader(IDWriteFontCollectionLoader* iface)
700 return CONTAINING_RECORD(iface, struct test_fontcollectionloader, IDWriteFontFileCollectionLoader_iface);
703 static HRESULT WINAPI resourcecollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
705 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontCollectionLoader))
707 *obj = iface;
708 IDWriteFontCollectionLoader_AddRef(iface);
709 return S_OK;
711 return E_NOINTERFACE;
714 static ULONG WINAPI resourcecollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
716 return 2;
719 static ULONG WINAPI resourcecollectionloader_Release(IDWriteFontCollectionLoader *iface)
721 return 1;
724 static HRESULT WINAPI resourcecollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory,
725 const void * collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator ** fontFileEnumerator)
727 struct test_fontcollectionloader *This = impl_from_IDWriteFontFileCollectionLoader(iface);
728 IDWriteFontFile *font_file;
729 HRESULT hr;
731 hr = IDWriteFactory_CreateCustomFontFileReference(factory, collectionKey, collectionKeySize, This->loader, &font_file);
732 ok(hr == S_OK, "Failed to create custom file reference, hr %#lx.\n", hr);
734 hr = create_enumerator(font_file, fontFileEnumerator);
735 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
737 IDWriteFontFile_Release(font_file);
738 return hr;
741 static const struct IDWriteFontCollectionLoaderVtbl resourcecollectionloadervtbl = {
742 resourcecollectionloader_QueryInterface,
743 resourcecollectionloader_AddRef,
744 resourcecollectionloader_Release,
745 resourcecollectionloader_CreateEnumeratorFromKey
748 /* Here is a functional custom font set of interfaces */
749 struct test_fontdatastream
751 IDWriteFontFileStream IDWriteFontFileStream_iface;
752 LONG ref;
754 LPVOID data;
755 DWORD size;
758 static inline struct test_fontdatastream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream* iface)
760 return CONTAINING_RECORD(iface, struct test_fontdatastream, IDWriteFontFileStream_iface);
763 static HRESULT WINAPI fontdatastream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
765 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
767 *obj = iface;
768 IDWriteFontFileStream_AddRef(iface);
769 return S_OK;
771 *obj = NULL;
772 return E_NOINTERFACE;
775 static ULONG WINAPI fontdatastream_AddRef(IDWriteFontFileStream *iface)
777 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
778 ULONG ref = InterlockedIncrement(&This->ref);
779 return ref;
782 static ULONG WINAPI fontdatastream_Release(IDWriteFontFileStream *iface)
784 struct test_fontdatastream *stream = impl_from_IDWriteFontFileStream(iface);
785 ULONG refcount = InterlockedDecrement(&stream->ref);
787 if (!refcount)
788 free(stream);
790 return refcount;
793 static HRESULT WINAPI fontdatastream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
795 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
796 *fragment_context = NULL;
797 if (offset+fragment_size > This->size)
799 *fragment_start = NULL;
800 return E_FAIL;
802 else
804 *fragment_start = (BYTE*)This->data + offset;
805 return S_OK;
809 static void WINAPI fontdatastream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
811 /* Do Nothing */
814 static HRESULT WINAPI fontdatastream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
816 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
817 *size = This->size;
818 return S_OK;
821 static HRESULT WINAPI fontdatastream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
823 return E_NOTIMPL;
826 static const IDWriteFontFileStreamVtbl fontdatastreamvtbl =
828 fontdatastream_QueryInterface,
829 fontdatastream_AddRef,
830 fontdatastream_Release,
831 fontdatastream_ReadFileFragment,
832 fontdatastream_ReleaseFileFragment,
833 fontdatastream_GetFileSize,
834 fontdatastream_GetLastWriteTime
837 static HRESULT create_fontdatastream(LPVOID data, UINT size, IDWriteFontFileStream** iface)
839 struct test_fontdatastream *object = calloc(1, sizeof(*object));
840 if (!object)
841 return E_OUTOFMEMORY;
843 object->IDWriteFontFileStream_iface.lpVtbl = &fontdatastreamvtbl;
844 object->ref = 1;
845 object->data = data;
846 object->size = size;
848 *iface = &object->IDWriteFontFileStream_iface;
850 return S_OK;
853 static HRESULT WINAPI resourcefontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
855 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
857 *obj = iface;
858 return S_OK;
860 *obj = NULL;
861 return E_NOINTERFACE;
864 static ULONG WINAPI resourcefontfileloader_AddRef(IDWriteFontFileLoader *iface)
866 return 2;
869 static ULONG WINAPI resourcefontfileloader_Release(IDWriteFontFileLoader *iface)
871 return 1;
874 static HRESULT WINAPI resourcefontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
875 IDWriteFontFileStream **stream)
877 LPVOID data;
878 DWORD size;
879 HGLOBAL mem;
881 mem = LoadResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
882 ok(mem != NULL, "Failed to lock font resource\n");
883 if (mem)
885 size = SizeofResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
886 data = LockResource(mem);
887 return create_fontdatastream(data, size, stream);
889 return E_FAIL;
892 static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = {
893 resourcefontfileloader_QueryInterface,
894 resourcefontfileloader_AddRef,
895 resourcefontfileloader_Release,
896 resourcefontfileloader_CreateStreamFromKey
899 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
901 static D2D1_POINT_2F g_startpoints[2];
902 static int g_startpoint_count;
904 static HRESULT WINAPI test_geometrysink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **ret)
906 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
907 IsEqualIID(riid, &IID_IUnknown))
909 *ret = iface;
910 ID2D1SimplifiedGeometrySink_AddRef(iface);
911 return S_OK;
914 *ret = NULL;
915 return E_NOINTERFACE;
918 static ULONG WINAPI test_geometrysink_AddRef(ID2D1SimplifiedGeometrySink *iface)
920 return 2;
923 static ULONG WINAPI test_geometrysink_Release(ID2D1SimplifiedGeometrySink *iface)
925 return 1;
928 static void WINAPI test_geometrysink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
930 CHECK_EXPECT(setfillmode);
931 ok(mode == D2D1_FILL_MODE_WINDING, "fill mode %d\n", mode);
934 static void WINAPI test_geometrysink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT flags)
936 ok(0, "unexpected SetSegmentFlags() - flags %d\n", flags);
939 static void WINAPI test_geometrysink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
940 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
942 ok(figureBegin == D2D1_FIGURE_BEGIN_FILLED, "begin figure %d\n", figureBegin);
943 if (g_startpoint_count < ARRAY_SIZE(g_startpoints))
944 g_startpoints[g_startpoint_count] = startPoint;
945 g_startpoint_count++;
948 static void WINAPI test_geometrysink_AddLines(ID2D1SimplifiedGeometrySink *iface,
949 const D2D1_POINT_2F *points, UINT32 count)
953 static void WINAPI test_geometrysink_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
954 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
958 static void WINAPI test_geometrysink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
960 ok(figureEnd == D2D1_FIGURE_END_CLOSED, "end figure %d\n", figureEnd);
963 static HRESULT WINAPI test_geometrysink_Close(ID2D1SimplifiedGeometrySink *iface)
965 ok(0, "unexpected Close()\n");
966 return E_NOTIMPL;
969 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink_vtbl = {
970 test_geometrysink_QueryInterface,
971 test_geometrysink_AddRef,
972 test_geometrysink_Release,
973 test_geometrysink_SetFillMode,
974 test_geometrysink_SetSegmentFlags,
975 test_geometrysink_BeginFigure,
976 test_geometrysink_AddLines,
977 test_geometrysink_AddBeziers,
978 test_geometrysink_EndFigure,
979 test_geometrysink_Close
982 static void WINAPI test_geometrysink2_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
983 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
985 ok(0, "unexpected call\n");
988 static void WINAPI test_geometrysink2_AddLines(ID2D1SimplifiedGeometrySink *iface,
989 const D2D1_POINT_2F *points, UINT32 count)
991 ok(0, "unexpected call\n");
994 static void WINAPI test_geometrysink2_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
995 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
997 ok(0, "unexpected call\n");
1000 static void WINAPI test_geometrysink2_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
1002 ok(0, "unexpected call\n");
1005 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink2_vtbl = {
1006 test_geometrysink_QueryInterface,
1007 test_geometrysink_AddRef,
1008 test_geometrysink_Release,
1009 test_geometrysink_SetFillMode,
1010 test_geometrysink_SetSegmentFlags,
1011 test_geometrysink2_BeginFigure,
1012 test_geometrysink2_AddLines,
1013 test_geometrysink2_AddBeziers,
1014 test_geometrysink2_EndFigure,
1015 test_geometrysink_Close
1018 static ID2D1SimplifiedGeometrySink test_geomsink = { &test_geometrysink_vtbl };
1019 static ID2D1SimplifiedGeometrySink test_geomsink2 = { &test_geometrysink2_vtbl };
1021 static void test_CreateFontFromLOGFONT(void)
1023 IDWriteGdiInterop1 *interop1;
1024 IDWriteGdiInterop *interop;
1025 DWRITE_FONT_WEIGHT weight;
1026 DWRITE_FONT_STYLE style;
1027 IDWriteFont *font;
1028 LOGFONTW logfont;
1029 LONG weights[][2] = {
1030 {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
1031 {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
1032 { 0, DWRITE_FONT_WEIGHT_NORMAL},
1033 { 50, DWRITE_FONT_WEIGHT_NORMAL},
1034 {150, DWRITE_FONT_WEIGHT_NORMAL},
1035 {250, DWRITE_FONT_WEIGHT_NORMAL},
1036 {350, DWRITE_FONT_WEIGHT_NORMAL},
1037 {450, DWRITE_FONT_WEIGHT_NORMAL},
1038 {650, DWRITE_FONT_WEIGHT_BOLD},
1039 {750, DWRITE_FONT_WEIGHT_BOLD},
1040 {850, DWRITE_FONT_WEIGHT_BOLD},
1041 {950, DWRITE_FONT_WEIGHT_BOLD},
1042 {960, DWRITE_FONT_WEIGHT_BOLD},
1044 OUTLINETEXTMETRICW otm;
1045 IDWriteFactory *factory;
1046 HRESULT hr;
1047 BOOL ret;
1048 HDC hdc;
1049 HFONT hfont;
1050 BOOL exists;
1051 ULONG ref;
1052 int i;
1053 UINT r;
1055 factory = create_factory();
1057 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1058 ok(hr == S_OK, "got %#lx\n", hr);
1060 if (0)
1061 /* null out parameter crashes this call */
1062 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
1064 font = (void*)0xdeadbeef;
1065 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
1066 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1067 ok(font == NULL, "got %p\n", font);
1069 memset(&logfont, 0, sizeof(logfont));
1070 logfont.lfHeight = 12;
1071 logfont.lfWidth = 12;
1072 logfont.lfWeight = FW_NORMAL;
1073 logfont.lfItalic = 1;
1074 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1076 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1077 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1079 hfont = CreateFontIndirectW(&logfont);
1080 hdc = CreateCompatibleDC(0);
1081 SelectObject(hdc, hfont);
1083 otm.otmSize = sizeof(otm);
1084 r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
1085 ok(r, "got %d\n", r);
1086 DeleteDC(hdc);
1087 DeleteObject(hfont);
1089 exists = TRUE;
1090 hr = IDWriteFont_HasCharacter(font, 0xd800, &exists);
1091 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1092 ok(exists == FALSE, "got %d\n", exists);
1094 exists = FALSE;
1095 hr = IDWriteFont_HasCharacter(font, 0x20, &exists);
1096 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1097 ok(exists == TRUE, "got %d\n", exists);
1099 /* now check properties */
1100 weight = IDWriteFont_GetWeight(font);
1101 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1103 style = IDWriteFont_GetStyle(font);
1104 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1105 ok(otm.otmfsSelection & 1, "got 0x%08x\n", otm.otmfsSelection);
1107 ret = IDWriteFont_IsSymbolFont(font);
1108 ok(!ret, "got %d\n", ret);
1110 IDWriteFont_Release(font);
1112 /* weight values */
1113 for (i = 0; i < ARRAY_SIZE(weights); i++)
1115 memset(&logfont, 0, sizeof(logfont));
1116 logfont.lfHeight = 12;
1117 logfont.lfWidth = 12;
1118 logfont.lfWeight = weights[i][0];
1119 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1121 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1122 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1124 weight = IDWriteFont_GetWeight(font);
1125 ok(weight == weights[i][1],
1126 "%d: got %d, expected %ld\n", i, weight, weights[i][1]);
1128 IDWriteFont_Release(font);
1131 /* weight not from enum */
1132 memset(&logfont, 0, sizeof(logfont));
1133 logfont.lfHeight = 12;
1134 logfont.lfWidth = 12;
1135 logfont.lfWeight = 550;
1136 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1138 font = NULL;
1139 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1140 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1142 weight = IDWriteFont_GetWeight(font);
1143 ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
1144 "got %d\n", weight);
1146 IDWriteFont_Release(font);
1148 /* empty or nonexistent face name */
1149 memset(&logfont, 0, sizeof(logfont));
1150 logfont.lfHeight = 12;
1151 logfont.lfWidth = 12;
1152 logfont.lfWeight = FW_NORMAL;
1153 lstrcpyW(logfont.lfFaceName, L"Blah!");
1155 font = (void*)0xdeadbeef;
1156 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1157 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
1158 ok(font == NULL, "got %p\n", font);
1160 /* Try with name 'Tahoma ' */
1161 memset(&logfont, 0, sizeof(logfont));
1162 logfont.lfHeight = 12;
1163 logfont.lfWidth = 12;
1164 logfont.lfWeight = FW_NORMAL;
1165 lstrcpyW(logfont.lfFaceName, L"Tahoma ");
1167 font = (void*)0xdeadbeef;
1168 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1169 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
1170 ok(font == NULL, "got %p\n", font);
1172 /* empty string as a facename */
1173 memset(&logfont, 0, sizeof(logfont));
1174 logfont.lfHeight = 12;
1175 logfont.lfWidth = 12;
1176 logfont.lfWeight = FW_NORMAL;
1178 font = (void*)0xdeadbeef;
1179 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1180 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
1181 ok(font == NULL, "got %p\n", font);
1183 /* IDWriteGdiInterop1::CreateFontFromLOGFONT() */
1184 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
1185 if (hr == S_OK) {
1186 memset(&logfont, 0, sizeof(logfont));
1187 logfont.lfHeight = 12;
1188 logfont.lfWidth = 12;
1189 logfont.lfWeight = FW_NORMAL;
1190 logfont.lfItalic = 1;
1191 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1193 hr = IDWriteGdiInterop1_CreateFontFromLOGFONT(interop1, &logfont, NULL, &font);
1194 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1196 IDWriteFont_Release(font);
1197 IDWriteGdiInterop1_Release(interop1);
1199 else
1200 win_skip("IDWriteGdiInterop1 is not supported, skipping CreateFontFromLOGFONT() tests.\n");
1202 ref = IDWriteGdiInterop_Release(interop);
1203 ok(ref == 0, "interop is not released, %lu\n", ref);
1204 ref = IDWriteFactory_Release(factory);
1205 ok(ref == 0, "factory is not released, %lu\n", ref);
1208 static void test_CreateBitmapRenderTarget(void)
1210 IDWriteBitmapRenderTarget *target, *target2;
1211 IDWriteBitmapRenderTarget1 *target1;
1212 IDWriteRenderingParams *params;
1213 IDWriteGdiInterop *interop;
1214 IDWriteFontFace *fontface;
1215 IDWriteFactory *factory;
1216 DWRITE_GLYPH_RUN run;
1217 HBITMAP hbm, hbm2;
1218 UINT16 glyphs[2];
1219 DWRITE_MATRIX m;
1220 DIBSECTION ds;
1221 XFORM xform;
1222 COLORREF c;
1223 HRESULT hr;
1224 FLOAT pdip;
1225 SIZE size;
1226 ULONG ref;
1227 UINT32 ch;
1228 HDC hdc;
1229 int ret;
1231 factory = create_factory();
1233 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1234 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1236 target = NULL;
1237 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
1238 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1240 if (0) /* crashes on native */
1241 hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
1243 size.cx = size.cy = -1;
1244 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1245 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1246 ok(size.cx == 0, "got %ld\n", size.cx);
1247 ok(size.cy == 0, "got %ld\n", size.cy);
1249 target2 = NULL;
1250 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
1251 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1252 ok(target != target2, "got %p, %p\n", target2, target);
1253 IDWriteBitmapRenderTarget_Release(target2);
1255 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1256 ok(hdc != NULL, "got %p\n", hdc);
1258 /* test mode */
1259 ret = GetGraphicsMode(hdc);
1260 ok(ret == GM_ADVANCED, "got %d\n", ret);
1262 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1263 ok(hbm != NULL, "got %p\n", hbm);
1265 /* check DIB properties */
1266 ret = GetObjectW(hbm, sizeof(ds), &ds);
1267 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1268 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1269 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1270 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1271 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1272 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1274 IDWriteBitmapRenderTarget_Release(target);
1276 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1277 ok(!hbm, "got %p\n", hbm);
1279 target = NULL;
1280 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
1281 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1283 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1284 ok(hdc != NULL, "got %p\n", hdc);
1286 /* test context settings */
1287 c = GetTextColor(hdc);
1288 ok(c == RGB(0, 0, 0), "got 0x%08lx\n", c);
1289 ret = GetBkMode(hdc);
1290 ok(ret == OPAQUE, "got %d\n", ret);
1291 c = GetBkColor(hdc);
1292 ok(c == RGB(255, 255, 255), "got 0x%08lx\n", c);
1294 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1295 ok(hbm != NULL, "got %p\n", hbm);
1297 /* check DIB properties */
1298 ret = GetObjectW(hbm, sizeof(ds), &ds);
1299 ok(ret == sizeof(ds), "got %d\n", ret);
1300 ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
1301 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1302 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1303 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1304 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1306 size.cx = size.cy = -1;
1307 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1308 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1309 ok(size.cx == 10, "got %ld\n", size.cx);
1310 ok(size.cy == 5, "got %ld\n", size.cy);
1312 /* resize to same size */
1313 hr = IDWriteBitmapRenderTarget_Resize(target, 10, 5);
1314 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1316 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1317 ok(hbm2 == hbm, "got %p, %p\n", hbm2, hbm);
1319 /* shrink */
1320 hr = IDWriteBitmapRenderTarget_Resize(target, 5, 5);
1321 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1323 size.cx = size.cy = -1;
1324 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1325 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1326 ok(size.cx == 5, "got %ld\n", size.cx);
1327 ok(size.cy == 5, "got %ld\n", size.cy);
1329 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1330 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1332 hr = IDWriteBitmapRenderTarget_Resize(target, 20, 5);
1333 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1335 size.cx = size.cy = -1;
1336 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1337 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1338 ok(size.cx == 20, "got %ld\n", size.cx);
1339 ok(size.cy == 5, "got %ld\n", size.cy);
1341 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1342 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1344 hr = IDWriteBitmapRenderTarget_Resize(target, 1, 5);
1345 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1347 size.cx = size.cy = -1;
1348 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1349 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1350 ok(size.cx == 1, "got %ld\n", size.cx);
1351 ok(size.cy == 5, "got %ld\n", size.cy);
1353 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1354 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1356 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1357 ok(ret == sizeof(ds), "got %d\n", ret);
1358 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1359 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1360 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1361 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1362 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1364 /* empty rectangle */
1365 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 5);
1366 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1368 size.cx = size.cy = -1;
1369 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1370 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1371 ok(size.cx == 0, "got %ld\n", size.cx);
1372 ok(size.cy == 5, "got %ld\n", size.cy);
1374 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1375 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1377 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1378 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1379 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1380 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1381 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1382 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1383 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1385 /* transform tests, current hdc transform is not immediately affected */
1386 if (0) /* crashes on native */
1387 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, NULL);
1389 memset(&m, 0xcc, sizeof(m));
1390 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1391 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1392 ok(m.m11 == 1.0 && m.m22 == 1.0 && m.m12 == 0.0 && m.m21 == 0.0, "got %.1f,%.1f,%.1f,%.1f\n", m.m11, m.m22, m.m12, m.m21);
1393 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1394 ret = GetWorldTransform(hdc, &xform);
1395 ok(ret, "got %d\n", ret);
1396 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1397 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1399 memset(&m, 0, sizeof(m));
1400 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1401 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1403 memset(&m, 0xcc, sizeof(m));
1404 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1405 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1406 ok(m.m11 == 0.0 && m.m22 == 0.0 && m.m12 == 0.0 && m.m21 == 0.0, "got %.1f,%.1f,%.1f,%.1f\n", m.m11, m.m22, m.m12, m.m21);
1407 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1408 ret = GetWorldTransform(hdc, &xform);
1409 ok(ret, "got %d\n", ret);
1410 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1411 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1413 memset(&m, 0, sizeof(m));
1414 m.m11 = 2.0; m.m22 = 1.0;
1415 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1416 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1417 ret = GetWorldTransform(hdc, &xform);
1418 ok(ret, "got %d\n", ret);
1419 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1420 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1422 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, NULL);
1423 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1425 memset(&m, 0xcc, sizeof(m));
1426 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1427 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1428 ok(m.m11 == 1.0 && m.m22 == 1.0 && m.m12 == 0.0 && m.m21 == 0.0, "got %.1f,%.1f,%.1f,%.1f\n", m.m11, m.m22, m.m12, m.m21);
1429 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1431 /* pixels per dip */
1432 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1433 ok(pdip == 1.0, "got %.2f\n", pdip);
1435 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
1436 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1438 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, -1.0);
1439 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1441 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 0.0);
1442 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1444 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1445 ok(pdip == 2.0, "got %.2f\n", pdip);
1447 hr = IDWriteBitmapRenderTarget_QueryInterface(target, &IID_IDWriteBitmapRenderTarget1, (void**)&target1);
1448 if (hr == S_OK) {
1449 DWRITE_TEXT_ANTIALIAS_MODE mode;
1451 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1452 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1454 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE+1);
1455 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1457 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1458 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1460 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
1461 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1463 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1464 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, "got %d\n", mode);
1466 IDWriteBitmapRenderTarget1_Release(target1);
1468 else
1469 win_skip("IDWriteBitmapRenderTarget1 is not supported.\n");
1471 /* DrawGlyphRun() argument validation. */
1472 hr = IDWriteBitmapRenderTarget_Resize(target, 16, 16);
1473 ok(hr == S_OK, "Failed to resize target, hr %#lx.\n", hr);
1475 fontface = create_fontface(factory);
1477 ch = 'A';
1478 glyphs[0] = 0;
1479 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, glyphs);
1480 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1481 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
1482 glyphs[1] = glyphs[0];
1484 memset(&run, 0, sizeof(run));
1485 run.fontFace = fontface;
1486 run.fontEmSize = 12.0f;
1487 run.glyphCount = 2;
1488 run.glyphIndices = glyphs;
1490 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
1491 DWRITE_RENDERING_MODE_DEFAULT, &params);
1492 ok(hr == S_OK, "Failed to create rendering params, hr %#lx.\n", hr);
1494 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1495 &run, NULL, RGB(255, 0, 0), NULL);
1496 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1498 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1499 &run, NULL, RGB(255, 0, 0), NULL);
1500 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1502 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1503 &run, params, RGB(255, 0, 0), NULL);
1504 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Unexpected hr %#lx.\n", hr);
1506 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL,
1507 &run, params, RGB(255, 0, 0), NULL);
1508 ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr);
1510 IDWriteRenderingParams_Release(params);
1512 /* Zero sized target returns earlier. */
1513 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 16);
1514 ok(hr == S_OK, "Failed to resize target, hr %#lx.\n", hr);
1516 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1517 &run, NULL, RGB(255, 0, 0), NULL);
1518 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1520 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1521 &run, params, RGB(255, 0, 0), NULL);
1522 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1524 IDWriteFontFace_Release(fontface);
1526 ref = IDWriteBitmapRenderTarget_Release(target);
1527 ok(ref == 0, "render target not released, %lu\n", ref);
1528 ref = IDWriteGdiInterop_Release(interop);
1529 ok(ref == 0, "interop not released, %lu\n", ref);
1530 ref = IDWriteFactory_Release(factory);
1531 ok(ref == 0, "factory not released, %lu\n", ref);
1534 static void test_GetFontFamily(void)
1536 IDWriteFontCollection *collection, *collection2;
1537 IDWriteFontCollection *syscoll;
1538 IDWriteFontCollection2 *coll2;
1539 IDWriteFontFamily *family, *family2;
1540 IDWriteFontFamily1 *family1;
1541 IDWriteGdiInterop *interop;
1542 IDWriteFont *font, *font2;
1543 IDWriteFactory *factory;
1544 LOGFONTW logfont;
1545 ULONG ref, count;
1546 HRESULT hr;
1548 factory = create_factory();
1550 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1551 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1553 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1554 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1556 memset(&logfont, 0, sizeof(logfont));
1557 logfont.lfHeight = 12;
1558 logfont.lfWidth = 12;
1559 logfont.lfWeight = FW_NORMAL;
1560 logfont.lfItalic = 1;
1561 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1563 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1564 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1566 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1567 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1568 ok(font2 != font, "got %p, %p\n", font2, font);
1570 if (0) /* crashes on native */
1571 hr = IDWriteFont_GetFontFamily(font, NULL);
1573 EXPECT_REF(font, 1);
1574 hr = IDWriteFont_GetFontFamily(font, &family);
1575 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1576 EXPECT_REF(font, 1);
1577 EXPECT_REF(family, 2);
1579 hr = IDWriteFont_GetFontFamily(font, &family2);
1580 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1581 ok(family2 == family, "got %p, previous %p\n", family2, family);
1582 EXPECT_REF(font, 1);
1583 EXPECT_REF(family, 3);
1584 IDWriteFontFamily_Release(family2);
1586 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
1587 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
1588 ok(family2 == NULL, "got %p\n", family2);
1590 hr = IDWriteFont_GetFontFamily(font2, &family2);
1591 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1592 ok(family2 != family, "got %p, %p\n", family2, family);
1594 collection = NULL;
1595 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
1596 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1598 collection2 = NULL;
1599 hr = IDWriteFontFamily_GetFontCollection(family2, &collection2);
1600 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1601 ok(collection == collection2, "got %p, %p\n", collection, collection2);
1602 ok(collection == syscoll, "got %p, %p\n", collection, syscoll);
1604 IDWriteFont_Release(font);
1605 IDWriteFont_Release(font2);
1607 hr = IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily1, (void**)&family1);
1608 if (hr == S_OK) {
1609 IDWriteFontFaceReference *ref, *ref1;
1610 IDWriteFontList1 *fontlist1;
1611 IDWriteFontList2 *fontlist2;
1612 IDWriteFontList *fontlist;
1613 IDWriteFont3 *font3;
1614 IDWriteFont1 *font1;
1616 font3 = (void*)0xdeadbeef;
1617 hr = IDWriteFontFamily1_GetFont(family1, ~0u, &font3);
1618 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1619 ok(font3 == NULL, "got %p\n", font3);
1621 hr = IDWriteFontFamily1_GetFont(family1, 0, &font3);
1622 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1624 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont, (void**)&font);
1625 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1626 IDWriteFont_Release(font);
1628 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont1, (void**)&font1);
1629 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1630 IDWriteFont1_Release(font1);
1632 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList1, (void **)&fontlist1);
1633 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Failed to get interface, hr %#lx.\n", hr);
1634 if (hr == S_OK) {
1635 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void **)&fontlist);
1636 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1637 ok(fontlist == (IDWriteFontList *)fontlist1, "Unexpected interface pointer.\n");
1638 ok(fontlist != (IDWriteFontList *)family1, "Unexpected interface pointer.\n");
1639 ok(fontlist != (IDWriteFontList *)family, "Unexpected interface pointer.\n");
1641 if (SUCCEEDED(IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList2, (void **)&fontlist2)))
1643 IDWriteFontSet1 *fontset = NULL, *fontset2 = NULL;
1645 ok(fontlist == (IDWriteFontList *)fontlist2, "Unexpected interface pointer.\n");
1647 hr = IDWriteFontList2_GetFontSet(fontlist2, &fontset);
1648 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1650 hr = IDWriteFontList2_GetFontSet(fontlist2, &fontset2);
1651 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1652 ok(fontset != fontset2, "Unexpected instance.\n");
1654 IDWriteFontSet1_Release(fontset2);
1655 IDWriteFontSet1_Release(fontset);
1657 IDWriteFontList2_Release(fontlist2);
1659 else
1660 win_skip("IDWriteFontList2 is not supported.\n");
1662 IDWriteFontList1_Release(fontlist1);
1663 IDWriteFontList_Release(fontlist);
1666 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void**)&fontlist);
1667 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1668 IDWriteFontList_Release(fontlist);
1670 IDWriteFont3_Release(font3);
1672 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref);
1673 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1675 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref1);
1676 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1677 ok(ref != ref1, "got %p, %p\n", ref, ref1);
1679 IDWriteFontFaceReference_Release(ref);
1680 IDWriteFontFaceReference_Release(ref1);
1682 IDWriteFontFamily1_Release(family1);
1684 else
1685 win_skip("IDWriteFontFamily1 is not supported.\n");
1687 /* IDWriteFontCollection2::GetFontFamily() */
1688 if (SUCCEEDED(IDWriteFontCollection_QueryInterface(syscoll, &IID_IDWriteFontCollection2, (void **)&coll2)))
1690 IDWriteFontFamily2 *family2;
1692 count = IDWriteFontCollection2_GetFontFamilyCount(coll2);
1693 ok(!!count, "Unexpected family count.\n");
1695 family2 = (void *)0xdeadbeef;
1696 hr = IDWriteFontCollection2_GetFontFamily(coll2, count, &family2);
1697 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1698 ok(!family2, "Unexpected pointer.\n");
1700 hr = IDWriteFontCollection2_GetFontFamily(coll2, 0, &family2);
1701 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
1702 IDWriteFontFamily2_Release(family2);
1704 IDWriteFontCollection2_Release(coll2);
1706 else
1707 win_skip("IDWriteFontCollection2 is not supported.\n");
1709 IDWriteFontCollection_Release(syscoll);
1710 IDWriteFontCollection_Release(collection2);
1711 IDWriteFontCollection_Release(collection);
1712 IDWriteFontFamily_Release(family2);
1713 IDWriteFontFamily_Release(family);
1714 IDWriteGdiInterop_Release(interop);
1715 ref = IDWriteFactory_Release(factory);
1716 ok(ref == 0, "factory not released, %lu\n", ref);
1719 static void test_GetFamilyNames(void)
1721 IDWriteLocalizedStrings *names, *names2;
1722 IDWriteFontFace3 *fontface3;
1723 IDWriteGdiInterop *interop;
1724 IDWriteFontFamily *family;
1725 IDWriteFontFace *fontface;
1726 IDWriteFactory *factory;
1727 IDWriteFont *font;
1728 LOGFONTW logfont;
1729 WCHAR buffer[100];
1730 HRESULT hr;
1731 UINT32 len;
1732 ULONG ref;
1734 factory = create_factory();
1736 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1737 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1739 memset(&logfont, 0, sizeof(logfont));
1740 logfont.lfHeight = 12;
1741 logfont.lfWidth = 12;
1742 logfont.lfWeight = FW_NORMAL;
1743 logfont.lfItalic = 1;
1744 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1746 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1747 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1749 hr = IDWriteFont_GetFontFamily(font, &family);
1750 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1752 if (0) /* crashes on native */
1753 hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
1755 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1756 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1757 EXPECT_REF(names, 1);
1759 hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
1760 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1761 EXPECT_REF(names2, 1);
1762 ok(names != names2, "got %p, was %p\n", names2, names);
1764 IDWriteLocalizedStrings_Release(names2);
1766 /* GetStringLength */
1767 if (0) /* crashes on native */
1768 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
1770 len = 100;
1771 hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
1772 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1773 ok(len == (UINT32)-1, "got %u\n", len);
1775 len = 0;
1776 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
1777 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1778 ok(len > 0, "got %u\n", len);
1780 /* GetString */
1781 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
1782 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1784 hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
1785 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
1787 if (0)
1788 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
1790 buffer[0] = 1;
1791 hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
1792 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1793 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1795 buffer[0] = 1;
1796 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
1797 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1798 ok(buffer[0] == 0 || broken(buffer[0] == 'T'), "Unexpected buffer contents, %#x.\n", buffer[0]);
1800 buffer[0] = 1;
1801 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
1802 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1803 ok(buffer[0] == 0 || broken(buffer[0] == 'T'), "Unexpected buffer contents, %#x.\n", buffer[0]);
1805 buffer[0] = 0;
1806 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1807 ok(hr == S_OK, "Failed to get a string, hr %#lx.\n", hr);
1808 ok(!lstrcmpW(buffer, L"Tahoma"), "Unexpected family name %s.\n", wine_dbgstr_w(buffer));
1810 IDWriteLocalizedStrings_Release(names);
1812 /* GetFamilyNames() on font face */
1813 hr = IDWriteFont_CreateFontFace(font, &fontface);
1814 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
1816 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
1818 hr = IDWriteFontFace3_GetFamilyNames(fontface3, &names);
1819 ok(hr == S_OK, "Failed to get family names, hr %#lx.\n", hr);
1821 buffer[0] = 0;
1822 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1823 ok(hr == S_OK, "Failed to get a string, hr %#lx.\n", hr);
1824 ok(!lstrcmpW(buffer, L"Tahoma"), "Unexpected family name %s.\n", wine_dbgstr_w(buffer));
1826 IDWriteLocalizedStrings_Release(names);
1827 IDWriteFontFace3_Release(fontface3);
1829 else
1830 win_skip("IDWriteFontFace3::GetFamilyNames() is not supported.\n");
1832 IDWriteFontFace_Release(fontface);
1834 IDWriteFontFamily_Release(family);
1835 IDWriteFont_Release(font);
1836 IDWriteGdiInterop_Release(interop);
1837 ref = IDWriteFactory_Release(factory);
1838 ok(ref == 0, "factory not released, %lu\n", ref);
1841 static void test_CreateFontFace(void)
1843 IDWriteFontFace *fontface, *fontface2;
1844 IDWriteFontCollection *collection;
1845 DWRITE_FONT_FILE_TYPE file_type;
1846 DWRITE_FONT_FACE_TYPE face_type;
1847 IDWriteFontFace5 *fontface5;
1848 IDWriteGdiInterop *interop;
1849 IDWriteFont *font, *font2;
1850 IDWriteFontFamily *family;
1851 IDWriteFactory *factory;
1852 IDWriteFontFile *file;
1853 BOOL supported, ret;
1854 LOGFONTW logfont;
1855 UINT32 count;
1856 WCHAR *path;
1857 HRESULT hr;
1858 ULONG ref;
1860 factory = create_factory();
1862 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1863 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1865 memset(&logfont, 0, sizeof(logfont));
1866 logfont.lfHeight = 12;
1867 logfont.lfWidth = 12;
1868 logfont.lfWeight = FW_NORMAL;
1869 logfont.lfItalic = 1;
1870 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1872 font = NULL;
1873 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1874 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1876 font2 = NULL;
1877 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1878 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1879 ok(font != font2, "got %p, %p\n", font, font2);
1881 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
1882 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
1884 if (0) /* crashes on native */
1885 hr = IDWriteFont_CreateFontFace(font, NULL);
1887 fontface = NULL;
1888 hr = IDWriteFont_CreateFontFace(font, &fontface);
1889 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1891 fontface2 = NULL;
1892 hr = IDWriteFont_CreateFontFace(font, &fontface2);
1893 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1894 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1895 IDWriteFontFace_Release(fontface2);
1897 fontface2 = NULL;
1898 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1899 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1900 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1901 IDWriteFontFace_Release(fontface2);
1903 IDWriteFont_Release(font2);
1904 IDWriteFont_Release(font);
1906 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFont, (void**)&font);
1907 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL), "Unexpected hr %#lx.\n", hr);
1909 IDWriteFontFace_Release(fontface);
1910 IDWriteGdiInterop_Release(interop);
1912 /* Create from system collection */
1913 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1914 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1916 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
1917 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1919 font = NULL;
1920 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1921 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1922 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1924 font2 = NULL;
1925 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1926 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
1927 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1928 ok(font != font2, "got %p, %p\n", font, font2);
1930 fontface = NULL;
1931 hr = IDWriteFont_CreateFontFace(font, &fontface);
1932 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1934 fontface2 = NULL;
1935 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1936 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1937 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1939 /* Trivial equality test */
1940 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5)))
1942 ret = IDWriteFontFace5_Equals(fontface5, fontface2);
1943 ok(ret, "Unexpected result %d.\n", ret);
1944 IDWriteFontFace5_Release(fontface5);
1947 IDWriteFontFace_Release(fontface);
1948 IDWriteFontFace_Release(fontface2);
1949 IDWriteFont_Release(font2);
1950 IDWriteFont_Release(font);
1951 IDWriteFontFamily_Release(family);
1952 IDWriteFontCollection_Release(collection);
1953 ref = IDWriteFactory_Release(factory);
1954 ok(ref == 0, "factory not released, %lu.\n", ref);
1956 /* IDWriteFactory::CreateFontFace() */
1957 path = create_testfontfile(test_fontfile);
1958 factory = create_factory();
1960 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
1961 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
1963 supported = FALSE;
1964 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1965 face_type = DWRITE_FONT_FACE_TYPE_CFF;
1966 count = 0;
1967 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &count);
1968 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1969 ok(supported == TRUE, "got %i\n", supported);
1970 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
1971 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
1972 ok(count == 1, "got %i\n", count);
1974 /* invalid simulation flags */
1975 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, ~0u, &fontface);
1976 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1978 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0xf, &fontface);
1979 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1981 /* try mismatching face type, the one that's not supported */
1982 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1983 ok(hr == DWRITE_E_FILEFORMAT, "Unexpected hr %#lx.\n", hr);
1985 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, 1, &file, 0,
1986 DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1987 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* < win10 */, "Unexpected hr %#lx.\n", hr);
1989 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_RAW_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1990 todo_wine
1991 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == E_INVALIDARG) /* older versions */, "Unexpected hr %#lx.\n", hr);
1993 fontface = (void*)0xdeadbeef;
1994 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TYPE1, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1995 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1996 ok(fontface == NULL, "got %p\n", fontface);
1998 fontface = (void*)0xdeadbeef;
1999 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_VECTOR, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2000 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2001 ok(fontface == NULL, "got %p\n", fontface);
2003 fontface = (void*)0xdeadbeef;
2004 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_BITMAP, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2005 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2006 ok(fontface == NULL, "got %p\n", fontface);
2008 fontface = NULL;
2009 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_UNKNOWN, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2010 todo_wine
2011 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* < win10 */, "Unexpected hr %#lx.\n", hr);
2012 if (hr == S_OK) {
2013 ok(fontface != NULL, "got %p\n", fontface);
2014 face_type = IDWriteFontFace_GetType(fontface);
2015 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %d\n", face_type);
2016 IDWriteFontFace_Release(fontface);
2019 IDWriteFontFile_Release(file);
2020 ref = IDWriteFactory_Release(factory);
2021 ok(ref == 0, "factory not released, %lu.\n", ref);
2022 DELETE_FONTFILE(path);
2025 static void get_expected_font_metrics(IDWriteFontFace *fontface, DWRITE_FONT_METRICS1 *metrics)
2027 void *os2_context, *head_context, *post_context, *hhea_context;
2028 const struct tt_os2 *tt_os2;
2029 const TT_HEAD *tt_head;
2030 const TT_POST *tt_post;
2031 const TT_HHEA *tt_hhea;
2032 UINT32 size;
2033 BOOL exists;
2034 HRESULT hr;
2036 memset(metrics, 0, sizeof(*metrics));
2038 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
2039 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2040 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void**)&tt_head, &size, &head_context, &exists);
2041 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2042 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HHEA_TAG, (const void**)&tt_hhea, &size, &hhea_context, &exists);
2043 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2044 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_POST_TAG, (const void**)&tt_post, &size, &post_context, &exists);
2045 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2047 if (tt_head) {
2048 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
2049 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
2050 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
2051 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
2052 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
2055 if (tt_os2) {
2056 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
2057 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
2058 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
2059 metrics->descent = descent < 0 ? -descent : 0;
2060 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
2061 metrics->hasTypographicMetrics = TRUE;
2063 else {
2064 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
2065 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
2066 interpreted as large unsigned value. */
2067 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
2069 if (tt_hhea) {
2070 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
2071 INT32 linegap;
2073 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
2074 metrics->ascent - metrics->descent;
2075 metrics->lineGap = linegap > 0 ? linegap : 0;
2079 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
2080 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
2082 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
2083 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
2084 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
2085 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
2086 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
2087 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
2088 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
2089 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
2091 else {
2092 metrics->strikethroughPosition = metrics->designUnitsPerEm / 3;
2093 if (tt_hhea) {
2094 metrics->ascent = GET_BE_WORD(tt_hhea->ascender);
2095 metrics->descent = abs((SHORT)GET_BE_WORD(tt_hhea->descender));
2099 if (tt_post) {
2100 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
2101 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
2104 if (metrics->underlineThickness == 0)
2105 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
2106 if (metrics->strikethroughThickness == 0)
2107 metrics->strikethroughThickness = metrics->underlineThickness;
2109 if (tt_os2)
2110 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2111 if (tt_head)
2112 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2113 if (tt_hhea)
2114 IDWriteFontFace_ReleaseFontTable(fontface, hhea_context);
2115 if (tt_post)
2116 IDWriteFontFace_ReleaseFontTable(fontface, post_context);
2119 static void check_font_metrics(const WCHAR *nameW, IDWriteFontFace *fontface, const DWRITE_FONT_METRICS1 *expected)
2121 IDWriteFontFace1 *fontface1 = NULL;
2122 DWRITE_FONT_METRICS1 metrics;
2123 DWORD simulations;
2124 BOOL has_metrics1;
2126 has_metrics1 = SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1));
2127 simulations = IDWriteFontFace_GetSimulations(fontface);
2129 if (fontface1) {
2130 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
2131 IDWriteFontFace1_Release(fontface1);
2133 else
2134 IDWriteFontFace_GetMetrics(fontface, (DWRITE_FONT_METRICS *)&metrics);
2136 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
2138 ok(metrics.designUnitsPerEm == expected->designUnitsPerEm, "designUnitsPerEm %u, expected %u.\n",
2139 metrics.designUnitsPerEm, expected->designUnitsPerEm);
2140 ok(metrics.ascent == expected->ascent, "ascent %u, expected %u.\n", metrics.ascent, expected->ascent);
2141 ok(metrics.descent == expected->descent, "descent %u, expected %u.\n", metrics.descent, expected->descent);
2142 ok(metrics.lineGap == expected->lineGap, "lineGap %d, expected %d.\n", metrics.lineGap, expected->lineGap);
2143 ok(metrics.underlinePosition == expected->underlinePosition, "underlinePosition %d, expected %d.\n",
2144 metrics.underlinePosition, expected->underlinePosition);
2145 ok(metrics.underlineThickness == expected->underlineThickness, "underlineThickness %u, expected %u.\n",
2146 metrics.underlineThickness, expected->underlineThickness);
2147 ok(metrics.strikethroughPosition == expected->strikethroughPosition, "strikethroughPosition %d, expected %d.\n",
2148 metrics.strikethroughPosition, expected->strikethroughPosition);
2149 ok(metrics.strikethroughThickness == expected->strikethroughThickness, "strikethroughThickness %u, "
2150 "expected %u.\n", metrics.strikethroughThickness, expected->strikethroughThickness);
2152 if (has_metrics1)
2154 /* For simulated faces metrics are adjusted. Enable tests when exact pattern is understood. */
2155 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2157 winetest_pop_context();
2158 return;
2161 ok(metrics.hasTypographicMetrics == expected->hasTypographicMetrics, "hasTypographicMetrics %d, "
2162 "expected %d.\n", metrics.hasTypographicMetrics, expected->hasTypographicMetrics);
2163 ok(metrics.glyphBoxLeft == expected->glyphBoxLeft, "glyphBoxLeft %d, expected %d.\n",
2164 metrics.glyphBoxLeft, expected->glyphBoxLeft);
2165 ok(metrics.glyphBoxTop == expected->glyphBoxTop, "glyphBoxTop %d, expected %d.\n",
2166 metrics.glyphBoxTop, expected->glyphBoxTop);
2167 ok(metrics.glyphBoxRight == expected->glyphBoxRight, "glyphBoxRight %d, expected %d.\n",
2168 metrics.glyphBoxRight, expected->glyphBoxRight);
2169 ok(metrics.glyphBoxBottom == expected->glyphBoxBottom, "glyphBoxBottom %d, expected %d.\n",
2170 metrics.glyphBoxBottom, expected->glyphBoxBottom);
2172 ok(metrics.subscriptPositionX == expected->subscriptPositionX, "subscriptPositionX %d, expected %d.\n",
2173 metrics.subscriptPositionX, expected->subscriptPositionX);
2174 ok(metrics.subscriptPositionY == expected->subscriptPositionY, "subscriptPositionY %d, expected %d.\n",
2175 metrics.subscriptPositionY, expected->subscriptPositionY);
2176 ok(metrics.subscriptSizeX == expected->subscriptSizeX, "subscriptSizeX %d, expected %d.\n",
2177 metrics.subscriptSizeX, expected->subscriptSizeX);
2178 ok(metrics.subscriptSizeY == expected->subscriptSizeY, "subscriptSizeY %d, expected %d.\n",
2179 metrics.subscriptSizeY, expected->subscriptSizeY);
2180 ok(metrics.superscriptPositionX == expected->superscriptPositionX, "superscriptPositionX %d, expected %d.\n",
2181 metrics.superscriptPositionX, expected->superscriptPositionX);
2182 ok(metrics.superscriptPositionY == expected->superscriptPositionY, "superscriptPositionY %d, expected %d.\n",
2183 metrics.superscriptPositionY, expected->superscriptPositionY);
2184 ok(metrics.superscriptSizeX == expected->superscriptSizeX, "superscriptSizeX %d, expected %d.\n",
2185 metrics.superscriptSizeX, expected->superscriptSizeX);
2186 ok(metrics.superscriptSizeY == expected->superscriptSizeY, "superscriptSizeY %d, expected %d.\n",
2187 metrics.superscriptSizeY, expected->superscriptSizeY);
2190 winetest_pop_context();
2193 static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
2195 BOOL exists = FALSE;
2196 UINT32 index;
2197 HRESULT hr;
2199 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
2200 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2201 if (!exists)
2202 index = 0;
2203 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
2204 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2207 static void test_GetMetrics(void)
2209 DWRITE_FONT_METRICS metrics, metrics2;
2210 IDWriteFontCollection *syscollection;
2211 IDWriteGdiInterop *interop;
2212 IDWriteFontFace *fontface;
2213 IDWriteFactory *factory;
2214 OUTLINETEXTMETRICW otm;
2215 IDWriteFontFile *file;
2216 IDWriteFont1 *font1;
2217 IDWriteFont *font;
2218 LOGFONTW logfont;
2219 UINT32 count, i;
2220 HRESULT hr;
2221 HDC hdc;
2222 HFONT hfont;
2223 ULONG ref;
2224 int ret;
2226 factory = create_factory();
2228 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2229 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2231 memset(&logfont, 0, sizeof(logfont));
2232 logfont.lfHeight = 12;
2233 logfont.lfWidth = 12;
2234 logfont.lfWeight = FW_NORMAL;
2235 logfont.lfItalic = 1;
2236 lstrcpyW(logfont.lfFaceName, L"Tahoma");
2238 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2239 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2241 hfont = CreateFontIndirectW(&logfont);
2242 hdc = CreateCompatibleDC(0);
2243 SelectObject(hdc, hfont);
2245 otm.otmSize = sizeof(otm);
2246 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
2247 ok(ret, "got %d\n", ret);
2248 DeleteDC(hdc);
2249 DeleteObject(hfont);
2251 if (0) /* crashes on native */
2252 IDWriteFont_GetMetrics(font, NULL);
2254 memset(&metrics, 0, sizeof(metrics));
2255 IDWriteFont_GetMetrics(font, &metrics);
2257 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2258 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2259 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2260 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2261 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2262 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2263 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2264 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2265 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2266 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2268 hr = IDWriteFont_CreateFontFace(font, &fontface);
2269 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2271 memset(&metrics, 0, sizeof(metrics));
2272 IDWriteFontFace_GetMetrics(fontface, &metrics);
2274 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2275 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2276 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2277 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2278 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2279 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2280 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2281 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2282 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2283 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2285 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
2286 if (hr == S_OK) {
2287 DWRITE_FONT_METRICS1 metrics1;
2288 IDWriteFontFace1 *fontface1;
2290 memset(&metrics1, 0, sizeof(metrics1));
2291 IDWriteFont1_GetMetrics(font1, &metrics1);
2293 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2294 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2295 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2296 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2297 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2298 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2299 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2300 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2301 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2302 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2303 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2304 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2305 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2306 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2307 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2308 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2309 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2310 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2311 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2312 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2313 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2315 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2316 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2318 memset(&metrics1, 0, sizeof(metrics1));
2319 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2321 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2322 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2323 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2324 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2325 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2326 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2327 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2328 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2329 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2330 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2331 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2332 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2333 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2334 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2335 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2336 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2337 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2338 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2339 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2340 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2341 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2343 IDWriteFontFace1_Release(fontface1);
2344 IDWriteFont1_Release(font1);
2346 else
2347 win_skip("DWRITE_FONT_METRICS1 is not supported.\n");
2349 IDWriteFontFace_Release(fontface);
2350 IDWriteFont_Release(font);
2351 IDWriteGdiInterop_Release(interop);
2353 /* bold simulation affects returned font metrics */
2354 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
2356 /* create regulat Tahoma with bold simulation */
2357 hr = IDWriteFont_CreateFontFace(font, &fontface);
2358 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2360 count = 1;
2361 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
2362 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2364 IDWriteFontFace_GetMetrics(fontface, &metrics);
2365 ok(IDWriteFontFace_GetSimulations(fontface) == 0, "wrong simulations flags\n");
2366 IDWriteFontFace_Release(fontface);
2368 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
2369 0, DWRITE_FONT_SIMULATIONS_BOLD, &fontface);
2370 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2371 IDWriteFontFace_GetMetrics(fontface, &metrics2);
2372 ok(IDWriteFontFace_GetSimulations(fontface) == DWRITE_FONT_SIMULATIONS_BOLD, "wrong simulations flags\n");
2374 ok(metrics.ascent == metrics2.ascent, "got %u, %u\n", metrics2.ascent, metrics.ascent);
2375 ok(metrics.descent == metrics2.descent, "got %u, %u\n", metrics2.descent, metrics.descent);
2376 ok(metrics.lineGap == metrics2.lineGap, "got %d, %d\n", metrics2.lineGap, metrics.lineGap);
2377 ok(metrics.capHeight == metrics2.capHeight, "got %u, %u\n", metrics2.capHeight, metrics.capHeight);
2378 ok(metrics.xHeight == metrics2.xHeight, "got %u, %u\n", metrics2.xHeight, metrics.xHeight);
2379 ok(metrics.underlinePosition == metrics2.underlinePosition, "got %d, %d\n", metrics2.underlinePosition,
2380 metrics.underlinePosition);
2381 ok(metrics.underlineThickness == metrics2.underlineThickness, "got %u, %u\n", metrics2.underlineThickness,
2382 metrics.underlineThickness);
2383 ok(metrics.strikethroughPosition == metrics2.strikethroughPosition, "got %d, %d\n", metrics2.strikethroughPosition,
2384 metrics.strikethroughPosition);
2385 ok(metrics.strikethroughThickness == metrics2.strikethroughThickness, "got %u, %u\n", metrics2.strikethroughThickness,
2386 metrics.strikethroughThickness);
2388 IDWriteFontFile_Release(file);
2389 IDWriteFontFace_Release(fontface);
2390 IDWriteFont_Release(font);
2392 /* test metrics for whole system collection */
2393 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
2394 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2395 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
2397 for (i = 0; i < count; i++) {
2398 DWRITE_FONT_METRICS1 expected_metrics;
2399 WCHAR familyW[256], faceW[256];
2400 IDWriteLocalizedStrings *names;
2401 IDWriteFontFamily *family;
2402 UINT32 fontcount, j;
2403 IDWriteFont *font;
2405 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
2406 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2408 fontcount = IDWriteFontFamily_GetFontCount(family);
2410 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2411 ok(hr == S_OK, "Failed to get family names, hr %#lx.\n", hr);
2412 get_enus_string(names, familyW, ARRAY_SIZE(familyW));
2413 IDWriteLocalizedStrings_Release(names);
2415 for (j = 0; j < fontcount; j++) {
2416 WCHAR nameW[256];
2418 hr = IDWriteFontFamily_GetFont(family, j, &font);
2419 ok(hr == S_OK, "Failed to get a font, hr %#lx.\n", hr);
2421 hr = IDWriteFont_CreateFontFace(font, &fontface);
2422 ok(hr == S_OK, "Failed to create face instance, hr %#lx.\n", hr);
2424 hr = IDWriteFont_GetFaceNames(font, &names);
2425 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
2426 get_enus_string(names, faceW, ARRAY_SIZE(faceW));
2427 IDWriteLocalizedStrings_Release(names);
2429 IDWriteFont_Release(font);
2431 get_combined_font_name(familyW, faceW, nameW);
2433 if (has_face_variations(fontface))
2435 static int once;
2436 if (!once++)
2437 skip("GetMetrics() test does not support variable fonts.\n");
2438 IDWriteFontFace_Release(fontface);
2439 continue;
2442 get_expected_font_metrics(fontface, &expected_metrics);
2443 check_font_metrics(nameW, fontface, &expected_metrics);
2445 IDWriteFontFace_Release(fontface);
2448 IDWriteFontFamily_Release(family);
2450 IDWriteFontCollection_Release(syscollection);
2451 ref = IDWriteFactory_Release(factory);
2452 ok(ref == 0, "factory not released, %lu\n", ref);
2455 static void test_system_fontcollection(void)
2457 IDWriteFontCollection *collection, *coll2;
2458 IDWriteLocalFontFileLoader *localloader;
2459 IDWriteFontCollection1 *collection1;
2460 IDWriteFontCollection2 *collection2;
2461 IDWriteFontCollection3 *collection3;
2462 IDWriteFactory *factory, *factory2;
2463 IDWriteFontFileLoader *loader;
2464 IDWriteFontFamily *family;
2465 IDWriteFontFace *fontface;
2466 IDWriteFactory6 *factory6;
2467 IDWriteFontFile *file;
2468 IDWriteFont *font;
2469 HRESULT hr;
2470 ULONG ref;
2471 UINT32 i;
2472 BOOL ret;
2474 factory = create_factory();
2476 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2477 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2479 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, FALSE);
2480 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2481 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2482 IDWriteFontCollection_Release(coll2);
2484 factory2 = create_factory();
2485 hr = IDWriteFactory_GetSystemFontCollection(factory2, &coll2, FALSE);
2486 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2487 ok(coll2 != collection, "got %p, was %p\n", coll2, collection);
2488 IDWriteFontCollection_Release(coll2);
2489 IDWriteFactory_Release(factory2);
2491 i = IDWriteFontCollection_GetFontFamilyCount(collection);
2492 ok(i, "got %u\n", i);
2494 /* invalid index */
2495 family = (void*)0xdeadbeef;
2496 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2497 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
2498 ok(family == NULL, "got %p\n", family);
2500 ret = FALSE;
2501 i = (UINT32)-1;
2502 hr = IDWriteFontCollection_FindFamilyName(collection, L"Tahoma", &i, &ret);
2503 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2504 ok(ret, "got %d\n", ret);
2505 ok(i != (UINT32)-1, "got %u\n", i);
2507 ret = FALSE;
2508 i = (UINT32)-1;
2509 hr = IDWriteFontCollection_FindFamilyName(collection, L"TAHOMA", &i, &ret);
2510 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2511 ok(ret, "got %d\n", ret);
2512 ok(i != (UINT32)-1, "got %u\n", i);
2514 ret = FALSE;
2515 i = (UINT32)-1;
2516 hr = IDWriteFontCollection_FindFamilyName(collection, L"tAhOmA", &i, &ret);
2517 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2518 ok(ret, "got %d\n", ret);
2519 ok(i != (UINT32)-1, "got %u\n", i);
2521 /* get back local file loader */
2522 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2523 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2525 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2526 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2527 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2528 IDWriteFontFamily_Release(family);
2530 hr = IDWriteFont_CreateFontFace(font, &fontface);
2531 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2532 IDWriteFont_Release(font);
2534 i = 1;
2535 file = NULL;
2536 hr = IDWriteFontFace_GetFiles(fontface, &i, &file);
2537 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2538 ok(file != NULL, "got %p\n", file);
2539 IDWriteFontFace_Release(fontface);
2541 hr = IDWriteFontFile_GetLoader(file, &loader);
2542 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2543 IDWriteFontFile_Release(file);
2545 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2546 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2547 IDWriteLocalFontFileLoader_Release(localloader);
2549 /* local loader is not registered by default */
2550 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
2551 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "Unexpected hr %#lx.\n", hr);
2552 hr = IDWriteFactory_UnregisterFontFileLoader(factory, loader);
2553 ok(hr == S_OK || broken(hr == E_INVALIDARG), "Unexpected hr %#lx.\n", hr);
2555 /* try with a different factory */
2556 factory2 = create_factory();
2557 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2558 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "Unexpected hr %#lx.\n", hr);
2559 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2560 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
2561 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2562 ok(hr == S_OK || broken(hr == E_INVALIDARG), "Unexpected hr %#lx.\n", hr);
2563 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2564 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2565 IDWriteFactory_Release(factory2);
2567 IDWriteFontFileLoader_Release(loader);
2569 ret = TRUE;
2570 i = 0;
2571 hr = IDWriteFontCollection_FindFamilyName(collection, L"Blah!", &i, &ret);
2572 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2573 ok(!ret, "got %d\n", ret);
2574 ok(i == (UINT32)-1, "got %u\n", i);
2576 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection1, (void**)&collection1);
2577 if (hr == S_OK) {
2578 IDWriteFontSet *fontset, *fontset2;
2579 IDWriteFontFamily1 *family1;
2580 IDWriteFactory3 *factory3;
2582 hr = IDWriteFontCollection1_QueryInterface(collection1, &IID_IDWriteFontCollection, (void**)&coll2);
2583 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2584 ok(coll2 == collection, "got %p, %p\n", collection, coll2);
2585 IDWriteFontCollection_Release(coll2);
2587 family1 = (void*)0xdeadbeef;
2588 hr = IDWriteFontCollection1_GetFontFamily(collection1, ~0u, &family1);
2589 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
2590 ok(family1 == NULL, "got %p\n", family1);
2592 hr = IDWriteFontCollection1_GetFontFamily(collection1, 0, &family1);
2593 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2594 IDWriteFontFamily1_Release(family1);
2596 /* system fontset */
2597 EXPECT_REF(collection1, 2);
2598 EXPECT_REF(factory, 2);
2599 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset);
2600 todo_wine
2601 ok(hr == S_OK, "Failed to get fontset, hr %#lx.\n", hr);
2602 if (hr == S_OK) {
2603 EXPECT_REF(collection1, 2);
2604 EXPECT_REF(factory, 2);
2605 EXPECT_REF(fontset, 1);
2607 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset2);
2608 ok(hr == S_OK, "Failed to get fontset, hr %#lx.\n", hr);
2609 ok(fontset != fontset2, "Expected new fontset instance.\n");
2610 EXPECT_REF(fontset2, 1);
2611 IDWriteFontSet_Release(fontset2);
2613 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3);
2614 ok(hr == S_OK, "Failed to get IDWriteFactory3 interface, hr %#lx.\n", hr);
2616 EXPECT_REF(factory, 3);
2617 hr = IDWriteFactory3_GetSystemFontSet(factory3, &fontset2);
2618 ok(hr == S_OK, "Failed to get system font set, hr %#lx.\n", hr);
2619 ok(fontset != fontset2, "Expected new fontset instance.\n");
2620 EXPECT_REF(fontset2, 1);
2621 EXPECT_REF(factory, 4);
2623 IDWriteFontSet_Release(fontset2);
2624 IDWriteFontSet_Release(fontset);
2626 IDWriteFactory3_Release(factory3);
2628 IDWriteFontCollection1_Release(collection1);
2630 else
2631 win_skip("IDWriteFontCollection1 is not supported.\n");
2633 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
2634 if (SUCCEEDED(hr))
2636 HANDLE event;
2638 event = IDWriteFontCollection3_GetExpirationEvent(collection3);
2639 todo_wine
2640 ok(!!event, "Expected event handle.\n");
2642 check_familymodel(collection3, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE);
2644 IDWriteFontCollection3_Release(collection3);
2646 else
2647 win_skip("IDWriteFontCollection3 is not supported.\n");
2649 /* With specified family model. */
2650 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory6, (void **)&factory6);
2651 if (SUCCEEDED(hr))
2653 IDWriteFontCollection2 *c2;
2655 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
2656 &collection2);
2657 ok(hr == S_OK, "Failed to get collection, hr %#lx.\n", hr);
2659 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC, &c2);
2660 ok(hr == S_OK, "Failed to get collection, hr %#lx.\n", hr);
2661 ok(c2 == collection2 && collection != (IDWriteFontCollection *)c2, "Unexpected collection instance.\n");
2662 IDWriteFontCollection2_Release(c2);
2663 IDWriteFontCollection2_Release(collection2);
2665 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE,
2666 &collection2);
2667 ok(hr == S_OK, "Failed to get collection, hr %#lx.\n", hr);
2668 IDWriteFontCollection2_Release(collection2);
2669 IDWriteFactory6_Release(factory6);
2671 else
2672 win_skip("IDWriteFactory6 is not supported.\n");
2674 ref = IDWriteFontCollection_Release(collection);
2675 ok(!ref, "Collection wasn't released, %lu.\n", ref);
2676 ref = IDWriteFactory_Release(factory);
2677 ok(!ref, "Factory wasn't released, %lu.\n", ref);
2680 static void get_logfont_from_font(IDWriteFont *font, LOGFONTW *logfont)
2682 void *os2_context, *head_context;
2683 IDWriteLocalizedStrings *names;
2684 DWRITE_FONT_SIMULATIONS sim;
2685 const struct tt_os2 *tt_os2;
2686 IDWriteFontFace *fontface;
2687 DWRITE_FONT_STYLE style;
2688 const TT_HEAD *tt_head;
2689 LONG weight;
2690 UINT32 size;
2691 BOOL exists;
2692 HRESULT hr;
2694 /* These are rendering time properties. */
2695 logfont->lfHeight = 0;
2696 logfont->lfWidth = 0;
2697 logfont->lfEscapement = 0;
2698 logfont->lfOrientation = 0;
2699 logfont->lfUnderline = 0;
2700 logfont->lfStrikeOut = 0;
2702 logfont->lfWeight = 0;
2703 logfont->lfItalic = 0;
2705 hr = IDWriteFont_CreateFontFace(font, &fontface);
2706 ok(hr == S_OK, "Failed to create font face, %#lx\n", hr);
2708 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size,
2709 &os2_context, &exists);
2710 ok(hr == S_OK, "Failed to get OS/2 table, %#lx\n", hr);
2712 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void **)&tt_head, &size,
2713 &head_context, &exists);
2714 ok(hr == S_OK, "Failed to get head table, %#lx\n", hr);
2716 sim = IDWriteFont_GetSimulations(font);
2718 /* lfWeight */
2719 weight = FW_REGULAR;
2720 if (tt_os2) {
2721 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
2723 if (usWeightClass >= 1 && usWeightClass <= 9)
2724 usWeightClass *= 100;
2726 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
2727 weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
2728 else if (usWeightClass > 0)
2729 weight = usWeightClass;
2731 else if (tt_head) {
2732 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2733 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
2734 weight = DWRITE_FONT_WEIGHT_BOLD;
2736 if (sim & DWRITE_FONT_SIMULATIONS_BOLD)
2737 weight += (FW_BOLD - FW_REGULAR) / 2 + 1;
2738 logfont->lfWeight = weight;
2740 /* lfItalic */
2741 if (IDWriteFont_GetSimulations(font) & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2742 logfont->lfItalic = 1;
2744 style = IDWriteFont_GetStyle(font);
2745 if (!logfont->lfItalic && ((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE))) {
2746 if (tt_os2) {
2747 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
2748 logfont->lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
2750 else if (tt_head) {
2751 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2752 logfont->lfItalic = !!(macStyle & TT_HEAD_MACSTYLE_ITALIC);
2756 /* lfFaceName */
2757 exists = FALSE;
2758 logfont->lfFaceName[0] = 0;
2759 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &exists);
2760 if (SUCCEEDED(hr))
2762 if (exists)
2764 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
2765 WCHAR nameW[256];
2766 UINT32 index;
2768 /* Fallback to en-us if there's no string for user locale. */
2769 exists = FALSE;
2770 if (GetSystemDefaultLocaleName(localeW, ARRAY_SIZE(localeW)))
2771 IDWriteLocalizedStrings_FindLocaleName(names, localeW, &index, &exists);
2773 if (!exists)
2774 IDWriteLocalizedStrings_FindLocaleName(names, L"en-us", &index, &exists);
2776 if (exists) {
2777 nameW[0] = 0;
2778 hr = IDWriteLocalizedStrings_GetString(names, index, nameW, ARRAY_SIZE(nameW));
2779 ok(hr == S_OK, "Failed to get name string, hr %#lx.\n", hr);
2780 lstrcpynW(logfont->lfFaceName, nameW, ARRAY_SIZE(logfont->lfFaceName));
2784 IDWriteLocalizedStrings_Release(names);
2787 if (tt_os2)
2788 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2789 if (tt_head)
2790 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2791 IDWriteFontFace_Release(fontface);
2794 static void test_ConvertFontFaceToLOGFONT(void)
2796 IDWriteFontCollection *collection;
2797 IDWriteGdiInterop *interop;
2798 IDWriteFontFace *fontface;
2799 IDWriteFactory *factory;
2800 LOGFONTW logfont;
2801 UINT32 count, i;
2802 HRESULT hr;
2803 ULONG ref;
2805 factory = create_factory();
2807 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2808 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2810 if (0) /* crashes on native */
2812 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, NULL);
2813 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, NULL);
2815 memset(&logfont, 0xcc, sizeof(logfont));
2816 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, &logfont);
2817 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2818 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2820 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2821 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2823 count = IDWriteFontCollection_GetFontFamilyCount(collection);
2824 for (i = 0; i < count; i++) {
2825 WCHAR nameW[128], familynameW[64], facenameW[64];
2826 IDWriteLocalizedStrings *names;
2827 DWRITE_FONT_SIMULATIONS sim;
2828 IDWriteFontFamily *family;
2829 UINT32 font_count, j;
2830 IDWriteFont *font;
2831 LOGFONTW lf;
2833 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2834 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2836 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2837 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2839 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
2840 IDWriteLocalizedStrings_Release(names);
2842 font_count = IDWriteFontFamily_GetFontCount(family);
2844 for (j = 0; j < font_count; j++) {
2845 IDWriteFontFace *fontface;
2847 hr = IDWriteFontFamily_GetFont(family, j, &font);
2848 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2850 hr = IDWriteFont_GetFaceNames(font, &names);
2851 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2853 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
2854 IDWriteLocalizedStrings_Release(names);
2856 get_combined_font_name(familynameW, facenameW, nameW);
2858 hr = IDWriteFont_CreateFontFace(font, &fontface);
2859 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2861 if (has_face_variations(fontface))
2863 static int once;
2864 if (!once++)
2865 skip("ConvertFontFaceToLOGFONT() test does not support variable fonts.\n");
2866 IDWriteFontFace_Release(fontface);
2867 IDWriteFont_Release(font);
2868 continue;
2871 memset(&logfont, 0xcc, sizeof(logfont));
2872 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, &logfont);
2873 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2875 sim = IDWriteFontFace_GetSimulations(fontface);
2876 get_logfont_from_font(font, &lf);
2878 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
2880 ok(logfont.lfWeight == lf.lfWeight, "Unexpected lfWeight %ld, expected lfWeight %ld, font weight %d, "
2881 "bold simulation %s.\n", logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
2882 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
2883 ok(logfont.lfItalic == lf.lfItalic, "Unexpected italic flag %d, oblique simulation %s.\n",
2884 logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
2885 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "Unexpected facename %s, expected %s\n",
2886 wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
2888 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "Unexpected output precision %d.\n", logfont.lfOutPrecision);
2889 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "Unexpected clipping precision %d.\n", logfont.lfClipPrecision);
2890 ok(logfont.lfQuality == DEFAULT_QUALITY, "Unexpected quality %d.\n", logfont.lfQuality);
2891 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "Unexpected pitch %d.\n", logfont.lfPitchAndFamily);
2893 winetest_pop_context();
2895 IDWriteFontFace_Release(fontface);
2896 IDWriteFont_Release(font);
2899 IDWriteFontFamily_Release(family);
2902 IDWriteFontCollection_Release(collection);
2903 IDWriteGdiInterop_Release(interop);
2904 ref = IDWriteFactory_Release(factory);
2905 ok(ref == 0, "factory not released, %lu\n", ref);
2908 static HRESULT WINAPI fontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2910 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
2912 *obj = iface;
2913 IDWriteFontFileEnumerator_AddRef(iface);
2914 return S_OK;
2916 return E_NOINTERFACE;
2919 static ULONG WINAPI fontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2921 return 2;
2924 static ULONG WINAPI fontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2926 return 1;
2929 static HRESULT WINAPI fontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2931 *file = NULL;
2932 return E_FAIL;
2935 static HRESULT WINAPI fontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2937 *current = FALSE;
2938 return S_OK;
2941 static const struct IDWriteFontFileEnumeratorVtbl dwritefontfileenumeratorvtbl =
2943 fontfileenumerator_QueryInterface,
2944 fontfileenumerator_AddRef,
2945 fontfileenumerator_Release,
2946 fontfileenumerator_MoveNext,
2947 fontfileenumerator_GetCurrentFontFile,
2950 struct collection_loader
2952 IDWriteFontCollectionLoader IDWriteFontCollectionLoader_iface;
2953 LONG ref;
2956 static inline struct collection_loader *impl_from_IDWriteFontCollectionLoader(IDWriteFontCollectionLoader *iface)
2958 return CONTAINING_RECORD(iface, struct collection_loader, IDWriteFontCollectionLoader_iface);
2961 static HRESULT WINAPI fontcollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
2963 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2965 if (IsEqualIID(&IID_IDWriteFontCollectionLoader, riid) ||
2966 IsEqualIID(&IID_IUnknown, riid))
2968 *obj = &loader->IDWriteFontCollectionLoader_iface;
2969 IDWriteFontCollectionLoader_AddRef(iface);
2970 return S_OK;
2973 *obj = NULL;
2974 return E_NOINTERFACE;
2977 static ULONG WINAPI fontcollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
2979 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2980 return InterlockedIncrement(&loader->ref);
2983 static ULONG WINAPI fontcollectionloader_Release(IDWriteFontCollectionLoader *iface)
2985 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2986 ULONG ref = InterlockedDecrement(&loader->ref);
2988 if (!ref)
2989 free(loader);
2991 return ref;
2994 static HRESULT WINAPI fontcollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory, const void *key,
2995 UINT32 key_size, IDWriteFontFileEnumerator **ret)
2997 static IDWriteFontFileEnumerator enumerator = { &dwritefontfileenumeratorvtbl };
2998 *ret = &enumerator;
2999 return S_OK;
3002 static const struct IDWriteFontCollectionLoaderVtbl dwritefontcollectionloadervtbl = {
3003 fontcollectionloader_QueryInterface,
3004 fontcollectionloader_AddRef,
3005 fontcollectionloader_Release,
3006 fontcollectionloader_CreateEnumeratorFromKey
3009 static IDWriteFontCollectionLoader *create_collection_loader(void)
3011 struct collection_loader *loader = malloc(sizeof(*loader));
3013 loader->IDWriteFontCollectionLoader_iface.lpVtbl = &dwritefontcollectionloadervtbl;
3014 loader->ref = 1;
3016 return &loader->IDWriteFontCollectionLoader_iface;
3019 static void test_CustomFontCollection(void)
3021 IDWriteFontCollectionLoader *loader, *loader2, *loader3;
3022 IDWriteFontCollection *font_collection = NULL;
3023 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
3024 struct test_fontcollectionloader resource_collection = { { &resourcecollectionloadervtbl }, &rloader };
3025 IDWriteFontFamily *family, *family2, *family3;
3026 IDWriteFontFace *idfontface, *idfontface2;
3027 IDWriteFontFile *fontfile, *fontfile2;
3028 IDWriteLocalizedStrings *string;
3029 IDWriteFont *idfont, *idfont2;
3030 IDWriteFactory *factory;
3031 UINT32 index, count;
3032 BOOL exists;
3033 HRESULT hr;
3034 HRSRC font;
3035 ULONG ref;
3037 factory = create_factory();
3039 loader = create_collection_loader();
3040 loader2 = create_collection_loader();
3041 loader3 = create_collection_loader();
3043 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, NULL);
3044 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3046 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, NULL);
3047 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3049 EXPECT_REF(loader, 1);
3050 EXPECT_REF(loader2, 1);
3052 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
3053 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3054 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader2);
3055 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3056 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
3057 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
3059 EXPECT_REF(loader, 2);
3060 EXPECT_REF(loader2, 2);
3062 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3063 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3064 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
3065 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3067 /* Loader wasn't registered. */
3068 font_collection = (void*)0xdeadbeef;
3069 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader3, "Billy", 6, &font_collection);
3070 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3071 ok(font_collection == NULL, "got %p\n", font_collection);
3073 EXPECT_REF(factory, 1);
3074 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader, "Billy", 6, &font_collection);
3075 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3076 todo_wine
3077 EXPECT_REF(factory, 1);
3078 EXPECT_REF(loader, 2);
3079 IDWriteFontCollection_Release(font_collection);
3081 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader2, "Billy", 6, &font_collection);
3082 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3083 IDWriteFontCollection_Release(font_collection);
3085 font_collection = (void*)0xdeadbeef;
3086 hr = IDWriteFactory_CreateCustomFontCollection(factory, (IDWriteFontCollectionLoader*)0xdeadbeef, "Billy", 6, &font_collection);
3087 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3088 ok(font_collection == NULL, "got %p\n", font_collection);
3090 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3091 ok(font != NULL, "Failed to find font resource\n");
3093 hr = IDWriteFactory_CreateCustomFontCollection(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface,
3094 &font, sizeof(HRSRC), &font_collection);
3095 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
3096 EXPECT_REF(font_collection, 1);
3098 index = 1;
3099 exists = FALSE;
3100 hr = IDWriteFontCollection_FindFamilyName(font_collection, L"wine_test", &index, &exists);
3101 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3102 ok(index == 0, "got index %i\n", index);
3103 ok(exists, "got exists %i\n", exists);
3105 count = IDWriteFontCollection_GetFontFamilyCount(font_collection);
3106 ok(count == 1, "got %u\n", count);
3108 family = NULL;
3109 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family);
3110 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3111 EXPECT_REF(family, 1);
3113 family2 = NULL;
3114 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family2);
3115 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3116 EXPECT_REF(family2, 1);
3117 ok(family != family2, "got %p, %p\n", family, family2);
3119 hr = IDWriteFontFamily_GetFont(family, 0, &idfont);
3120 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3121 EXPECT_REF(idfont, 1);
3122 EXPECT_REF(family, 2);
3123 hr = IDWriteFontFamily_GetFont(family, 0, &idfont2);
3124 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3125 EXPECT_REF(idfont2, 1);
3126 EXPECT_REF(family, 3);
3127 ok(idfont != idfont2, "got %p, %p\n", idfont, idfont2);
3128 IDWriteFont_Release(idfont2);
3130 hr = IDWriteFont_GetInformationalStrings(idfont, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &string, &exists);
3131 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3132 ok(exists, "got %d\n", exists);
3133 EXPECT_REF(string, 1);
3134 IDWriteLocalizedStrings_Release(string);
3136 family3 = NULL;
3137 hr = IDWriteFont_GetFontFamily(idfont, &family3);
3138 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3139 EXPECT_REF(family, 3);
3140 ok(family == family3, "got %p, %p\n", family, family3);
3141 IDWriteFontFamily_Release(family3);
3143 idfontface = NULL;
3144 hr = IDWriteFont_CreateFontFace(idfont, &idfontface);
3145 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3146 EXPECT_REF(idfont, 1);
3148 idfont2 = NULL;
3149 hr = IDWriteFontFamily_GetFont(family2, 0, &idfont2);
3150 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3151 EXPECT_REF(idfont2, 1);
3152 EXPECT_REF(idfont, 1);
3153 ok(idfont2 != idfont, "Font instances should not match\n");
3155 idfontface2 = NULL;
3156 hr = IDWriteFont_CreateFontFace(idfont2, &idfontface2);
3157 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3158 ok(idfontface2 == idfontface, "fontfaces should match\n");
3160 index = 1;
3161 fontfile = NULL;
3162 hr = IDWriteFontFace_GetFiles(idfontface, &index, &fontfile);
3163 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3165 index = 1;
3166 fontfile2 = NULL;
3167 hr = IDWriteFontFace_GetFiles(idfontface2, &index, &fontfile2);
3168 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3169 ok(fontfile == fontfile2, "fontfiles should match\n");
3171 IDWriteFont_Release(idfont);
3172 IDWriteFont_Release(idfont2);
3173 IDWriteFontFile_Release(fontfile);
3174 IDWriteFontFile_Release(fontfile2);
3175 IDWriteFontFace_Release(idfontface);
3176 IDWriteFontFace_Release(idfontface2);
3177 IDWriteFontFamily_Release(family2);
3178 IDWriteFontFamily_Release(family);
3179 IDWriteFontCollection_Release(font_collection);
3181 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
3182 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3183 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
3184 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3185 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader2);
3186 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3187 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
3188 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3189 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3190 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3192 IDWriteFontCollectionLoader_Release(loader);
3193 IDWriteFontCollectionLoader_Release(loader2);
3194 IDWriteFontCollectionLoader_Release(loader3);
3196 ref = IDWriteFactory_Release(factory);
3197 ok(ref == 0, "factory not released, %lu\n", ref);
3200 static HRESULT WINAPI fontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
3202 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
3204 *obj = iface;
3205 IDWriteFontFileLoader_AddRef(iface);
3206 return S_OK;
3209 *obj = NULL;
3210 return E_NOINTERFACE;
3213 static ULONG WINAPI fontfileloader_AddRef(IDWriteFontFileLoader *iface)
3215 return 2;
3218 static ULONG WINAPI fontfileloader_Release(IDWriteFontFileLoader *iface)
3220 return 1;
3223 static HRESULT WINAPI fontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
3224 IDWriteFontFileStream **stream)
3226 return 0x8faecafe;
3229 static const struct IDWriteFontFileLoaderVtbl dwritefontfileloadervtbl = {
3230 fontfileloader_QueryInterface,
3231 fontfileloader_AddRef,
3232 fontfileloader_Release,
3233 fontfileloader_CreateStreamFromKey
3236 static void test_CreateCustomFontFileReference(void)
3238 IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl };
3239 IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl };
3240 IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl };
3241 IDWriteFactory *factory, *factory2;
3242 IDWriteFontFileLoader *loader;
3243 IDWriteFontFile *file, *file2;
3244 BOOL support;
3245 DWRITE_FONT_FILE_TYPE file_type;
3246 DWRITE_FONT_FACE_TYPE face_type;
3247 UINT32 count;
3248 IDWriteFontFace *face, *face2;
3249 HRESULT hr;
3250 HRSRC fontrsrc;
3251 UINT32 codePoints[1] = {0xa8};
3252 UINT16 indices[2];
3253 const void *key;
3254 UINT32 key_size;
3255 WCHAR *path;
3256 ULONG ref;
3258 path = create_testfontfile(test_fontfile);
3260 factory = create_factory();
3261 factory2 = create_factory();
3263 if (0) { /* crashes on win10 */
3264 hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
3265 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3267 /* local loader is accepted too */
3268 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3269 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3271 hr = IDWriteFontFile_GetLoader(file, &loader);
3272 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3274 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3275 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3277 hr = IDWriteFactory_CreateCustomFontFileReference(factory, key, key_size, loader, &file2);
3278 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3280 IDWriteFontFile_Release(file2);
3281 IDWriteFontFile_Release(file);
3282 IDWriteFontFileLoader_Release(loader);
3284 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3285 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3286 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader2);
3287 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3288 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3289 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
3290 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3291 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3293 file = NULL;
3294 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3295 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3296 IDWriteFontFile_Release(file);
3298 file = (void*)0xdeadbeef;
3299 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader3, &file);
3300 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3301 ok(file == NULL, "got %p\n", file);
3303 file = (void*)0xdeadbeef;
3304 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, NULL, &file);
3305 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3306 ok(file == NULL, "got %p\n", file);
3308 file = NULL;
3309 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3310 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3312 file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
3313 face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
3314 support = TRUE;
3315 count = 1;
3316 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3317 ok(hr == 0x8faecafe, "Unexpected hr %#lx.\n", hr);
3318 ok(support == FALSE, "got %i\n", support);
3319 ok(file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN, "got %i\n", file_type);
3320 ok(face_type == DWRITE_FONT_FACE_TYPE_UNKNOWN, "got %i\n", face_type);
3321 ok(count == 0, "got %i\n", count);
3323 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0, &face);
3324 ok(hr == 0x8faecafe, "Unexpected hr %#lx.\n", hr);
3325 IDWriteFontFile_Release(file);
3327 fontrsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3328 ok(fontrsrc != NULL, "Failed to find font resource\n");
3330 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file);
3331 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3333 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3334 face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3335 support = FALSE;
3336 count = 0;
3337 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3338 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3339 ok(support == TRUE, "got %i\n", support);
3340 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
3341 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
3342 ok(count == 1, "got %i\n", count);
3344 /* invalid index */
3345 face = (void*)0xdeadbeef;
3346 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 1, DWRITE_FONT_SIMULATIONS_NONE, &face);
3347 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3348 ok(face == NULL, "got %p\n", face);
3350 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
3351 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3353 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3354 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3355 /* fontface instances are reused starting with win7 */
3356 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3357 IDWriteFontFace_Release(face2);
3359 /* file was created with different factory */
3360 face2 = NULL;
3361 hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3362 todo_wine
3363 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3364 if (face2) {
3365 IDWriteFontFace_Release(face2);
3367 file2 = NULL;
3368 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2);
3369 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3370 ok(file != file2, "got %p, %p\n", file, file2);
3372 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3373 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3374 /* fontface instances are reused starting with win7 */
3375 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3376 IDWriteFontFace_Release(face2);
3377 IDWriteFontFile_Release(file2);
3379 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, NULL);
3380 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
3382 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, NULL);
3383 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
3385 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, indices);
3386 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3388 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, indices);
3389 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
3391 indices[0] = indices[1] = 11;
3392 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, indices);
3393 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3394 ok(indices[0] == 0, "got index %i\n", indices[0]);
3395 ok(indices[1] == 11, "got index %i\n", indices[1]);
3397 if (0) /* crashes on native */
3398 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, NULL);
3400 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 1, indices);
3401 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3402 ok(indices[0] == 7, "Unexpected glyph index, %u.\n", indices[0]);
3403 IDWriteFontFace_Release(face);
3404 IDWriteFontFile_Release(file);
3406 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3407 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3408 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3409 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3410 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader2);
3411 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3412 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3413 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3415 ref = IDWriteFactory_Release(factory2);
3416 ok(ref == 0, "factory not released, %lu\n", ref);
3417 ref = IDWriteFactory_Release(factory);
3418 ok(ref == 0, "factory not released, %lu\n", ref);
3419 DELETE_FONTFILE(path);
3422 static void test_CreateFontFileReference(void)
3424 HRESULT hr;
3425 IDWriteFontFile *ffile = NULL;
3426 BOOL support;
3427 DWRITE_FONT_FILE_TYPE type;
3428 DWRITE_FONT_FACE_TYPE face;
3429 UINT32 count;
3430 IDWriteFontFace *fface = NULL;
3431 IDWriteFactory *factory;
3432 WCHAR *path;
3433 ULONG ref;
3435 path = create_testfontfile(test_fontfile);
3436 factory = create_factory();
3438 ffile = (void*)0xdeadbeef;
3439 hr = IDWriteFactory_CreateFontFileReference(factory, NULL, NULL, &ffile);
3440 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n",hr);
3441 ok(ffile == NULL, "got %p\n", ffile);
3443 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &ffile);
3444 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
3446 support = FALSE;
3447 type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3448 face = DWRITE_FONT_FACE_TYPE_CFF;
3449 count = 0;
3450 hr = IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count);
3451 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3452 ok(support == TRUE, "got %i\n", support);
3453 ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type);
3454 ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face);
3455 ok(count == 1, "got %i\n", count);
3457 hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface);
3458 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3460 IDWriteFontFace_Release(fface);
3461 IDWriteFontFile_Release(ffile);
3462 ref = IDWriteFactory_Release(factory);
3463 ok(ref == 0, "factory not released, %lu\n", ref);
3465 DELETE_FONTFILE(path);
3468 static void test_shared_isolated(void)
3470 IDWriteFactory *isolated, *isolated2;
3471 IDWriteFactory *shared, *shared2;
3472 HRESULT hr;
3473 ULONG ref;
3475 /* invalid type */
3476 shared = NULL;
3477 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&shared);
3478 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3479 ok(shared != NULL, "got %p\n", shared);
3480 IDWriteFactory_Release(shared);
3482 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared);
3483 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3485 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3486 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3487 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3488 IDWriteFactory_Release(shared2);
3490 IDWriteFactory_Release(shared);
3492 /* we got 2 references, released 2 - still same pointer is returned */
3493 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3494 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3495 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3496 IDWriteFactory_Release(shared2);
3498 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated);
3499 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3501 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3502 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3503 ok(isolated != isolated2, "got %p, and %p\n", isolated, isolated2);
3504 IDWriteFactory_Release(isolated2);
3506 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IUnknown, (IUnknown**)&isolated2);
3507 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3508 IDWriteFactory_Release(isolated2);
3510 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3511 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3512 ok(shared != isolated2, "got %p, and %p\n", shared, isolated2);
3514 ref = IDWriteFactory_Release(isolated);
3515 ok(ref == 0, "factory not released, %lu\n", ref);
3516 ref = IDWriteFactory_Release(isolated2);
3517 ok(ref == 0, "factory not released, %lu\n", ref);
3520 struct dwrite_fonttable
3522 BYTE *data;
3523 void *context;
3524 UINT32 size;
3527 static const void *table_read_ensure(const struct dwrite_fonttable *table, unsigned int offset, unsigned int size)
3529 if (size > table->size || offset > table->size - size)
3530 return NULL;
3532 return table->data + offset;
3535 static WORD table_read_be_word(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
3537 if (!ptr)
3538 ptr = table->data;
3540 if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
3541 return 0;
3543 if (offset > table->size - sizeof(WORD))
3544 return 0;
3546 return GET_BE_WORD(*(WORD *)((BYTE *)ptr + offset));
3549 static DWORD table_read_be_dword(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
3551 if (!ptr)
3552 ptr = table->data;
3554 if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
3555 return 0;
3557 if (offset > table->size - sizeof(WORD))
3558 return 0;
3560 return GET_BE_DWORD(*(DWORD *)((BYTE *)ptr + offset));
3563 static void array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
3565 size_t new_capacity, max_capacity;
3566 void *new_elements;
3568 if (count <= *capacity)
3569 return;
3571 max_capacity = ~(SIZE_T)0 / size;
3572 if (count > max_capacity)
3573 return;
3575 new_capacity = max(4, *capacity);
3576 while (new_capacity < count && new_capacity <= max_capacity / 2)
3577 new_capacity *= 2;
3578 if (new_capacity < count)
3579 new_capacity = max_capacity;
3581 if (!(new_elements = realloc(*elements, new_capacity * size)))
3582 return;
3584 *elements = new_elements;
3585 *capacity = new_capacity;
3588 static void opentype_cmap_read_table(const struct dwrite_fonttable *table, UINT16 cmap_index, UINT32 *count,
3589 size_t *capacity, DWRITE_UNICODE_RANGE **ranges)
3591 const BYTE *tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
3592 struct cmap_encoding_record *record;
3593 DWORD table_offset;
3594 WORD format;
3595 int j;
3597 record = (struct cmap_encoding_record *)(tables + cmap_index * sizeof(*record));
3599 if (!(table_offset = table_read_be_dword(table, record, FIELD_OFFSET(struct cmap_encoding_record, offset))))
3600 return;
3602 format = table_read_be_word(table, NULL, table_offset);
3603 switch (format)
3605 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
3607 UINT16 segment_count = table_read_be_word(table, NULL, table_offset +
3608 FIELD_OFFSET(struct cmap_segmented_mapping_0, segCountX2)) / 2;
3609 DWORD start_code_offset = table_offset + sizeof(struct cmap_segmented_mapping_0) +
3610 sizeof(WORD) * segment_count;
3612 for (j = 0; j < segment_count; ++j) {
3613 WORD endcode = table_read_be_word(table, NULL, table_offset +
3614 FIELD_OFFSET(struct cmap_segmented_mapping_0, endCode) + j * sizeof(WORD));
3615 WORD first;
3617 if (endcode == 0xffff)
3618 break;
3620 first = table_read_be_word(table, NULL, start_code_offset + j * sizeof(WORD));
3622 array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
3623 (*ranges)[*count].first = first;
3624 (*ranges)[*count].last = endcode;
3625 (*count)++;
3627 break;
3629 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
3631 DWORD num_groups = table_read_be_dword(table, NULL, table_offset +
3632 FIELD_OFFSET(struct cmap_segmented_coverage, nGroups));
3634 for (j = 0; j < num_groups; ++j) {
3635 DWORD group_offset = table_offset + FIELD_OFFSET(struct cmap_segmented_coverage, groups) +
3636 j * sizeof(struct cmap_segmented_coverage_group);
3637 DWORD first = table_read_be_dword(table, NULL, group_offset +
3638 FIELD_OFFSET(struct cmap_segmented_coverage_group, startCharCode));
3639 DWORD last = table_read_be_dword(table, NULL, group_offset +
3640 FIELD_OFFSET(struct cmap_segmented_coverage_group, endCharCode));
3642 array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
3643 (*ranges)[*count].first = first;
3644 (*ranges)[*count].last = last;
3645 (*count)++;
3647 break;
3649 default:
3650 ok(0, "%u table format %#x unhandled.\n", cmap_index, format);
3654 static UINT32 opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *table, DWRITE_UNICODE_RANGE **ranges)
3656 int index_full = -1, index_bmp = -1;
3657 unsigned int i, count = 0;
3658 size_t capacity = 0;
3659 const BYTE *tables;
3660 WORD num_tables;
3662 *ranges = NULL;
3664 num_tables = table_read_be_word(table, 0, FIELD_OFFSET(struct cmap_header, num_tables));
3665 tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
3667 for (i = 0; i < num_tables; ++i)
3669 struct cmap_encoding_record *record = (struct cmap_encoding_record *)(tables + i * sizeof(*record));
3670 WORD platform, encoding;
3672 platform = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, platformID));
3673 encoding = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, encodingID));
3675 if (platform == OPENTYPE_CMAP_TABLE_PLATFORM_WIN)
3677 if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL)
3679 index_full = i;
3680 break;
3682 else if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP)
3683 index_bmp = i;
3687 if (index_full != -1)
3688 opentype_cmap_read_table(table, index_full, &count, &capacity, ranges);
3689 else if (index_bmp != -1)
3690 opentype_cmap_read_table(table, index_bmp, &count, &capacity, ranges);
3692 return count;
3695 static UINT32 fontface_get_expected_unicode_ranges(IDWriteFontFace1 *fontface, DWRITE_UNICODE_RANGE **out)
3697 struct dwrite_fonttable cmap;
3698 DWRITE_UNICODE_RANGE *ranges;
3699 UINT32 i, j, count;
3700 BOOL exists;
3701 HRESULT hr;
3703 *out = NULL;
3705 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_CMAP_TAG, (const void **)&cmap.data,
3706 &cmap.size, &cmap.context, &exists);
3707 if (FAILED(hr) || !exists)
3708 return 0;
3710 count = opentype_cmap_get_unicode_ranges(&cmap, &ranges);
3711 IDWriteFontFace1_ReleaseFontTable(fontface, cmap.context);
3713 *out = malloc(count * sizeof(**out));
3715 /* Eliminate duplicates and merge ranges together. */
3716 for (i = 0, j = 0; i < count; ++i) {
3717 if (j) {
3718 DWRITE_UNICODE_RANGE *prev = &(*out)[j-1];
3719 /* Merge adjacent ranges. */
3720 if (ranges[i].first == prev->last + 1) {
3721 prev->last = ranges[i].last;
3722 continue;
3725 (*out)[j++] = ranges[i];
3728 free(ranges);
3730 return j;
3733 static void test_GetUnicodeRanges(void)
3735 IDWriteFontCollection *syscollection;
3736 DWRITE_UNICODE_RANGE *ranges, r;
3737 IDWriteFontFile *ffile = NULL;
3738 IDWriteFontFace1 *fontface1;
3739 IDWriteFontFace *fontface;
3740 IDWriteFactory *factory;
3741 UINT32 count, i;
3742 HRESULT hr;
3743 HRSRC font;
3744 ULONG ref;
3746 factory = create_factory();
3748 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3749 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3751 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3752 ok(font != NULL, "Failed to find font resource\n");
3754 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile);
3755 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3757 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3758 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3759 IDWriteFontFile_Release(ffile);
3761 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3762 IDWriteFontFace_Release(fontface);
3763 if (hr != S_OK) {
3764 win_skip("GetUnicodeRanges() is not supported.\n");
3765 IDWriteFactory_Release(factory);
3766 return;
3769 count = 0;
3770 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
3771 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3772 ok(count > 0, "got %u\n", count);
3774 count = 1;
3775 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count);
3776 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3777 ok(count == 0, "got %u\n", count);
3779 count = 0;
3780 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count);
3781 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3782 ok(count > 1, "got %u\n", count);
3784 ranges = malloc(count*sizeof(DWRITE_UNICODE_RANGE));
3785 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
3786 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3788 ranges[0].first = ranges[0].last = 0;
3789 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count);
3790 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3791 ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last);
3793 free(ranges);
3795 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3796 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3798 IDWriteFontFace1_Release(fontface1);
3800 if (strcmp(winetest_platform, "wine")) {
3802 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
3803 ok(hr == S_OK, "Failed to get system collection, hr %#lx.\n", hr);
3805 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
3807 for (i = 0; i < count; i++) {
3808 WCHAR familynameW[256], facenameW[128];
3809 IDWriteLocalizedStrings *names;
3810 IDWriteFontFamily *family;
3811 UINT32 j, k, fontcount;
3812 IDWriteFont *font;
3814 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
3815 ok(hr == S_OK, "Failed to get font family, hr %#lx.\n", hr);
3817 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
3818 ok(hr == S_OK, "Failed to get family names, hr %#lx.\n", hr);
3820 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
3821 IDWriteLocalizedStrings_Release(names);
3823 fontcount = IDWriteFontFamily_GetFontCount(family);
3824 for (j = 0; j < fontcount; j++) {
3825 DWRITE_UNICODE_RANGE *expected_ranges = NULL;
3826 UINT32 range_count, expected_count;
3828 hr = IDWriteFontFamily_GetFont(family, j, &font);
3829 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
3831 hr = IDWriteFont_CreateFontFace(font, &fontface);
3832 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
3834 hr = IDWriteFont_GetFaceNames(font, &names);
3835 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
3836 IDWriteFont_Release(font);
3838 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
3840 IDWriteLocalizedStrings_Release(names);
3842 if (IDWriteFontFace_IsSymbolFont(fontface))
3844 static int once;
3845 if (!once++)
3846 skip("GetUnicodeRanges() test does not support symbol fonts.\n");
3847 IDWriteFontFace_Release(fontface);
3848 continue;
3851 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
3853 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &range_count);
3854 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3856 ranges = malloc(range_count * sizeof(*ranges));
3858 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, range_count, ranges, &range_count);
3859 ok(hr == S_OK, "Failed to get ranges, hr %#lx.\n", hr);
3861 expected_count = fontface_get_expected_unicode_ranges(fontface1, &expected_ranges);
3862 ok(expected_count == range_count, "%s - %s: unexpected range count %u, expected %u.\n",
3863 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), range_count, expected_count);
3865 if (expected_count == range_count) {
3866 if (memcmp(expected_ranges, ranges, expected_count * sizeof(*ranges))) {
3867 for (k = 0; k < expected_count; ++k) {
3868 BOOL failed = memcmp(&expected_ranges[k], &ranges[k], sizeof(*ranges));
3869 ok(!failed, "%u: %s - %s mismatching range [%#x, %#x] vs [%#x, %#x].\n", k,
3870 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), ranges[k].first, ranges[k].last,
3871 expected_ranges[k].first, expected_ranges[k].last);
3872 if (failed)
3873 break;
3878 free(expected_ranges);
3879 free(ranges);
3881 IDWriteFontFace1_Release(fontface1);
3882 IDWriteFontFace_Release(fontface);
3885 IDWriteFontFamily_Release(family);
3888 IDWriteFontCollection_Release(syscollection);
3890 ref = IDWriteFactory_Release(factory);
3891 ok(ref == 0, "factory not released, %lu\n", ref);
3894 static void test_GetFontFromFontFace(void)
3896 IDWriteFontFace *fontface, *fontface2;
3897 IDWriteFontCollection *collection;
3898 IDWriteFont *font, *font2, *font3;
3899 IDWriteFontFamily *family;
3900 IDWriteFactory *factory;
3901 IDWriteFontFile *file;
3902 WCHAR *path;
3903 HRESULT hr;
3904 ULONG ref;
3906 factory = create_factory();
3908 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3909 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3911 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3912 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3914 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3915 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3916 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3918 hr = IDWriteFont_CreateFontFace(font, &fontface);
3919 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3921 font2 = NULL;
3922 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
3923 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3924 ok(font2 != font, "got %p, %p\n", font2, font);
3926 font3 = NULL;
3927 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3928 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3929 ok(font3 != font && font3 != font2, "got %p, %p, %p\n", font3, font2, font);
3931 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
3932 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3933 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3934 IDWriteFontFace_Release(fontface2);
3936 hr = IDWriteFont_CreateFontFace(font3, &fontface2);
3937 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3938 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3939 IDWriteFontFace_Release(fontface2);
3940 IDWriteFontFace_Release(fontface);
3941 IDWriteFont_Release(font3);
3942 IDWriteFactory_Release(factory);
3944 /* fontface that wasn't created from this collection */
3945 factory = create_factory();
3946 path = create_testfontfile(test_fontfile);
3948 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3949 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
3951 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3952 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3953 IDWriteFontFile_Release(file);
3955 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3956 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
3957 ok(font3 == NULL, "got %p\n", font3);
3958 IDWriteFontFace_Release(fontface);
3960 IDWriteFont_Release(font);
3961 IDWriteFont_Release(font2);
3962 IDWriteFontFamily_Release(family);
3963 IDWriteFontCollection_Release(collection);
3964 ref = IDWriteFactory_Release(factory);
3965 ok(ref == 0, "factory not released, %lu\n", ref);
3966 DELETE_FONTFILE(path);
3969 static void test_GetFirstMatchingFont(void)
3971 DWRITE_FONT_SIMULATIONS simulations;
3972 IDWriteFontCollection *collection;
3973 IDWriteFontFamily *family;
3974 IDWriteFont *font, *font2;
3975 IDWriteFactory *factory;
3976 HRESULT hr;
3977 ULONG ref;
3979 factory = create_factory();
3981 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3982 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3984 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3985 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3987 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3988 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3989 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3991 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3992 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
3993 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3994 ok(font != font2, "got %p, %p\n", font, font2);
3995 IDWriteFont_Release(font);
3996 IDWriteFont_Release(font2);
3998 /* out-of-range font props are allowed */
3999 hr = IDWriteFontFamily_GetFirstMatchingFont(family, 1000, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4000 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4001 IDWriteFont_Release(font);
4003 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, 10, DWRITE_FONT_STYLE_NORMAL, &font);
4004 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4005 IDWriteFont_Release(font);
4007 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
4008 10, &font);
4009 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4010 IDWriteFont_Release(font);
4012 IDWriteFontFamily_Release(family);
4014 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
4015 simulations = IDWriteFont_GetSimulations(font);
4016 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "%d\n", simulations);
4017 IDWriteFont_Release(font);
4019 IDWriteFontCollection_Release(collection);
4020 ref = IDWriteFactory_Release(factory);
4021 ok(ref == 0, "factory not released, %lu\n", ref);
4024 static void test_GetMatchingFonts(void)
4026 IDWriteFontCollection *collection;
4027 IDWriteFontFamily *family;
4028 IDWriteFactory *factory;
4029 IDWriteFontList *fontlist, *fontlist2;
4030 IDWriteFontList1 *fontlist1;
4031 IDWriteFontList2 *fontlist3;
4032 HRESULT hr;
4033 ULONG ref;
4035 factory = create_factory();
4037 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4038 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4040 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4041 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4043 /* out-of-range font props are allowed */
4044 hr = IDWriteFontFamily_GetMatchingFonts(family, 1000, DWRITE_FONT_STRETCH_NORMAL,
4045 DWRITE_FONT_STYLE_NORMAL, &fontlist);
4046 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4047 IDWriteFontList_Release(fontlist);
4049 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, 10,
4050 DWRITE_FONT_STYLE_NORMAL, &fontlist);
4051 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4052 IDWriteFontList_Release(fontlist);
4054 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
4055 10, &fontlist);
4056 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4057 IDWriteFontList_Release(fontlist);
4059 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
4060 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
4061 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4063 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
4064 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
4065 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4066 ok(fontlist != fontlist2, "got %p, %p\n", fontlist, fontlist2);
4067 IDWriteFontList_Release(fontlist2);
4069 hr = IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList1, (void**)&fontlist1);
4070 if (hr == S_OK) {
4071 IDWriteFontFaceReference *ref, *ref1;
4072 IDWriteFont3 *font;
4073 UINT32 count;
4075 count = IDWriteFontList1_GetFontCount(fontlist1);
4076 ok(count > 0, "got %u\n", count);
4078 font = (void*)0xdeadbeef;
4079 hr = IDWriteFontList1_GetFont(fontlist1, ~0u, &font);
4080 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4081 ok(font == NULL, "got %p\n", font);
4083 font = (void*)0xdeadbeef;
4084 hr = IDWriteFontList1_GetFont(fontlist1, count, &font);
4085 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4086 ok(font == NULL, "got %p\n", font);
4088 hr = IDWriteFontList1_GetFont(fontlist1, 0, &font);
4089 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4090 IDWriteFont3_Release(font);
4092 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref);
4093 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4095 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref1);
4096 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4097 ok(ref != ref1, "got %p, %p\n", ref, ref1);
4099 IDWriteFontFaceReference_Release(ref1);
4100 IDWriteFontFaceReference_Release(ref);
4101 IDWriteFontList1_Release(fontlist1);
4103 else
4104 win_skip("IDWriteFontList1 is not supported.\n");
4106 if (SUCCEEDED(IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList2, (void **)&fontlist3)))
4108 IDWriteFontSet1 *fontset, *fontset2;
4110 hr = IDWriteFontList2_GetFontSet(fontlist3, &fontset);
4111 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4113 hr = IDWriteFontList2_GetFontSet(fontlist3, &fontset2);
4114 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4115 ok(fontset != fontset2, "Unexpected instance.\n");
4117 IDWriteFontSet1_Release(fontset2);
4118 IDWriteFontSet1_Release(fontset);
4120 IDWriteFontList2_Release(fontlist3);
4122 else
4123 win_skip("IDWriteFontList2 is not supported.\n");
4125 IDWriteFontList_Release(fontlist);
4126 IDWriteFontFamily_Release(family);
4128 IDWriteFontCollection_Release(collection);
4129 ref = IDWriteFactory_Release(factory);
4130 ok(ref == 0, "factory not released, %lu\n", ref);
4133 static void test_GetInformationalStrings(void)
4135 IDWriteLocalizedStrings *strings, *strings2;
4136 IDWriteFontCollection *collection;
4137 IDWriteFontFace3 *fontface3;
4138 IDWriteFontFace *fontface;
4139 IDWriteFontFamily *family;
4140 IDWriteFactory *factory;
4141 IDWriteFont *font;
4142 BOOL exists;
4143 HRESULT hr;
4144 ULONG ref;
4146 factory = create_factory();
4148 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4149 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4151 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4152 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4154 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4155 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4156 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4158 exists = TRUE;
4159 strings = (void *)0xdeadbeef;
4160 hr = IDWriteFont_GetInformationalStrings(font, 0xdead, &strings, &exists);
4161 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4162 ok(exists == FALSE, "got %d\n", exists);
4163 ok(strings == NULL, "got %p\n", strings);
4165 exists = TRUE;
4166 strings = NULL;
4167 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists);
4168 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4169 ok(exists == FALSE, "got %d\n", exists);
4171 exists = FALSE;
4172 strings = NULL;
4173 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
4174 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4175 ok(exists == TRUE, "got %d\n", exists);
4177 /* strings instance is not reused */
4178 strings2 = NULL;
4179 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings2, &exists);
4180 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4181 ok(strings2 != strings, "got %p, %p\n", strings2, strings);
4183 IDWriteLocalizedStrings_Release(strings);
4184 IDWriteLocalizedStrings_Release(strings2);
4186 hr = IDWriteFont_CreateFontFace(font, &fontface);
4187 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
4189 if (SUCCEEDED(hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
4191 hr = IDWriteFontFace3_GetInformationalStrings(fontface3, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES,
4192 &strings, &exists);
4193 ok(hr == S_OK, "Failed to get info strings, hr %#lx.\n", hr);
4194 IDWriteLocalizedStrings_Release(strings);
4196 IDWriteFontFace3_Release(fontface3);
4198 else
4199 win_skip("IDWriteFontFace3::GetInformationalStrings() is not supported.\n");
4201 IDWriteFontFace_Release(fontface);
4203 IDWriteFont_Release(font);
4204 IDWriteFontFamily_Release(family);
4205 IDWriteFontCollection_Release(collection);
4206 ref = IDWriteFactory_Release(factory);
4207 ok(ref == 0, "factory not released, %lu\n", ref);
4210 static void test_GetGdiInterop(void)
4212 IDWriteGdiInterop *interop, *interop2;
4213 IDWriteFactory *factory, *factory2;
4214 IDWriteFont *font;
4215 LOGFONTW logfont;
4216 HRESULT hr;
4217 ULONG ref;
4219 factory = create_factory();
4221 interop = NULL;
4222 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4223 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4225 interop2 = NULL;
4226 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
4227 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4228 ok(interop == interop2, "got %p, %p\n", interop, interop2);
4229 IDWriteGdiInterop_Release(interop2);
4231 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory2);
4232 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4234 /* each factory gets its own interop */
4235 interop2 = NULL;
4236 hr = IDWriteFactory_GetGdiInterop(factory2, &interop2);
4237 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4238 ok(interop != interop2, "got %p, %p\n", interop, interop2);
4240 /* release factory - interop still works */
4241 IDWriteFactory_Release(factory2);
4243 memset(&logfont, 0, sizeof(logfont));
4244 logfont.lfHeight = 12;
4245 logfont.lfWidth = 12;
4246 logfont.lfWeight = FW_NORMAL;
4247 logfont.lfItalic = 1;
4248 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4250 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop2, &logfont, &font);
4251 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4252 IDWriteFont_Release(font);
4254 IDWriteGdiInterop_Release(interop2);
4255 IDWriteGdiInterop_Release(interop);
4256 ref = IDWriteFactory_Release(factory);
4257 ok(ref == 0, "factory not released, %lu\n", ref);
4260 static void *map_font_file(const WCHAR *filename, DWORD *file_size)
4262 HANDLE file, mapping;
4263 void *ptr;
4265 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4266 if (file == INVALID_HANDLE_VALUE) return NULL;
4268 *file_size = GetFileSize(file, NULL);
4270 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4271 if (!mapping)
4273 CloseHandle(file);
4274 return NULL;
4277 ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4279 CloseHandle(file);
4280 CloseHandle(mapping);
4281 return ptr;
4284 struct font_realization_info
4286 DWORD size;
4287 DWORD flags;
4288 DWORD cache_num;
4289 DWORD instance_id;
4290 DWORD file_count;
4291 WORD face_index;
4292 WORD simulations;
4295 static void test_CreateFontFaceFromHdc(void)
4297 IDWriteFontFileStream *stream, *stream2;
4298 void *font_data, *fragment_context;
4299 struct font_realization_info info;
4300 const void *refkey, *fragment;
4301 IDWriteFontFileLoader *loader;
4302 DWORD data_size, num_fonts;
4303 IDWriteGdiInterop *interop;
4304 IDWriteFontFace *fontface;
4305 IDWriteFactory *factory;
4306 UINT64 size, writetime;
4307 IDWriteFontFile *file;
4308 HFONT hfont, oldhfont;
4309 UINT32 count, dummy;
4310 LOGFONTW logfont;
4311 HANDLE resource;
4312 IUnknown *unk;
4313 LOGFONTA lf;
4314 WCHAR *path;
4315 HRESULT hr;
4316 ULONG ref;
4317 BOOL ret;
4318 HDC hdc;
4320 factory = create_factory();
4322 pGetFontRealizationInfo = (void *)GetProcAddress(GetModuleHandleA("gdi32"), "GetFontRealizationInfo");
4324 interop = NULL;
4325 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4326 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4328 /* Invalid HDC. */
4329 fontface = (void*)0xdeadbeef;
4330 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, NULL, &fontface);
4331 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
4332 ok(fontface == NULL, "got %p\n", fontface);
4334 fontface = (void *)0xdeadbeef;
4335 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, (HDC)0xdeadbeef, &fontface);
4336 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4337 ok(fontface == NULL, "got %p\n", fontface);
4339 memset(&logfont, 0, sizeof(logfont));
4340 logfont.lfHeight = 12;
4341 logfont.lfWidth = 12;
4342 logfont.lfWeight = FW_NORMAL;
4343 logfont.lfItalic = 1;
4344 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4346 hfont = CreateFontIndirectW(&logfont);
4347 hdc = CreateCompatibleDC(0);
4348 oldhfont = SelectObject(hdc, hfont);
4350 fontface = NULL;
4351 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4352 ok(hr == S_OK, "Failed to create font face, hr %#lx.\n", hr);
4354 count = 1;
4355 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
4356 ok(hr == S_OK, "Failed to get font files, hr %#lx.\n", hr);
4358 hr = IDWriteFontFile_GetLoader(file, &loader);
4359 ok(hr == S_OK, "Failed to get file loader, hr %#lx.\n", hr);
4361 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void **)&unk);
4362 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Vista */, "Expected local loader, hr %#lx.\n", hr);
4363 if (unk)
4364 IUnknown_Release(unk);
4366 IDWriteFontFileLoader_Release(loader);
4367 IDWriteFontFile_Release(file);
4369 IDWriteFontFace_Release(fontface);
4370 DeleteObject(SelectObject(hdc, oldhfont));
4372 /* Select bitmap font MS Sans Serif, format that's not supported by DirectWrite. */
4373 memset(&lf, 0, sizeof(lf));
4374 lf.lfHeight = -12;
4375 strcpy(lf.lfFaceName, "MS Sans Serif");
4377 hfont = CreateFontIndirectA(&lf);
4378 oldhfont = SelectObject(hdc, hfont);
4380 fontface = (void *)0xdeadbeef;
4381 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4382 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* Vista */, "Unexpected hr %#lx.\n", hr);
4383 ok(fontface == NULL, "got %p\n", fontface);
4385 DeleteObject(SelectObject(hdc, oldhfont));
4387 /* Memory resource font */
4388 path = create_testfontfile(test_fontfile);
4390 data_size = 0;
4391 font_data = map_font_file(path, &data_size);
4393 num_fonts = 0;
4394 resource = AddFontMemResourceEx(font_data, data_size, NULL, &num_fonts);
4395 ok(resource != NULL, "Failed to add memory resource font, %ld.\n", GetLastError());
4396 ok(num_fonts == 1, "Unexpected number of fonts.\n");
4398 memset(&lf, 0, sizeof(lf));
4399 lf.lfHeight = -12;
4400 strcpy(lf.lfFaceName, "wine_test");
4402 hfont = CreateFontIndirectA(&lf);
4403 ok(hfont != NULL, "Failed to create a font.\n");
4404 oldhfont = SelectObject(hdc, hfont);
4406 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4407 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
4409 count = 1;
4410 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
4411 ok(hr == S_OK, "Failed to get font files, hr %#lx.\n", hr);
4413 hr = IDWriteFontFile_GetLoader(file, &loader);
4414 ok(hr == S_OK, "Failed to get file loader, hr %#lx.\n", hr);
4416 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
4417 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
4419 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&unk);
4420 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
4422 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void **)&unk);
4423 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
4425 count = 0;
4426 hr = IDWriteFontFile_GetReferenceKey(file, &refkey, &count);
4427 ok(hr == S_OK, "Failed to get ref key, hr %#lx.\n", hr);
4428 ok(count > 0, "Unexpected key length %u.\n", count);
4430 if (pGetFontRealizationInfo)
4432 info.size = sizeof(info);
4433 ret = pGetFontRealizationInfo(hdc, &info);
4434 ok(ret, "Failed to get realization info.\n");
4435 ok(count == sizeof(info.instance_id), "Unexpected key size.\n");
4436 ok(*(DWORD *)refkey == info.instance_id, "Unexpected stream key.\n");
4438 else
4439 win_skip("GetFontRealizationInfo() is not available.\n");
4441 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refkey, count, &stream);
4442 ok(hr == S_OK, "Failed to create file stream, hr %#lx.\n", hr);
4444 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refkey, count, &stream2);
4445 ok(hr == S_OK, "Failed to create file stream, hr %#lx.\n", hr);
4446 ok(stream2 != stream, "Unexpected stream instance.\n");
4447 IDWriteFontFileStream_Release(stream2);
4449 dummy = 1;
4450 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, &dummy, count, &stream2);
4451 ok(hr == S_OK, "Failed to create file stream, hr %#lx.\n", hr);
4453 writetime = 1;
4454 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
4455 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
4456 ok(writetime == 1, "Unexpected write time.\n");
4458 IDWriteFontFileStream_Release(stream2);
4460 hr = IDWriteFontFileStream_GetFileSize(stream, &size);
4461 ok(hr == S_OK, "Failed to get stream size, hr %#lx.\n", hr);
4462 ok(size == data_size, "Unexpected stream size.\n");
4464 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4465 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
4467 fragment_context = NULL;
4468 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, size, &fragment_context);
4469 ok(hr == S_OK, "Failed to read fragment, hr %#lx.\n", hr);
4470 ok(fragment_context != NULL, "Unexpected context %p.\n", fragment_context);
4471 ok(fragment == fragment_context, "Unexpected data pointer %p, context %p.\n", fragment, fragment_context);
4472 IDWriteFontFileStream_ReleaseFileFragment(stream, fragment_context);
4474 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, size + 1, &fragment_context);
4475 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
4477 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, size - 1, size / 2, &fragment_context);
4478 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
4480 IDWriteFontFileStream_Release(stream);
4482 IDWriteFontFileLoader_Release(loader);
4483 IDWriteFontFile_Release(file);
4485 IDWriteFontFace_Release(fontface);
4487 ret = RemoveFontMemResourceEx(resource);
4488 ok(ret, "Failed to remove memory resource font, %ld.\n", GetLastError());
4490 UnmapViewOfFile(font_data);
4492 DELETE_FONTFILE(path);
4494 DeleteObject(SelectObject(hdc, oldhfont));
4495 DeleteDC(hdc);
4496 IDWriteGdiInterop_Release(interop);
4497 ref = IDWriteFactory_Release(factory);
4498 ok(ref == 0, "factory not released, %lu\n", ref);
4501 static void test_GetSimulations(void)
4503 DWRITE_FONT_SIMULATIONS simulations;
4504 IDWriteGdiInterop *interop;
4505 IDWriteFontFace *fontface;
4506 IDWriteFactory *factory;
4507 IDWriteFont *font;
4508 LOGFONTW logfont;
4509 HRESULT hr;
4510 ULONG ref;
4512 factory = create_factory();
4514 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4515 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4517 memset(&logfont, 0, sizeof(logfont));
4518 logfont.lfHeight = 12;
4519 logfont.lfWidth = 12;
4520 logfont.lfWeight = FW_NORMAL;
4521 logfont.lfItalic = 1;
4522 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4524 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4525 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4527 simulations = IDWriteFont_GetSimulations(font);
4528 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
4529 hr = IDWriteFont_CreateFontFace(font, &fontface);
4530 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4531 simulations = IDWriteFontFace_GetSimulations(fontface);
4532 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
4533 IDWriteFontFace_Release(fontface);
4534 IDWriteFont_Release(font);
4536 memset(&logfont, 0, sizeof(logfont));
4537 logfont.lfHeight = 12;
4538 logfont.lfWidth = 12;
4539 logfont.lfWeight = FW_NORMAL;
4540 logfont.lfItalic = 0;
4541 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4543 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4544 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4546 simulations = IDWriteFont_GetSimulations(font);
4547 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
4548 hr = IDWriteFont_CreateFontFace(font, &fontface);
4549 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4550 simulations = IDWriteFontFace_GetSimulations(fontface);
4551 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
4552 IDWriteFontFace_Release(fontface);
4553 IDWriteFont_Release(font);
4555 IDWriteGdiInterop_Release(interop);
4556 ref = IDWriteFactory_Release(factory);
4557 ok(ref == 0, "factory not released, %lu\n", ref);
4560 static void test_GetFaceNames(void)
4562 IDWriteLocalizedStrings *strings, *strings2, *strings3;
4563 IDWriteFontFace3 *fontface3;
4564 IDWriteGdiInterop *interop;
4565 IDWriteFontFace *fontface;
4566 IDWriteFactory *factory;
4567 UINT32 count, index;
4568 IDWriteFont *font;
4569 LOGFONTW logfont;
4570 WCHAR buffW[255];
4571 BOOL exists;
4572 HRESULT hr;
4573 ULONG ref;
4575 factory = create_factory();
4577 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4578 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4580 memset(&logfont, 0, sizeof(logfont));
4581 logfont.lfHeight = 12;
4582 logfont.lfWidth = 12;
4583 logfont.lfWeight = FW_NORMAL;
4584 logfont.lfItalic = 1;
4585 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4587 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4588 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4590 hr = IDWriteFont_GetFaceNames(font, &strings);
4591 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4593 hr = IDWriteFont_GetFaceNames(font, &strings2);
4594 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4595 ok(strings != strings2, "got %p, %p\n", strings2, strings);
4596 IDWriteLocalizedStrings_Release(strings2);
4598 count = IDWriteLocalizedStrings_GetCount(strings);
4599 ok(count == 1, "got %d\n", count);
4601 index = 1;
4602 exists = FALSE;
4603 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-Us", &index, &exists);
4604 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4605 ok(index == 0 && exists, "got %d, %d\n", index, exists);
4607 count = 0;
4608 hr = IDWriteLocalizedStrings_GetLocaleNameLength(strings, 1, &count);
4609 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4610 ok(count == ~0, "got %d\n", count);
4612 /* for simulated faces names are also simulated */
4613 buffW[0] = 0;
4614 hr = IDWriteLocalizedStrings_GetLocaleName(strings, 0, buffW, ARRAY_SIZE(buffW));
4615 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4616 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
4618 buffW[0] = 0;
4619 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
4620 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4621 ok(!lstrcmpW(buffW, L"Oblique"), "got %s\n", wine_dbgstr_w(buffW));
4622 IDWriteLocalizedStrings_Release(strings);
4624 hr = IDWriteFont_CreateFontFace(font, &fontface);
4625 ok(hr == S_OK, "Failed to create a font face, hr %#lx.\n", hr);
4627 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
4629 hr = IDWriteFontFace3_GetFaceNames(fontface3, &strings2);
4630 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
4632 hr = IDWriteFontFace3_GetFaceNames(fontface3, &strings3);
4633 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
4634 ok(strings2 != strings3, "Unexpected instance.\n");
4635 IDWriteLocalizedStrings_Release(strings3);
4637 buffW[0] = 0;
4638 hr = IDWriteLocalizedStrings_GetString(strings2, 0, buffW, ARRAY_SIZE(buffW));
4639 ok(hr == S_OK, "Failed to get a string, hr %#lx.\n", hr);
4640 ok(!lstrcmpW(buffW, L"Oblique"), "Unexpected name %s.\n", wine_dbgstr_w(buffW));
4641 IDWriteLocalizedStrings_Release(strings2);
4643 IDWriteFontFace3_Release(fontface3);
4645 else
4646 win_skip("GetFaceNames() is not supported.\n");
4648 IDWriteFontFace_Release(fontface);
4650 IDWriteFont_Release(font);
4651 IDWriteGdiInterop_Release(interop);
4652 ref = IDWriteFactory_Release(factory);
4653 ok(ref == 0, "factory not released, %lu\n", ref);
4656 struct local_refkey
4658 FILETIME writetime;
4659 WCHAR name[1];
4662 static void test_TryGetFontTable(void)
4664 IDWriteLocalFontFileLoader *localloader;
4665 WIN32_FILE_ATTRIBUTE_DATA info;
4666 const struct local_refkey *key;
4667 IDWriteFontFileLoader *loader;
4668 const void *table, *table2;
4669 IDWriteFontFace *fontface;
4670 void *context, *context2;
4671 IDWriteFactory *factory;
4672 IDWriteFontFile *file;
4673 WCHAR buffW[MAX_PATH];
4674 BOOL exists, ret;
4675 UINT32 size, len;
4676 WCHAR *path;
4677 HRESULT hr;
4678 ULONG ref;
4680 path = create_testfontfile(test_fontfile);
4682 factory = create_factory();
4684 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4685 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4687 key = NULL;
4688 size = 0;
4689 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4690 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4691 ok(size != 0, "got %u\n", size);
4693 ret = GetFileAttributesExW(path, GetFileExInfoStandard, &info);
4694 ok(ret, "got %d\n", ret);
4695 ok(!memcmp(&info.ftLastWriteTime, &key->writetime, sizeof(key->writetime)), "got wrong write time\n");
4697 hr = IDWriteFontFile_GetLoader(file, &loader);
4698 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4699 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4700 IDWriteFontFileLoader_Release(loader);
4702 hr = IDWriteLocalFontFileLoader_GetFilePathLengthFromKey(localloader, key, size, &len);
4703 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4704 ok(lstrlenW(key->name) == len, "path length %d\n", len);
4706 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, size, buffW, ARRAY_SIZE(buffW));
4707 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4708 ok(!lstrcmpW(buffW, key->name), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(key->name));
4709 IDWriteLocalFontFileLoader_Release(localloader);
4711 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, 0, &fontface);
4712 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4714 exists = FALSE;
4715 context = (void*)0xdeadbeef;
4716 table = NULL;
4717 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table, &size, &context, &exists);
4718 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4719 ok(exists == TRUE, "got %d\n", exists);
4720 ok(context == NULL && table != NULL, "cmap: context %p, table %p\n", context, table);
4722 exists = FALSE;
4723 context2 = (void*)0xdeadbeef;
4724 table2 = NULL;
4725 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table2, &size, &context2, &exists);
4726 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4727 ok(exists == TRUE, "got %d\n", exists);
4728 ok(context2 == context && table2 == table, "cmap: context2 %p, table2 %p\n", context2, table2);
4730 IDWriteFontFace_ReleaseFontTable(fontface, context2);
4731 IDWriteFontFace_ReleaseFontTable(fontface, context);
4733 /* table does not exist */
4734 exists = TRUE;
4735 context = (void*)0xdeadbeef;
4736 table = (void*)0xdeadbeef;
4737 hr = IDWriteFontFace_TryGetFontTable(fontface, 0xabababab, &table, &size, &context, &exists);
4738 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4739 ok(exists == FALSE, "got %d\n", exists);
4740 ok(context == NULL && table == NULL, "got context %p, table pointer %p\n", context, table);
4742 IDWriteFontFace_Release(fontface);
4743 IDWriteFontFile_Release(file);
4744 ref = IDWriteFactory_Release(factory);
4745 ok(ref == 0, "factory not released, %lu\n", ref);
4746 DELETE_FONTFILE(path);
4749 static void test_ConvertFontToLOGFONT(void)
4751 IDWriteFactory *factory, *factory2;
4752 IDWriteFontCollection *collection;
4753 IDWriteGdiInterop *interop;
4754 IDWriteFontFamily *family;
4755 IDWriteFont *font;
4756 LOGFONTW logfont;
4757 UINT32 i, count;
4758 BOOL system;
4759 HRESULT hr;
4760 ULONG ref;
4762 factory = create_factory();
4763 factory2 = create_factory();
4765 interop = NULL;
4766 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4767 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4769 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection, FALSE);
4770 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4772 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4773 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4775 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4776 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4777 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4779 if (0) { /* crashes on native */
4780 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, NULL, NULL);
4781 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, NULL);
4782 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, NULL, &system);
4785 memset(&logfont, 0xcc, sizeof(logfont));
4786 system = TRUE;
4787 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, &system);
4788 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
4789 ok(!system, "got %d\n", system);
4790 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
4792 count = IDWriteFontCollection_GetFontFamilyCount(collection);
4793 for (i = 0; i < count; i++) {
4794 WCHAR nameW[128], familynameW[64], facenameW[64];
4795 IDWriteLocalizedStrings *names;
4796 DWRITE_FONT_SIMULATIONS sim;
4797 IDWriteFontFamily *family;
4798 UINT32 font_count, j;
4799 IDWriteFont *font;
4800 LOGFONTW lf;
4802 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
4803 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4805 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
4806 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4808 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
4809 IDWriteLocalizedStrings_Release(names);
4811 font_count = IDWriteFontFamily_GetFontCount(family);
4813 for (j = 0; j < font_count; ++j)
4815 IDWriteFontFace *fontface;
4816 BOOL has_variations;
4818 hr = IDWriteFontFamily_GetFont(family, j, &font);
4819 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4821 hr = IDWriteFont_GetFaceNames(font, &names);
4822 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4824 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
4825 IDWriteLocalizedStrings_Release(names);
4827 lstrcpyW(nameW, familynameW);
4828 lstrcatW(nameW, L" ");
4829 lstrcatW(nameW, facenameW);
4831 hr = IDWriteFont_CreateFontFace(font, &fontface);
4832 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4834 has_variations = has_face_variations(fontface);
4835 IDWriteFontFace_Release(fontface);
4837 if (has_variations)
4839 static int once;
4840 if (!once++)
4841 skip("ConvertFontToLOGFONT() test does not support variable fonts.\n");
4842 IDWriteFont_Release(font);
4843 continue;
4846 system = FALSE;
4847 memset(&logfont, 0xcc, sizeof(logfont));
4848 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, &logfont, &system);
4849 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4850 ok(system, "got %d\n", system);
4852 sim = IDWriteFont_GetSimulations(font);
4854 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
4856 get_logfont_from_font(font, &lf);
4857 ok(logfont.lfWeight == lf.lfWeight, "Unexpected lfWeight %ld, expected lfWeight %ld, font weight %d, "
4858 "bold simulation %s.\n", logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
4859 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
4860 ok(logfont.lfItalic == lf.lfItalic, "Unexpected italic flag %d, oblique simulation %s.\n",
4861 logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
4862 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "Unexpected facename %s, expected %s.\n",
4863 wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
4865 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "Unexpected output precision %d.\n", logfont.lfOutPrecision);
4866 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "Unexpected clipping precision %d.\n", logfont.lfClipPrecision);
4867 ok(logfont.lfQuality == DEFAULT_QUALITY, "Unexpected quality %d.\n", logfont.lfQuality);
4868 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "Unexpected pitch %d.\n", logfont.lfPitchAndFamily);
4870 winetest_pop_context();
4872 IDWriteFont_Release(font);
4875 IDWriteFontFamily_Release(family);
4878 IDWriteFactory_Release(factory2);
4880 IDWriteFontCollection_Release(collection);
4881 IDWriteFontFamily_Release(family);
4882 IDWriteFont_Release(font);
4883 IDWriteGdiInterop_Release(interop);
4884 ref = IDWriteFactory_Release(factory);
4885 ok(ref == 0, "factory not released, %lu\n", ref);
4888 static void test_CreateStreamFromKey(void)
4890 IDWriteLocalFontFileLoader *localloader;
4891 IDWriteFontFileStream *stream, *stream2;
4892 IDWriteFontFileLoader *loader;
4893 IDWriteFactory *factory;
4894 IDWriteFontFile *file;
4895 UINT64 writetime;
4896 WCHAR *path;
4897 void *key;
4898 UINT32 size;
4899 HRESULT hr;
4900 ULONG ref;
4902 factory = create_factory();
4904 path = create_testfontfile(test_fontfile);
4906 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4907 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4909 key = NULL;
4910 size = 0;
4911 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4912 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4913 ok(size != 0, "got %u\n", size);
4915 hr = IDWriteFontFile_GetLoader(file, &loader);
4916 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4917 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4918 IDWriteFontFileLoader_Release(loader);
4920 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4921 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4922 EXPECT_REF(stream, 1);
4924 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2);
4925 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4926 ok(stream == stream2 || broken(stream != stream2) /* Win7 SP0 */, "got %p, %p\n", stream, stream2);
4927 if (stream == stream2)
4928 EXPECT_REF(stream, 2);
4929 IDWriteFontFileStream_Release(stream);
4930 IDWriteFontFileStream_Release(stream2);
4932 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4933 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4934 EXPECT_REF(stream, 1);
4936 writetime = 0;
4937 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4938 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4939 ok(writetime != 0, "got %s\n", wine_dbgstr_longlong(writetime));
4941 IDWriteFontFileStream_Release(stream);
4942 IDWriteFontFile_Release(file);
4944 IDWriteLocalFontFileLoader_Release(localloader);
4945 ref = IDWriteFactory_Release(factory);
4946 ok(ref == 0, "factory not released, %lu\n", ref);
4947 DELETE_FONTFILE(path);
4950 static void test_ReadFileFragment(void)
4952 IDWriteLocalFontFileLoader *localloader;
4953 IDWriteFontFileStream *stream;
4954 IDWriteFontFileLoader *loader;
4955 IDWriteFactory *factory;
4956 IDWriteFontFile *file;
4957 const void *fragment, *fragment2;
4958 void *key, *context, *context2;
4959 UINT64 filesize;
4960 UINT32 size;
4961 WCHAR *path;
4962 HRESULT hr;
4963 ULONG ref;
4965 factory = create_factory();
4967 path = create_testfontfile(test_fontfile);
4969 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4970 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4972 key = NULL;
4973 size = 0;
4974 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4975 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4976 ok(size != 0, "got %u\n", size);
4978 hr = IDWriteFontFile_GetLoader(file, &loader);
4979 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4980 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4981 IDWriteFontFileLoader_Release(loader);
4983 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4984 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4986 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
4987 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4989 /* reading past the end of the stream */
4990 fragment = (void*)0xdeadbeef;
4991 context = (void*)0xdeadbeef;
4992 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize+1, &context);
4993 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4994 ok(context == NULL, "got %p\n", context);
4995 ok(fragment == NULL, "got %p\n", fragment);
4997 fragment = (void*)0xdeadbeef;
4998 context = (void*)0xdeadbeef;
4999 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
5000 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5001 ok(context == NULL, "got %p\n", context);
5002 ok(fragment != NULL, "got %p\n", fragment);
5004 fragment2 = (void*)0xdeadbeef;
5005 context2 = (void*)0xdeadbeef;
5006 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment2, 0, filesize, &context2);
5007 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5008 ok(context2 == NULL, "got %p\n", context2);
5009 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
5011 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
5012 IDWriteFontFileStream_ReleaseFileFragment(stream, context2);
5014 /* fragment is released, try again */
5015 fragment = (void*)0xdeadbeef;
5016 context = (void*)0xdeadbeef;
5017 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
5018 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5019 ok(context == NULL, "got %p\n", context);
5020 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
5021 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
5023 IDWriteFontFile_Release(file);
5024 IDWriteFontFileStream_Release(stream);
5025 IDWriteLocalFontFileLoader_Release(localloader);
5026 ref = IDWriteFactory_Release(factory);
5027 ok(ref == 0, "factory not released, %lu\n", ref);
5028 DELETE_FONTFILE(path);
5031 static void test_GetDesignGlyphMetrics(void)
5033 DWRITE_GLYPH_METRICS metrics[2];
5034 IDWriteFontFace *fontface;
5035 IDWriteFactory *factory;
5036 IDWriteFontFile *file;
5037 UINT16 indices[2];
5038 UINT32 codepoint;
5039 WCHAR *path;
5040 HRESULT hr;
5041 ULONG ref;
5043 factory = create_factory();
5045 path = create_testfontfile(test_fontfile);
5047 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5048 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5050 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
5051 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5052 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5053 IDWriteFontFile_Release(file);
5055 codepoint = 'A';
5056 indices[0] = 0;
5057 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &indices[0]);
5058 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5059 ok(indices[0] > 0, "got %u\n", indices[0]);
5061 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 0, metrics, FALSE);
5062 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n",hr);
5064 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 1, metrics, FALSE);
5065 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n",hr);
5067 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 0, metrics, FALSE);
5068 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5070 /* missing glyphs are ignored */
5071 indices[1] = 1;
5072 memset(metrics, 0xcc, sizeof(metrics));
5073 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 2, metrics, FALSE);
5074 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5075 ok(metrics[0].advanceWidth == 1000, "got %d\n", metrics[0].advanceWidth);
5076 ok(metrics[1].advanceWidth == 0, "got %d\n", metrics[1].advanceWidth);
5078 IDWriteFontFace_Release(fontface);
5079 ref = IDWriteFactory_Release(factory);
5080 ok(ref == 0, "factory not released, %lu\n", ref);
5081 DELETE_FONTFILE(path);
5084 static BOOL get_expected_is_monospaced(IDWriteFontFace1 *fontface, const DWRITE_PANOSE *panose)
5086 BOOL exists, is_monospaced = FALSE;
5087 const TT_POST *tt_post;
5088 void *post_context;
5089 UINT32 size;
5090 HRESULT hr;
5092 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_POST_TAG, (const void **)&tt_post, &size,
5093 &post_context, &exists);
5094 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5096 if (tt_post)
5098 is_monospaced = !!tt_post->fixed_pitch;
5099 IDWriteFontFace1_ReleaseFontTable(fontface, post_context);
5102 if (!is_monospaced)
5103 is_monospaced |= panose->text.proportion == DWRITE_PANOSE_PROPORTION_MONOSPACED;
5105 return is_monospaced;
5108 static void test_IsMonospacedFont(void)
5110 IDWriteFontCollection *collection;
5111 IDWriteFactory1 *factory;
5112 UINT32 count, i;
5113 HRESULT hr;
5114 ULONG ref;
5116 factory = create_factory_iid(&IID_IDWriteFactory1);
5118 if (!factory)
5120 win_skip("IsMonospacedFont() is not supported.\n");
5121 return;
5124 hr = IDWriteFactory1_GetSystemFontCollection(factory, &collection, FALSE);
5125 ok(hr == S_OK, "Failed to get font collection, hr %#lx.\n", hr);
5127 count = IDWriteFontCollection_GetFontFamilyCount(collection);
5128 for (i = 0; i < count; ++i)
5130 IDWriteLocalizedStrings *names;
5131 IDWriteFontFamily *family;
5132 UINT32 font_count, j;
5133 WCHAR nameW[256];
5135 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
5136 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
5138 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
5139 ok(hr == S_OK, "Failed to get names, hr %#lx.\n", hr);
5140 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
5141 IDWriteLocalizedStrings_Release(names);
5143 font_count = IDWriteFontFamily_GetFontCount(family);
5145 for (j = 0; j < font_count; ++j)
5147 BOOL is_monospaced_font, is_monospaced_face, is_monospaced_expected;
5148 IDWriteFontFace1 *fontface1;
5149 IDWriteFontFace *fontface;
5150 DWRITE_PANOSE panose;
5151 IDWriteFont1 *font1;
5152 IDWriteFont *font;
5154 hr = IDWriteFontFamily_GetFont(family, j, &font);
5155 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
5157 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
5158 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
5159 IDWriteFont_Release(font);
5161 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
5162 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
5164 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
5165 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
5166 IDWriteFontFace_Release(fontface);
5168 is_monospaced_font = IDWriteFont1_IsMonospacedFont(font1);
5169 is_monospaced_face = IDWriteFontFace1_IsMonospacedFont(fontface1);
5170 ok(is_monospaced_font == is_monospaced_face, "Unexpected monospaced flag.\n");
5172 IDWriteFont1_GetPanose(font1, &panose);
5174 is_monospaced_expected = get_expected_is_monospaced(fontface1, &panose);
5175 ok(is_monospaced_expected == is_monospaced_face, "Unexpected is_monospaced flag %d for %s, font %d.\n",
5176 is_monospaced_face, wine_dbgstr_w(nameW), j);
5178 IDWriteFontFace1_Release(fontface1);
5179 IDWriteFont1_Release(font1);
5182 IDWriteFontFamily_Release(family);
5185 IDWriteFontCollection_Release(collection);
5186 ref = IDWriteFactory1_Release(factory);
5187 ok(ref == 0, "factory not released, %lu\n", ref);
5190 static void test_GetDesignGlyphAdvances(void)
5192 IDWriteFontFace1 *fontface1;
5193 IDWriteFontFace *fontface;
5194 IDWriteFactory *factory;
5195 IDWriteFontFile *file;
5196 WCHAR *path;
5197 HRESULT hr;
5198 ULONG ref;
5200 factory = create_factory();
5202 path = create_testfontfile(test_fontfile);
5204 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5205 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5207 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
5208 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5209 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5210 IDWriteFontFile_Release(file);
5212 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5213 if (hr == S_OK) {
5214 UINT32 codepoint;
5215 UINT16 index;
5216 INT32 advance;
5218 codepoint = 'A';
5219 index = 0;
5220 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &index);
5221 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5222 ok(index > 0, "got %u\n", index);
5224 advance = 0;
5225 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, FALSE);
5226 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5227 ok(advance == 1000, "got %i\n", advance);
5229 advance = 0;
5230 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, TRUE);
5231 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5232 todo_wine
5233 ok(advance == 2048, "got %i\n", advance);
5235 IDWriteFontFace1_Release(fontface1);
5237 else
5238 win_skip("GetDesignGlyphAdvances() is not supported.\n");
5240 IDWriteFontFace_Release(fontface);
5241 ref = IDWriteFactory_Release(factory);
5242 ok(ref == 0, "factory not released, %lu\n", ref);
5243 DELETE_FONTFILE(path);
5246 static void test_GetGlyphRunOutline(void)
5248 DWRITE_GLYPH_OFFSET offsets[2];
5249 IDWriteFactory *factory;
5250 IDWriteFontFile *file;
5251 IDWriteFontFace *face;
5252 UINT32 codepoint;
5253 FLOAT advances[2];
5254 UINT16 glyphs[2];
5255 WCHAR *path;
5256 HRESULT hr;
5257 ULONG ref;
5259 path = create_testfontfile(test_fontfile);
5260 factory = create_factory();
5262 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5263 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5265 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
5266 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5267 IDWriteFontFile_Release(file);
5269 codepoint = 'A';
5270 glyphs[0] = 0;
5271 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5272 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5273 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5274 glyphs[1] = glyphs[0];
5276 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, glyphs, advances, offsets, 1, FALSE, FALSE, NULL);
5277 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5279 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, NULL, NULL, offsets, 1, FALSE, FALSE, &test_geomsink);
5280 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5282 advances[0] = 1.0;
5283 advances[1] = 0.0;
5285 offsets[0].advanceOffset = 1.0;
5286 offsets[0].ascenderOffset = 1.0;
5287 offsets[1].advanceOffset = 0.0;
5288 offsets[1].ascenderOffset = 0.0;
5290 /* default advances, no offsets */
5291 memset(g_startpoints, 0, sizeof(g_startpoints));
5292 g_startpoint_count = 0;
5293 SET_EXPECT(setfillmode);
5294 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, FALSE, &test_geomsink);
5295 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5296 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5297 if (g_startpoint_count == 2) {
5298 /* glyph advance of 500 is applied */
5299 ok(g_startpoints[0].x == 229.5 && g_startpoints[0].y == -629.0, "0: got (%.2f,%.2f)\n", g_startpoints[0].x, g_startpoints[0].y);
5300 ok(g_startpoints[1].x == 729.5 && g_startpoints[1].y == -629.0, "1: got (%.2f,%.2f)\n", g_startpoints[1].x, g_startpoints[1].y);
5302 CHECK_CALLED(setfillmode);
5304 /* default advances, no offsets, RTL */
5305 memset(g_startpoints, 0, sizeof(g_startpoints));
5306 g_startpoint_count = 0;
5307 SET_EXPECT(setfillmode);
5308 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, TRUE, &test_geomsink);
5309 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5310 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5311 if (g_startpoint_count == 2) {
5312 /* advance is -500 now */
5313 ok(g_startpoints[0].x == -270.5 && g_startpoints[0].y == -629.0, "0: got (%.2f,%.2f)\n", g_startpoints[0].x, g_startpoints[0].y);
5314 ok(g_startpoints[1].x == -770.5 && g_startpoints[1].y == -629.0, "1: got (%.2f,%.2f)\n", g_startpoints[1].x, g_startpoints[1].y);
5316 CHECK_CALLED(setfillmode);
5318 /* default advances, additional offsets */
5319 memset(g_startpoints, 0, sizeof(g_startpoints));
5320 g_startpoint_count = 0;
5321 SET_EXPECT(setfillmode);
5322 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, FALSE, &test_geomsink);
5323 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5324 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5325 if (g_startpoint_count == 2) {
5326 /* offsets applied to first contour */
5327 ok(g_startpoints[0].x == 230.5 && g_startpoints[0].y == -630.0, "0: got (%.2f,%.2f)\n", g_startpoints[0].x, g_startpoints[0].y);
5328 ok(g_startpoints[1].x == 729.5 && g_startpoints[1].y == -629.0, "1: got (%.2f,%.2f)\n", g_startpoints[1].x, g_startpoints[1].y);
5330 CHECK_CALLED(setfillmode);
5332 /* default advances, additional offsets, RTL */
5333 memset(g_startpoints, 0, sizeof(g_startpoints));
5334 g_startpoint_count = 0;
5335 SET_EXPECT(setfillmode);
5336 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, TRUE, &test_geomsink);
5337 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5338 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5339 if (g_startpoint_count == 2) {
5340 ok(g_startpoints[0].x == -271.5 && g_startpoints[0].y == -630.0, "0: got (%.2f,%.2f)\n", g_startpoints[0].x, g_startpoints[0].y);
5341 ok(g_startpoints[1].x == -770.5 && g_startpoints[1].y == -629.0, "1: got (%.2f,%.2f)\n", g_startpoints[1].x, g_startpoints[1].y);
5343 CHECK_CALLED(setfillmode);
5345 /* custom advances and offsets, offset turns total advance value to zero */
5346 memset(g_startpoints, 0, sizeof(g_startpoints));
5347 g_startpoint_count = 0;
5348 SET_EXPECT(setfillmode);
5349 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, advances, offsets, 2, FALSE, FALSE, &test_geomsink);
5350 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5351 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5352 if (g_startpoint_count == 2) {
5353 ok(g_startpoints[0].x == 230.5 && g_startpoints[0].y == -630.0, "0: got (%.2f,%.2f)\n", g_startpoints[0].x, g_startpoints[0].y);
5354 ok(g_startpoints[1].x == 230.5 && g_startpoints[1].y == -629.0, "1: got (%.2f,%.2f)\n", g_startpoints[1].x, g_startpoints[1].y);
5356 CHECK_CALLED(setfillmode);
5358 /* 0 glyph count */
5359 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 0, FALSE, FALSE, &test_geomsink2);
5360 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5362 /* Glyph with open figure, single contour point. */
5363 codepoint = 'B';
5364 glyphs[0] = 0;
5365 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5366 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5367 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5369 SET_EXPECT(setfillmode);
5370 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
5371 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5372 CHECK_CALLED(setfillmode);
5374 IDWriteFactory_Release(factory);
5375 IDWriteFontFace_Release(face);
5376 DELETE_FONTFILE(path);
5378 /* space glyph */
5379 factory = create_factory();
5380 face = create_fontface(factory);
5382 codepoint = ' ';
5383 glyphs[0] = 0;
5384 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5385 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5386 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5388 SET_EXPECT(setfillmode);
5389 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
5390 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5391 CHECK_CALLED(setfillmode);
5393 IDWriteFontFace_Release(face);
5394 ref = IDWriteFactory_Release(factory);
5395 ok(ref == 0, "factory not released, %lu\n", ref);
5398 static void test_GetEudcFontCollection(void)
5400 IDWriteFontCollection *coll, *coll2;
5401 IDWriteFactory1 *factory;
5402 HRESULT hr;
5403 ULONG ref;
5405 factory = create_factory_iid(&IID_IDWriteFactory1);
5406 if (!factory) {
5407 win_skip("GetEudcFontCollection() is not supported.\n");
5408 return;
5411 EXPECT_REF(factory, 1);
5412 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll, FALSE);
5413 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5414 EXPECT_REF(factory, 2);
5415 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll2, FALSE);
5416 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5417 EXPECT_REF(factory, 2);
5418 ok(coll == coll2, "got %p, %p\n", coll, coll2);
5419 IDWriteFontCollection_Release(coll);
5420 IDWriteFontCollection_Release(coll2);
5422 ref = IDWriteFactory1_Release(factory);
5423 ok(ref == 0, "factory not released, %lu\n", ref);
5426 static void test_GetCaretMetrics(void)
5428 DWRITE_FONT_METRICS1 metrics;
5429 IDWriteFontFace1 *fontface1;
5430 DWRITE_CARET_METRICS caret;
5431 IDWriteFontFace *fontface;
5432 IDWriteFactory *factory;
5433 IDWriteFontFile *file;
5434 IDWriteFont *font;
5435 WCHAR *path;
5436 HRESULT hr;
5437 ULONG ref;
5439 path = create_testfontfile(test_fontfile);
5440 factory = create_factory();
5442 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5443 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5445 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5446 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5447 IDWriteFontFile_Release(file);
5449 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5450 IDWriteFontFace_Release(fontface);
5451 if (hr != S_OK) {
5452 win_skip("GetCaretMetrics() is not supported.\n");
5453 ref = IDWriteFactory_Release(factory);
5454 ok(ref == 0, "factory not released, %lu\n", ref);
5455 DELETE_FONTFILE(path);
5456 return;
5459 memset(&caret, 0xcc, sizeof(caret));
5460 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5461 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
5462 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
5463 ok(caret.offset == 0, "got %d\n", caret.offset);
5464 IDWriteFontFace1_Release(fontface1);
5465 IDWriteFactory_Release(factory);
5467 /* now with Tahoma Normal */
5468 factory = create_factory();
5469 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5470 hr = IDWriteFont_CreateFontFace(font, &fontface);
5471 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5472 IDWriteFont_Release(font);
5473 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5474 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5475 IDWriteFontFace_Release(fontface);
5477 memset(&caret, 0xcc, sizeof(caret));
5478 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5479 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
5480 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
5481 ok(caret.offset == 0, "got %d\n", caret.offset);
5482 IDWriteFontFace1_Release(fontface1);
5484 /* simulated italic */
5485 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
5486 hr = IDWriteFont_CreateFontFace(font, &fontface);
5487 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5488 IDWriteFont_Release(font);
5489 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5490 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5491 IDWriteFontFace_Release(fontface);
5493 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
5495 memset(&caret, 0xcc, sizeof(caret));
5496 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5497 ok(caret.slopeRise == metrics.designUnitsPerEm, "got %d\n", caret.slopeRise);
5498 ok(caret.slopeRun > 0, "got %d\n", caret.slopeRun);
5499 ok(caret.offset == 0, "got %d\n", caret.offset);
5500 IDWriteFontFace1_Release(fontface1);
5502 ref = IDWriteFactory_Release(factory);
5503 ok(ref == 0, "factory not released, %lu\n", ref);
5504 DELETE_FONTFILE(path);
5507 static void test_GetGlyphCount(void)
5509 IDWriteFontFace *fontface;
5510 IDWriteFactory *factory;
5511 IDWriteFontFile *file;
5512 UINT16 count;
5513 WCHAR *path;
5514 HRESULT hr;
5515 ULONG ref;
5517 path = create_testfontfile(test_fontfile);
5518 factory = create_factory();
5520 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5521 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5523 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5524 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5525 IDWriteFontFile_Release(file);
5527 count = IDWriteFontFace_GetGlyphCount(fontface);
5528 ok(count == 8, "got %u\n", count);
5530 IDWriteFontFace_Release(fontface);
5531 ref = IDWriteFactory_Release(factory);
5532 ok(ref == 0, "factory not released, %lu\n", ref);
5533 DELETE_FONTFILE(path);
5536 static void test_GetKerningPairAdjustments(void)
5538 IDWriteFontFace1 *fontface1;
5539 IDWriteFontFace *fontface;
5540 IDWriteFactory *factory;
5541 IDWriteFontFile *file;
5542 WCHAR *path;
5543 HRESULT hr;
5544 ULONG ref;
5546 path = create_testfontfile(test_fontfile);
5547 factory = create_factory();
5549 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5550 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5552 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5553 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5554 IDWriteFontFile_Release(file);
5556 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5557 if (hr == S_OK) {
5558 INT32 adjustments[1];
5560 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 0, NULL, NULL);
5561 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
5563 if (0) /* crashes on native */
5564 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, NULL);
5566 adjustments[0] = 1;
5567 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, adjustments);
5568 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5569 ok(adjustments[0] == 0, "got %d\n", adjustments[0]);
5571 IDWriteFontFace1_Release(fontface1);
5573 else
5574 win_skip("GetKerningPairAdjustments() is not supported.\n");
5576 IDWriteFontFace_Release(fontface);
5577 ref = IDWriteFactory_Release(factory);
5578 ok(ref == 0, "factory not released, %lu\n", ref);
5579 DELETE_FONTFILE(path);
5582 static void test_CreateRenderingParams(void)
5584 IDWriteRenderingParams2 *params2;
5585 IDWriteRenderingParams1 *params1;
5586 IDWriteRenderingParams *params;
5587 DWRITE_RENDERING_MODE mode;
5588 IDWriteFactory3 *factory3;
5589 IDWriteFactory *factory;
5590 HRESULT hr;
5591 ULONG ref;
5593 factory = create_factory();
5595 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
5596 DWRITE_RENDERING_MODE_DEFAULT, &params);
5597 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5599 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams1, (void**)&params1);
5600 if (hr == S_OK) {
5601 FLOAT enhcontrast;
5603 /* test what enhanced contrast setting set by default to */
5604 enhcontrast = IDWriteRenderingParams1_GetGrayscaleEnhancedContrast(params1);
5605 ok(enhcontrast == 1.0, "got %.2f\n", enhcontrast);
5606 IDWriteRenderingParams1_Release(params1);
5608 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
5609 if (hr == S_OK) {
5610 DWRITE_GRID_FIT_MODE gridfit;
5612 /* default gridfit mode */
5613 gridfit = IDWriteRenderingParams2_GetGridFitMode(params2);
5614 ok(gridfit == DWRITE_GRID_FIT_MODE_DEFAULT, "got %d\n", gridfit);
5616 IDWriteRenderingParams2_Release(params2);
5618 else
5619 win_skip("IDWriteRenderingParams2 not supported.\n");
5621 else
5622 win_skip("IDWriteRenderingParams1 not supported.\n");
5624 IDWriteRenderingParams_Release(params);
5626 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
5627 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5629 mode = IDWriteRenderingParams_GetRenderingMode(params);
5630 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
5631 IDWriteRenderingParams_Release(params);
5633 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
5634 if (hr == S_OK) {
5635 IDWriteRenderingParams3 *params3;
5637 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
5638 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_DEFAULT, &params3);
5639 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5641 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
5642 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5644 mode = IDWriteRenderingParams_GetRenderingMode(params);
5645 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
5647 IDWriteRenderingParams_Release(params);
5648 IDWriteRenderingParams3_Release(params3);
5649 IDWriteFactory3_Release(factory3);
5651 else
5652 win_skip("IDWriteRenderingParams3 not supported.\n");
5654 ref = IDWriteFactory_Release(factory);
5655 ok(ref == 0, "factory not released, %lu\n", ref);
5658 static void test_CreateGlyphRunAnalysis(void)
5660 static const DWRITE_RENDERING_MODE rendermodes[] = {
5661 DWRITE_RENDERING_MODE_ALIASED,
5662 DWRITE_RENDERING_MODE_GDI_CLASSIC,
5663 DWRITE_RENDERING_MODE_GDI_NATURAL,
5664 DWRITE_RENDERING_MODE_NATURAL,
5665 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
5668 IDWriteGlyphRunAnalysis *analysis, *analysis2;
5669 IDWriteRenderingParams *params;
5670 IDWriteFactory3 *factory3;
5671 IDWriteFactory2 *factory2;
5672 IDWriteFactory *factory;
5673 DWRITE_GLYPH_RUN run;
5674 IDWriteFontFace *face;
5675 UINT16 glyph, glyphs[10];
5676 FLOAT advances[2];
5677 HRESULT hr;
5678 UINT32 ch;
5679 RECT rect, rect2;
5680 DWRITE_GLYPH_OFFSET offsets[2];
5681 DWRITE_GLYPH_METRICS metrics;
5682 DWRITE_FONT_METRICS fm;
5683 DWRITE_MATRIX m;
5684 ULONG size;
5685 BYTE *bits;
5686 ULONG ref;
5687 int i;
5689 factory = create_factory();
5690 face = create_fontface(factory);
5692 ch = 'A';
5693 glyph = 0;
5694 hr = IDWriteFontFace_GetGlyphIndices(face, &ch, 1, &glyph);
5695 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5696 ok(glyph > 0, "got %u\n", glyph);
5698 hr = IDWriteFontFace_GetDesignGlyphMetrics(face, &glyph, 1, &metrics, FALSE);
5699 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5700 advances[0] = metrics.advanceWidth;
5702 offsets[0].advanceOffset = 0.0;
5703 offsets[0].ascenderOffset = 0.0;
5705 run.fontFace = face;
5706 run.fontEmSize = 24.0;
5707 run.glyphCount = 1;
5708 run.glyphIndices = &glyph;
5709 run.glyphAdvances = advances;
5710 run.glyphOffsets = offsets;
5711 run.isSideways = FALSE;
5712 run.bidiLevel = 0;
5714 /* zero ppdip */
5715 analysis = (void*)0xdeadbeef;
5716 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 0.0, NULL,
5717 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5718 0.0, 0.0, &analysis);
5719 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5720 ok(analysis == NULL, "got %p\n", analysis);
5722 /* negative ppdip */
5723 analysis = (void*)0xdeadbeef;
5724 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, -1.0, NULL,
5725 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5726 0.0, 0.0, &analysis);
5727 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5728 ok(analysis == NULL, "got %p\n", analysis);
5730 /* default mode is not allowed */
5731 analysis = (void*)0xdeadbeef;
5732 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5733 DWRITE_RENDERING_MODE_DEFAULT, DWRITE_MEASURING_MODE_NATURAL,
5734 0.0, 0.0, &analysis);
5735 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5736 ok(analysis == NULL, "got %p\n", analysis);
5738 /* outline too */
5739 analysis = (void*)0xdeadbeef;
5740 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5741 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_MEASURING_MODE_NATURAL,
5742 0.0, 0.0, &analysis);
5743 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5744 ok(analysis == NULL, "got %p\n", analysis);
5746 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5747 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5748 0.0, 0.0, &analysis);
5749 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5751 /* invalid texture type */
5752 memset(&rect, 0xcc, sizeof(rect));
5753 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &rect);
5754 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5755 ok(rect.left == 0 && rect.right == 0 &&
5756 rect.top == 0 && rect.bottom == 0, "unexpected rect\n");
5758 /* check how origin affects bounds */
5759 SetRectEmpty(&rect);
5760 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5761 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5762 ok(!IsRectEmpty(&rect), "got empty rect\n");
5763 IDWriteGlyphRunAnalysis_Release(analysis);
5765 /* doubled ppdip */
5766 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5767 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5768 0.0, 0.0, &analysis);
5769 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5770 SetRectEmpty(&rect2);
5771 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5772 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5773 ok(rect.right - rect.left < rect2.right - rect2.left, "expected wider rect\n");
5774 ok(rect.bottom - rect.top < rect2.bottom - rect2.top, "expected taller rect\n");
5775 IDWriteGlyphRunAnalysis_Release(analysis);
5777 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5778 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5779 10.0, -5.0, &analysis);
5780 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5782 SetRectEmpty(&rect2);
5783 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5784 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5785 ok(!IsRectEmpty(&rect2), "got empty rect\n");
5786 IDWriteGlyphRunAnalysis_Release(analysis);
5788 ok(!EqualRect(&rect, &rect2), "got equal bounds\n");
5789 OffsetRect(&rect, 10, -5);
5790 ok(EqualRect(&rect, &rect2), "got different bounds\n");
5792 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
5793 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5794 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
5795 0.0, 0.0, &analysis);
5796 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5798 if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
5799 SetRectEmpty(&rect);
5800 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5801 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5802 ok(!IsRectEmpty(&rect), "got empty rect\n");
5804 SetRect(&rect, 0, 0, 1, 1);
5805 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5806 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5807 ok(IsRectEmpty(&rect), "unexpected empty rect\n");
5809 else {
5810 SetRect(&rect, 0, 0, 1, 1);
5811 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5812 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5813 ok(IsRectEmpty(&rect), "got empty rect\n");
5815 SetRectEmpty(&rect);
5816 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5817 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5818 ok(!IsRectEmpty(&rect), "got empty rect\n");
5821 IDWriteGlyphRunAnalysis_Release(analysis);
5824 IDWriteFontFace_GetMetrics(run.fontFace, &fm);
5826 /* check bbox for a single glyph run */
5827 for (run.fontEmSize = 1.0; run.fontEmSize <= 100.0; run.fontEmSize += 1.0) {
5828 DWRITE_GLYPH_METRICS gm;
5829 LONG bboxX, bboxY;
5831 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5832 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5833 0.0, 0.0, &analysis);
5834 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5836 SetRectEmpty(&rect);
5837 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5838 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5840 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
5841 DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
5842 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5844 /* metrics are in design units */
5845 bboxX = (int)floorf((gm.advanceWidth - gm.leftSideBearing - gm.rightSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
5846 bboxY = (int)floorf((gm.advanceHeight - gm.topSideBearing - gm.bottomSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
5848 rect.right -= rect.left;
5849 rect.bottom -= rect.top;
5850 ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %ld, from metrics %ld\n", run.fontEmSize, rect.right, bboxX);
5851 ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %ld, from metrics %ld\n", run.fontEmSize, rect.bottom, bboxY);
5853 IDWriteGlyphRunAnalysis_Release(analysis);
5856 /* without offsets */
5857 run.fontFace = face;
5858 run.fontEmSize = 24.0;
5859 run.glyphCount = 1;
5860 run.glyphIndices = &glyph;
5861 run.glyphAdvances = advances;
5862 run.glyphOffsets = NULL;
5863 run.isSideways = FALSE;
5864 run.bidiLevel = 0;
5866 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5867 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5868 0.0, 0.0, &analysis);
5869 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5871 SetRectEmpty(&rect);
5872 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5873 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5874 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5876 IDWriteGlyphRunAnalysis_Release(analysis);
5878 /* without explicit advances */
5879 run.fontFace = face;
5880 run.fontEmSize = 24.0;
5881 run.glyphCount = 1;
5882 run.glyphIndices = &glyph;
5883 run.glyphAdvances = NULL;
5884 run.glyphOffsets = NULL;
5885 run.isSideways = FALSE;
5886 run.bidiLevel = 0;
5888 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5889 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5890 0.0, 0.0, &analysis);
5891 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5893 SetRectEmpty(&rect);
5894 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5895 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5896 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5898 IDWriteGlyphRunAnalysis_Release(analysis);
5900 /* test that advances are scaled according to ppdip too */
5901 glyphs[0] = glyphs[1] = glyph;
5902 advances[0] = advances[1] = 100.0f;
5903 run.fontFace = face;
5904 run.fontEmSize = 24.0;
5905 run.glyphCount = 2;
5906 run.glyphIndices = glyphs;
5907 run.glyphAdvances = advances;
5908 run.glyphOffsets = NULL;
5909 run.isSideways = FALSE;
5910 run.bidiLevel = 0;
5912 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5913 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5914 0.0, 0.0, &analysis);
5915 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5917 SetRectEmpty(&rect2);
5918 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5919 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5920 ok(!IsRectEmpty(&rect2), "got empty bounds\n");
5921 ok(!EqualRect(&rect, &rect2), "got wrong rect2\n");
5922 ok((rect2.right - rect.left) > advances[0], "got rect width %ld for advance %f\n", rect.right - rect.left, advances[0]);
5923 IDWriteGlyphRunAnalysis_Release(analysis);
5925 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5926 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5927 0.0, 0.0, &analysis);
5928 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5930 SetRectEmpty(&rect);
5931 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5932 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5933 ok((rect.right - rect.left) > 2 * advances[0], "got rect width %ld for advance %f\n", rect.right - rect.left, advances[0]);
5934 IDWriteGlyphRunAnalysis_Release(analysis);
5936 /* with scaling transform */
5937 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5938 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5939 0.0, 0.0, &analysis);
5940 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5942 SetRectEmpty(&rect);
5943 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5944 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5945 ok(!IsRectEmpty(&rect), "got rect width %ld\n", rect.right - rect.left);
5946 IDWriteGlyphRunAnalysis_Release(analysis);
5948 memset(&m, 0, sizeof(m));
5949 m.m11 = 2.0;
5950 m.m22 = 1.0;
5951 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5952 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5953 0.0, 0.0, &analysis);
5954 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5956 SetRectEmpty(&rect2);
5957 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5958 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5959 ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %ld\n", rect2.right - rect2.left);
5961 /* instances are not reused for same runs */
5962 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5963 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5964 0.0, 0.0, &analysis2);
5965 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5966 ok(analysis2 != analysis, "got %p, previous instance %p\n", analysis2, analysis);
5967 IDWriteGlyphRunAnalysis_Release(analysis2);
5969 IDWriteGlyphRunAnalysis_Release(analysis);
5971 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void **)&factory2) == S_OK) {
5972 FLOAT gamma, contrast, cleartype_level;
5974 /* Invalid antialias mode. */
5975 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5976 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
5977 0.0f, 0.0f, &analysis);
5978 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5980 /* Invalid grid fit mode. */
5981 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5982 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5983 0.0f, 0.0f, &analysis);
5984 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5986 /* Invalid rendering mode. */
5987 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_OUTLINE,
5988 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5989 0.0f, 0.0f, &analysis);
5990 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5992 /* Invalid measuring mode. */
5993 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5994 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5995 0.0f, 0.0f, &analysis);
5996 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5998 /* Win8 does not accept default grid fitting mode. */
5999 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
6000 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6001 0.0f, 0.0f, &analysis);
6002 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Win8 */, "Failed to create analysis, hr %#lx.\n", hr);
6003 if (hr == S_OK)
6004 IDWriteGlyphRunAnalysis_Release(analysis);
6006 /* Natural mode, grayscale antialiased. */
6007 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
6008 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6009 0.0f, 0.0f, &analysis);
6010 ok(hr == S_OK, "Failed to create analysis, hr %#lx.\n", hr);
6012 SetRect(&rect, 0, 1, 0, 1);
6013 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
6014 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6015 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
6017 SetRectEmpty(&rect);
6018 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
6019 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6020 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
6022 size = (rect.right - rect.left) * (rect.bottom - rect.top);
6023 bits = malloc(size);
6025 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
6026 ok(hr == S_OK, "Failed to get alpha texture, hr %#lx.\n", hr);
6028 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
6029 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
6031 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
6032 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6034 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
6035 todo_wine
6036 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6038 free(bits);
6040 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.1f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
6041 DWRITE_RENDERING_MODE_NATURAL, &params);
6042 ok(hr == S_OK, "Failed to create custom parameters, hr %#lx.\n", hr);
6044 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &cleartype_level);
6045 ok(hr == S_OK, "Failed to get alpha blend params, hr %#lx.\n", hr);
6046 todo_wine
6047 ok(cleartype_level == 0.0f, "Unexpected cleartype level %f.\n", cleartype_level);
6049 IDWriteRenderingParams_Release(params);
6050 IDWriteGlyphRunAnalysis_Release(analysis);
6052 IDWriteFactory2_Release(factory2);
6055 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3) == S_OK) {
6057 /* Invalid antialias mode. */
6058 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6059 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
6060 0.0f, 0.0f, &analysis);
6061 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6063 /* Invalid grid fit mode. */
6064 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6065 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6066 0.0f, 0.0f, &analysis);
6067 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6069 /* Invalid rendering mode. */
6070 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_OUTLINE,
6071 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6072 0.0f, 0.0f, &analysis);
6073 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6075 /* Invalid measuring mode. */
6076 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6077 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED,
6078 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, 0.0f, 0.0f, &analysis);
6079 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6081 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
6082 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6083 0.0f, 0.0f, &analysis);
6084 ok(hr == S_OK, "Failed to create analysis, hr %#lx.\n", hr);
6085 IDWriteGlyphRunAnalysis_Release(analysis);
6087 /* Natural mode, grayscale antialiased. */
6088 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
6089 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6090 0.0f, 0.0f, &analysis);
6091 ok(hr == S_OK, "Failed to create analysis, hr %#lx.\n", hr);
6093 SetRect(&rect, 0, 1, 0, 1);
6094 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
6095 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6096 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
6098 SetRectEmpty(&rect);
6099 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
6100 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6101 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
6103 size = (rect.right - rect.left) * (rect.bottom - rect.top);
6104 bits = malloc(size);
6106 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
6107 ok(hr == S_OK, "Failed to get alpha texture, hr %#lx.\n", hr);
6109 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
6110 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
6112 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
6113 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6115 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
6116 todo_wine
6117 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6119 free(bits);
6121 IDWriteGlyphRunAnalysis_Release(analysis);
6123 IDWriteFactory3_Release(factory3);
6126 IDWriteFontFace_Release(face);
6127 ref = IDWriteFactory_Release(factory);
6128 ok(ref == 0, "factory not released, %lu\n", ref);
6131 #define round(x) ((int)floor((x) + 0.5))
6133 struct VDMX_Header
6135 WORD version;
6136 WORD numRecs;
6137 WORD numRatios;
6140 struct VDMX_Ratio
6142 BYTE bCharSet;
6143 BYTE xRatio;
6144 BYTE yStartRatio;
6145 BYTE yEndRatio;
6148 struct VDMX_group
6150 WORD recs;
6151 BYTE startsz;
6152 BYTE endsz;
6155 struct VDMX_vTable
6157 WORD yPelHeight;
6158 SHORT yMax;
6159 SHORT yMin;
6162 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
6164 WORD num_ratios, i, group_offset = 0;
6165 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
6166 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
6168 num_ratios = GET_BE_WORD(hdr->numRatios);
6170 for (i = 0; i < num_ratios; i++)
6172 if (!ratios[i].bCharSet) continue;
6174 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
6175 ratios[i].yEndRatio == 0) ||
6176 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
6177 ratios[i].yEndRatio >= dev_y_ratio))
6179 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
6180 break;
6183 if (group_offset)
6184 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
6185 return NULL;
6188 static BOOL get_vdmx_size(const struct VDMX_group *group, int emsize, int *a, int *d)
6190 WORD recs, i;
6191 const struct VDMX_vTable *tables;
6193 if (!group) return FALSE;
6195 recs = GET_BE_WORD(group->recs);
6196 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
6198 tables = (const struct VDMX_vTable *)(group + 1);
6199 for (i = 0; i < recs; i++)
6201 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
6202 if (ppem > emsize)
6204 /* FIXME: Supposed to interpolate */
6205 trace("FIXME interpolate %d\n", emsize);
6206 return FALSE;
6209 if (ppem == emsize)
6211 *a = (SHORT)GET_BE_WORD(tables[i].yMax);
6212 *d = -(SHORT)GET_BE_WORD(tables[i].yMin);
6213 return TRUE;
6216 return FALSE;
6219 static void test_metrics_cmp(FLOAT emsize, const DWRITE_FONT_METRICS *metrics, const DWRITE_FONT_METRICS1 *expected)
6221 winetest_push_context("Size %.2f", emsize);
6223 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "got %u expect %u.\n",
6224 metrics->designUnitsPerEm, expected->designUnitsPerEm);
6225 ok(metrics->ascent == expected->ascent, "a: got %u expect %u.\n", metrics->ascent, expected->ascent);
6226 ok(metrics->descent == expected->descent, "d: got %u expect %u.\n", metrics->descent, expected->descent);
6227 ok(metrics->lineGap == expected->lineGap, "lg: got %d expect %d.\n", metrics->lineGap, expected->lineGap);
6228 ok(metrics->capHeight == expected->capHeight, "capH: got %u expect %u.\n", metrics->capHeight, expected->capHeight);
6229 ok(metrics->xHeight == expected->xHeight, "xH: got %u expect %u.\n", metrics->xHeight, expected->xHeight);
6230 ok(metrics->underlinePosition == expected->underlinePosition, "ulP: got %d expect %d.\n",
6231 metrics->underlinePosition, expected->underlinePosition);
6232 ok(metrics->underlineThickness == expected->underlineThickness, "ulTh: got %u expect %u.\n",
6233 metrics->underlineThickness, expected->underlineThickness);
6234 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "stP: got %d expect %d.\n",
6235 metrics->strikethroughPosition, expected->strikethroughPosition);
6236 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "stTh: got %u expect %u.\n",
6237 metrics->strikethroughThickness, expected->strikethroughThickness);
6239 winetest_pop_context();
6242 static void test_metrics1_cmp(FLOAT emsize, const DWRITE_FONT_METRICS1 *metrics, const DWRITE_FONT_METRICS1 *expected)
6244 winetest_push_context("Size %.2f", emsize);
6246 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "got %u expect %u.\n",
6247 metrics->designUnitsPerEm, expected->designUnitsPerEm);
6248 ok(metrics->ascent == expected->ascent, "a: got %u expect %u.\n", metrics->ascent, expected->ascent);
6249 ok(metrics->descent == expected->descent, "d: got %u expect %u.\n", metrics->descent, expected->descent);
6250 ok(metrics->lineGap == expected->lineGap, "lg: got %d expect %d.\n", metrics->lineGap, expected->lineGap);
6251 ok(metrics->capHeight == expected->capHeight, "capH: got %u expect %u.\n", metrics->capHeight, expected->capHeight);
6252 ok(metrics->xHeight == expected->xHeight, "xH: got %u expect %u.\n", metrics->xHeight, expected->xHeight);
6253 ok(metrics->underlinePosition == expected->underlinePosition, "ulP: got %d expect %d.\n",
6254 metrics->underlinePosition, expected->underlinePosition);
6255 ok(metrics->underlineThickness == expected->underlineThickness, "ulTh: got %u expect %u.\n",
6256 metrics->underlineThickness, expected->underlineThickness);
6257 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "stP: got %d expect %d.\n",
6258 metrics->strikethroughPosition, expected->strikethroughPosition);
6259 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "stTh: got %u expect %u.\n",
6260 metrics->strikethroughThickness, expected->strikethroughThickness);
6261 ok(metrics->glyphBoxLeft == expected->glyphBoxLeft, "box left: got %d expect %d.\n",
6262 metrics->glyphBoxLeft, expected->glyphBoxLeft);
6263 if (0) { /* this is not consistent */
6264 ok(metrics->glyphBoxTop == expected->glyphBoxTop, "box top: got %d expect %d.\n",
6265 metrics->glyphBoxTop, expected->glyphBoxTop);
6266 ok(metrics->glyphBoxRight == expected->glyphBoxRight, "box right: got %d expect %d.\n",
6267 metrics->glyphBoxRight, expected->glyphBoxRight);
6269 ok(metrics->glyphBoxBottom == expected->glyphBoxBottom, "box bottom: got %d expect %d.\n",
6270 metrics->glyphBoxBottom, expected->glyphBoxBottom);
6271 ok(metrics->subscriptPositionX == expected->subscriptPositionX, "subX: got %d expect %d.\n",
6272 metrics->subscriptPositionX, expected->subscriptPositionX);
6273 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "subY: got %d expect %d.\n",
6274 metrics->subscriptPositionY, expected->subscriptPositionY);
6275 ok(metrics->subscriptSizeX == expected->subscriptSizeX, "subsizeX: got %d expect %d.\n",
6276 metrics->subscriptSizeX, expected->subscriptSizeX);
6277 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "subsizeY: got %d expect %d.\n",
6278 metrics->subscriptSizeY, expected->subscriptSizeY);
6279 ok(metrics->superscriptPositionX == expected->superscriptPositionX, "supX: got %d expect %d.\n",
6280 metrics->superscriptPositionX, expected->superscriptPositionX);
6281 if (0)
6282 ok(metrics->superscriptPositionY == expected->superscriptPositionY, "supY: got %d expect %d.\n",
6283 metrics->superscriptPositionY, expected->superscriptPositionY);
6284 ok(metrics->superscriptSizeX == expected->superscriptSizeX, "supsizeX: got %d expect %d.\n",
6285 metrics->superscriptSizeX, expected->superscriptSizeX);
6286 ok(metrics->superscriptSizeY == expected->superscriptSizeY, "supsizeY: got %d expect %d.\n",
6287 metrics->superscriptSizeY, expected->superscriptSizeY);
6288 ok(metrics->hasTypographicMetrics == expected->hasTypographicMetrics, "hastypo: got %d expect %d.\n",
6289 metrics->hasTypographicMetrics, expected->hasTypographicMetrics);
6291 winetest_pop_context();
6294 struct compatmetrics_test {
6295 DWRITE_MATRIX m;
6296 FLOAT ppdip;
6297 FLOAT emsize;
6300 static struct compatmetrics_test compatmetrics_tests[] = {
6301 { { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0, 5.0 },
6302 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 1.0, 5.0 },
6303 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 2.0, 5.0 },
6304 { { 0.0, 0.0, 0.0, 3.0, 0.0, 0.0 }, 2.0, 5.0 },
6305 { { 0.0, 0.0, 0.0, -3.0, 0.0, 0.0 }, 2.0, 5.0 },
6306 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 2.0, 5.0 },
6307 { { 1.0, 0.0, 0.0, 1.0, 5.0, 0.0 }, 2.0, 5.0 },
6308 { { 1.0, 0.0, 0.0, 1.0, 0.0, 5.0 }, 2.0, 5.0 },
6311 static void get_expected_metrics(IDWriteFontFace *fontface, struct compatmetrics_test *ptr,
6312 DWRITE_FONT_METRICS *expected)
6314 HRESULT hr;
6316 memset(expected, 0, sizeof(*expected));
6317 hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, ptr->ppdip * fabsf(ptr->m.m22) * ptr->emsize, 1.0, NULL, expected);
6318 ok(hr == S_OK, "got %08lx\n", hr);
6321 static void test_gdicompat_metrics(IDWriteFontFace *face)
6323 IDWriteFontFace1 *fontface1 = NULL;
6324 HRESULT hr;
6325 DWRITE_FONT_METRICS design_metrics, comp_metrics;
6326 DWRITE_FONT_METRICS1 design_metrics1, expected;
6327 FLOAT emsize, scale;
6328 int ascent, descent;
6329 const struct VDMX_Header *vdmx;
6330 UINT32 vdmx_len;
6331 void *vdmx_ctx;
6332 BOOL exists;
6333 const struct VDMX_group *vdmx_group = NULL;
6334 int i;
6336 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace1, (void**)&fontface1);
6337 if (hr != S_OK)
6338 win_skip("gdi compatible DWRITE_FONT_METRICS1 are not supported.\n");
6340 if (fontface1) {
6341 IDWriteFontFace1_GetMetrics(fontface1, &design_metrics1);
6342 memcpy(&design_metrics, &design_metrics1, sizeof(design_metrics));
6344 else
6345 IDWriteFontFace_GetMetrics(face, &design_metrics);
6347 hr = IDWriteFontFace_TryGetFontTable(face, MS_VDMX_TAG, (const void **)&vdmx,
6348 &vdmx_len, &vdmx_ctx, &exists);
6349 if (hr != S_OK || !exists)
6350 vdmx = NULL;
6351 else
6352 vdmx_group = find_vdmx_group(vdmx);
6354 /* negative emsize */
6355 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6356 memset(&expected, 0, sizeof(expected));
6357 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, -10.0, 1.0, NULL, &comp_metrics);
6358 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6359 test_metrics_cmp(0.0, &comp_metrics, &expected);
6361 /* zero emsize */
6362 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6363 memset(&expected, 0, sizeof(expected));
6364 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 0.0, 1.0, NULL, &comp_metrics);
6365 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6366 test_metrics_cmp(0.0, &comp_metrics, &expected);
6368 /* zero pixels per dip */
6369 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6370 memset(&expected, 0, sizeof(expected));
6371 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, 0.0, NULL, &comp_metrics);
6372 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6373 test_metrics_cmp(5.0, &comp_metrics, &expected);
6375 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6376 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, -1.0, NULL, &comp_metrics);
6377 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6378 test_metrics_cmp(5.0, &comp_metrics, &expected);
6380 for (i = 0; i < ARRAY_SIZE(compatmetrics_tests); i++) {
6381 struct compatmetrics_test *ptr = &compatmetrics_tests[i];
6383 get_expected_metrics(face, ptr, (DWRITE_FONT_METRICS*)&expected);
6384 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, ptr->emsize, ptr->ppdip, &ptr->m, &comp_metrics);
6385 ok(hr == S_OK, "got %08lx\n", hr);
6386 test_metrics_cmp(ptr->emsize, &comp_metrics, &expected);
6389 for (emsize = 5; emsize <= design_metrics.designUnitsPerEm; emsize++)
6391 DWRITE_FONT_METRICS1 comp_metrics1, expected;
6393 if (fontface1) {
6394 hr = IDWriteFontFace1_GetGdiCompatibleMetrics(fontface1, emsize, 1.0, NULL, &comp_metrics1);
6395 ok(hr == S_OK, "got %08lx\n", hr);
6397 else {
6398 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, emsize, 1.0, NULL, &comp_metrics);
6399 ok(hr == S_OK, "got %08lx\n", hr);
6402 scale = emsize / design_metrics.designUnitsPerEm;
6403 if (!get_vdmx_size(vdmx_group, emsize, &ascent, &descent))
6405 ascent = round(design_metrics.ascent * scale);
6406 descent = round(design_metrics.descent * scale);
6409 expected.designUnitsPerEm = design_metrics.designUnitsPerEm;
6410 expected.ascent = round(ascent / scale );
6411 expected.descent = round(descent / scale );
6412 expected.lineGap = round(round(design_metrics.lineGap * scale) / scale);
6413 expected.capHeight = round(round(design_metrics.capHeight * scale) / scale);
6414 expected.xHeight = round(round(design_metrics.xHeight * scale) / scale);
6415 expected.underlinePosition = round(round(design_metrics.underlinePosition * scale) / scale);
6416 expected.underlineThickness = round(round(design_metrics.underlineThickness * scale) / scale);
6417 expected.strikethroughPosition = round(round(design_metrics.strikethroughPosition * scale) / scale);
6418 expected.strikethroughThickness = round(round(design_metrics.strikethroughThickness * scale) / scale);
6420 if (fontface1) {
6421 expected.glyphBoxLeft = round(round(design_metrics1.glyphBoxLeft * scale) / scale);
6423 if (0) { /* those two fail on Tahoma and Win7 */
6424 expected.glyphBoxTop = round(round(design_metrics1.glyphBoxTop * scale) / scale);
6425 expected.glyphBoxRight = round(round(design_metrics1.glyphBoxRight * scale) / scale);
6427 expected.glyphBoxBottom = round(round(design_metrics1.glyphBoxBottom * scale) / scale);
6428 expected.subscriptPositionX = round(round(design_metrics1.subscriptPositionX * scale) / scale);
6429 expected.subscriptPositionY = round(round(design_metrics1.subscriptPositionY * scale) / scale);
6430 expected.subscriptSizeX = round(round(design_metrics1.subscriptSizeX * scale) / scale);
6431 expected.subscriptSizeY = round(round(design_metrics1.subscriptSizeY * scale) / scale);
6432 expected.superscriptPositionX = round(round(design_metrics1.superscriptPositionX * scale) / scale);
6433 if (0) /* this fails for 3 emsizes, Tahoma from [5, 2048] range */ {
6434 expected.superscriptPositionY = round(round(design_metrics1.superscriptPositionY * scale) / scale);
6436 expected.superscriptSizeX = round(round(design_metrics1.superscriptSizeX * scale) / scale);
6437 expected.superscriptSizeY = round(round(design_metrics1.superscriptSizeY * scale) / scale);
6438 expected.hasTypographicMetrics = design_metrics1.hasTypographicMetrics;
6440 test_metrics1_cmp(emsize, &comp_metrics1, &expected);
6442 else
6443 test_metrics_cmp(emsize, &comp_metrics, &expected);
6447 if (fontface1)
6448 IDWriteFontFace1_Release(fontface1);
6449 if (vdmx) IDWriteFontFace_ReleaseFontTable(face, vdmx_ctx);
6452 static void test_GetGdiCompatibleMetrics(void)
6454 IDWriteFactory *factory;
6455 IDWriteFont *font;
6456 IDWriteFontFace *fontface;
6457 HRESULT hr;
6458 ULONG ref;
6460 factory = create_factory();
6462 font = get_font(factory, L"Tahoma", DWRITE_FONT_STYLE_NORMAL);
6463 hr = IDWriteFont_CreateFontFace(font, &fontface);
6464 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6465 IDWriteFont_Release(font);
6466 test_gdicompat_metrics(fontface);
6467 IDWriteFontFace_Release(fontface);
6469 font = get_font(factory, L"Arial", DWRITE_FONT_STYLE_NORMAL);
6470 if (!font)
6471 skip("Skipping tests with Arial\n");
6472 else
6474 hr = IDWriteFont_CreateFontFace(font, &fontface);
6475 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6476 IDWriteFont_Release(font);
6478 test_gdicompat_metrics(fontface);
6479 IDWriteFontFace_Release(fontface);
6482 ref = IDWriteFactory_Release(factory);
6483 ok(ref == 0, "factory not released, %lu\n", ref);
6486 static void get_expected_panose(IDWriteFont1 *font, DWRITE_PANOSE *panose)
6488 const struct tt_os2 *tt_os2;
6489 IDWriteFontFace *fontface;
6490 void *os2_context;
6491 UINT32 size;
6492 BOOL exists;
6493 HRESULT hr;
6495 memset(panose, 0, sizeof(*panose));
6497 hr = IDWriteFont1_CreateFontFace(font, &fontface);
6498 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6500 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
6501 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6503 if (tt_os2) {
6504 memcpy(panose, &tt_os2->panose, sizeof(*panose));
6505 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
6508 IDWriteFontFace_Release(fontface);
6511 static void test_GetPanose(void)
6513 IDWriteFontCollection *syscollection;
6514 IDWriteFactory *factory;
6515 IDWriteFont1 *font1;
6516 IDWriteFont *font;
6517 UINT count, i;
6518 HRESULT hr;
6519 ULONG ref;
6521 factory = create_factory();
6522 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6524 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
6525 IDWriteFont_Release(font);
6527 if (FAILED(hr)) {
6528 ref = IDWriteFactory_Release(factory);
6529 ok(ref == 0, "factory not released, %lu\n", ref);
6530 win_skip("GetPanose() is not supported.\n");
6531 return;
6533 IDWriteFont1_Release(font1);
6535 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
6536 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6537 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
6539 for (i = 0; i < count; i++) {
6540 DWRITE_PANOSE panose, expected_panose;
6541 IDWriteLocalizedStrings *names;
6542 IDWriteFontFace3 *fontface3;
6543 IDWriteFontFace *fontface;
6544 IDWriteFontFamily *family;
6545 IDWriteFont1 *font1;
6546 IDWriteFont *font;
6547 WCHAR nameW[256];
6549 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
6550 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6552 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
6553 DWRITE_FONT_STYLE_NORMAL, &font);
6554 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6556 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
6557 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6558 IDWriteFont_Release(font);
6560 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
6561 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6563 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
6565 IDWriteLocalizedStrings_Release(names);
6567 IDWriteFont1_GetPanose(font1, &panose);
6568 get_expected_panose(font1, &expected_panose);
6570 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
6572 ok(panose.values[0] == expected_panose.values[0], "values[0] %#x, expected %#x.\n",
6573 panose.values[0], expected_panose.values[0]);
6574 ok(panose.values[1] == expected_panose.values[1], "values[1] %#x, expected %#x.\n",
6575 panose.values[1], expected_panose.values[1]);
6576 ok(panose.values[2] == expected_panose.values[2], "values[2] %#x, expected %#x.\n",
6577 panose.values[2], expected_panose.values[2]);
6578 ok(panose.values[3] == expected_panose.values[3], "values[3] %#x, expected %#x.\n",
6579 panose.values[3], expected_panose.values[3]);
6580 ok(panose.values[4] == expected_panose.values[4], "values[4] %#x, expected %#x.\n",
6581 panose.values[4], expected_panose.values[4]);
6582 ok(panose.values[5] == expected_panose.values[5], "values[5] %#x, expected %#x.\n",
6583 panose.values[5], expected_panose.values[5]);
6584 ok(panose.values[6] == expected_panose.values[6], "values[6] %#x, expected %#x.\n",
6585 panose.values[6], expected_panose.values[6]);
6586 ok(panose.values[7] == expected_panose.values[7], "values[7] %#x, expected %#x.\n",
6587 panose.values[7], expected_panose.values[7]);
6588 ok(panose.values[8] == expected_panose.values[8], "values[8] %#x, expected %#x.\n",
6589 panose.values[8], expected_panose.values[8]);
6590 ok(panose.values[9] == expected_panose.values[9], "values[9] %#x, expected %#x.\n",
6591 panose.values[9], expected_panose.values[9]);
6593 winetest_pop_context();
6595 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
6596 ok(hr == S_OK, "Failed to create a font face, %#lx.\n", hr);
6597 if (IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3) == S_OK) {
6598 ok(!memcmp(&panose, &expected_panose, sizeof(panose)), "%s: Unexpected panose from font face.\n",
6599 wine_dbgstr_w(nameW));
6600 IDWriteFontFace3_Release(fontface3);
6602 IDWriteFontFace_Release(fontface);
6604 IDWriteFont1_Release(font1);
6605 IDWriteFontFamily_Release(family);
6608 IDWriteFontCollection_Release(syscollection);
6609 ref = IDWriteFactory_Release(factory);
6610 ok(ref == 0, "factory not released, %lu\n", ref);
6613 static INT32 get_gdi_font_advance(HDC hdc, FLOAT emsize)
6615 LOGFONTW logfont;
6616 HFONT hfont;
6617 BOOL ret;
6618 ABC abc;
6620 memset(&logfont, 0, sizeof(logfont));
6621 logfont.lfHeight = (LONG)-emsize;
6622 logfont.lfWeight = FW_NORMAL;
6623 logfont.lfQuality = CLEARTYPE_QUALITY;
6624 lstrcpyW(logfont.lfFaceName, L"Tahoma");
6626 hfont = CreateFontIndirectW(&logfont);
6627 SelectObject(hdc, hfont);
6629 ret = GetCharABCWidthsW(hdc, 'A', 'A', &abc);
6630 ok(ret, "got %d\n", ret);
6632 DeleteObject(hfont);
6634 return abc.abcA + abc.abcB + abc.abcC;
6637 static void test_GetGdiCompatibleGlyphAdvances(void)
6639 IDWriteFontFace1 *fontface1;
6640 IDWriteFontFace *fontface;
6641 IDWriteFactory *factory;
6642 IDWriteFont *font;
6643 HRESULT hr;
6644 HDC hdc;
6645 UINT32 codepoint;
6646 UINT16 glyph;
6647 FLOAT emsize;
6648 DWRITE_FONT_METRICS1 fm;
6649 INT32 advance;
6650 ULONG ref;
6652 factory = create_factory();
6653 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6655 hr = IDWriteFont_CreateFontFace(font, &fontface);
6656 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6657 IDWriteFont_Release(font);
6659 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
6660 IDWriteFontFace_Release(fontface);
6662 if (hr != S_OK) {
6663 ref = IDWriteFactory_Release(factory);
6664 ok(ref == 0, "factory not released, %lu\n", ref);
6665 win_skip("GetGdiCompatibleGlyphAdvances() is not supported\n");
6666 return;
6669 codepoint = 'A';
6670 glyph = 0;
6671 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &glyph);
6672 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6673 ok(glyph > 0, "got %u\n", glyph);
6675 /* zero emsize */
6676 advance = 1;
6677 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 0.0,
6678 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6679 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6680 ok(advance == 0, "got %d\n", advance);
6682 /* negative emsize */
6683 advance = 1;
6684 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, -1.0,
6685 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6686 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6687 ok(advance == 0, "got %d\n", advance);
6689 /* zero ppdip */
6690 advance = 1;
6691 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
6692 0.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6693 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6694 ok(advance == 0, "got %d\n", advance);
6696 /* negative ppdip */
6697 advance = 1;
6698 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
6699 -1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6700 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6701 ok(advance == 0, "got %d\n", advance);
6703 IDWriteFontFace1_GetMetrics(fontface1, &fm);
6705 hdc = CreateCompatibleDC(0);
6707 for (emsize = 1.0; emsize <= fm.designUnitsPerEm; emsize += 1.0) {
6708 INT32 gdi_advance;
6710 gdi_advance = get_gdi_font_advance(hdc, emsize);
6711 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emsize,
6712 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6713 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6715 /* advance is in design units */
6716 advance = (int)floorf(emsize * advance / fm.designUnitsPerEm + 0.5f);
6717 ok((advance - gdi_advance) <= 2, "%.0f: got advance %d, expected %d\n", emsize, advance, gdi_advance);
6720 DeleteObject(hdc);
6722 IDWriteFontFace1_Release(fontface1);
6723 ref = IDWriteFactory_Release(factory);
6724 ok(ref == 0, "factory not released, %lu\n", ref);
6727 static WORD get_gasp_flags(IDWriteFontFace *fontface, FLOAT emsize, FLOAT ppdip)
6729 WORD num_recs, version;
6730 const WORD *ptr;
6731 WORD flags = 0;
6732 UINT32 size;
6733 BOOL exists;
6734 void *ctxt;
6735 HRESULT hr;
6737 emsize *= ppdip;
6739 exists = FALSE;
6740 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GASP_TAG,
6741 (const void**)&ptr, &size, &ctxt, &exists);
6742 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6744 if (!exists)
6745 goto done;
6747 version = GET_BE_WORD( *ptr++ );
6748 num_recs = GET_BE_WORD( *ptr++ );
6749 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
6750 ok(0, "unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
6751 goto done;
6754 while (num_recs--)
6756 flags = GET_BE_WORD( *(ptr + 1) );
6757 if (emsize <= GET_BE_WORD( *ptr )) break;
6758 ptr += 2;
6761 done:
6762 IDWriteFontFace_ReleaseFontTable(fontface, ctxt);
6763 return flags;
6766 #define GASP_GRIDFIT 0x0001
6767 #define GASP_DOGRAY 0x0002
6768 #define GASP_SYMMETRIC_GRIDFIT 0x0004
6769 #define GASP_SYMMETRIC_SMOOTHING 0x0008
6771 static BOOL g_is_vista;
6772 static DWRITE_RENDERING_MODE get_expected_rendering_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
6773 DWRITE_OUTLINE_THRESHOLD threshold)
6775 static const FLOAT aa_threshold = 100.0f;
6776 static const FLOAT a_threshold = 350.0f;
6777 static const FLOAT naturalemsize = 20.0f;
6778 FLOAT v;
6780 /* outline threshold */
6781 if (g_is_vista)
6782 v = mode == DWRITE_MEASURING_MODE_NATURAL ? aa_threshold : a_threshold;
6783 else
6784 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
6786 if (emsize >= v)
6787 return DWRITE_RENDERING_MODE_OUTLINE;
6789 switch (mode)
6791 case DWRITE_MEASURING_MODE_NATURAL:
6792 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (emsize <= naturalemsize))
6793 return DWRITE_RENDERING_MODE_NATURAL;
6794 else
6795 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
6796 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6797 return DWRITE_RENDERING_MODE_GDI_CLASSIC;
6798 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6799 return DWRITE_RENDERING_MODE_GDI_NATURAL;
6800 default:
6804 /* should be unreachable */
6805 return DWRITE_RENDERING_MODE_DEFAULT;
6808 static DWRITE_GRID_FIT_MODE get_expected_gridfit_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
6809 DWRITE_OUTLINE_THRESHOLD threshold)
6811 static const FLOAT aa_threshold = 100.0f;
6812 static const FLOAT a_threshold = 350.0f;
6813 FLOAT v;
6815 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
6816 if (emsize >= v)
6817 return DWRITE_GRID_FIT_MODE_DISABLED;
6819 if (mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
6820 return DWRITE_GRID_FIT_MODE_ENABLED;
6822 return (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
6825 struct recommendedmode_test
6827 DWRITE_MEASURING_MODE measuring;
6828 DWRITE_OUTLINE_THRESHOLD threshold;
6831 static const struct recommendedmode_test recmode_tests[] = {
6832 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6833 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6834 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6837 static const struct recommendedmode_test recmode_tests1[] = {
6838 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6839 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6840 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6841 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6842 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6843 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6846 static void test_GetRecommendedRenderingMode(void)
6848 IDWriteRenderingParams *params;
6849 IDWriteFontFace3 *fontface3;
6850 IDWriteFontFace2 *fontface2;
6851 IDWriteFontFace1 *fontface1;
6852 IDWriteFontFace *fontface;
6853 DWRITE_RENDERING_MODE mode;
6854 IDWriteFactory *factory;
6855 FLOAT emsize;
6856 HRESULT hr;
6857 ULONG ref;
6859 factory = create_factory();
6860 fontface = create_fontface(factory);
6862 fontface1 = NULL;
6863 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
6864 if (hr != S_OK)
6865 win_skip("IDWriteFontFace1::GetRecommendedRenderingMode() is not supported.\n");
6867 fontface2 = NULL;
6868 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6869 if (hr != S_OK)
6870 win_skip("IDWriteFontFace2::GetRecommendedRenderingMode() is not supported.\n");
6872 fontface3 = NULL;
6873 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
6874 if (hr != S_OK)
6875 win_skip("IDWriteFontFace3::GetRecommendedRenderingMode() is not supported.\n");
6877 if (0) /* crashes on native */
6878 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6879 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, NULL);
6881 mode = 10;
6882 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6883 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode);
6884 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6885 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
6887 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
6888 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6890 /* detect old dwrite version, that is using higher threshold value */
6891 g_is_vista = fontface1 == NULL;
6893 for (emsize = 1.0; emsize < 500.0; emsize += 1.0)
6895 DWRITE_RENDERING_MODE expected;
6896 unsigned int i;
6897 FLOAT ppdip;
6898 WORD gasp;
6900 winetest_push_context("Size %.2f", emsize);
6902 for (i = 0; i < ARRAY_SIZE(recmode_tests); ++i)
6904 winetest_push_context("%u", i);
6906 ppdip = 1.0f;
6907 mode = 10;
6908 gasp = get_gasp_flags(fontface, emsize, ppdip);
6909 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6910 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6911 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6912 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6914 /* some ppdip variants */
6915 ppdip = 0.5f;
6916 mode = 10;
6917 gasp = get_gasp_flags(fontface, emsize, ppdip);
6918 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6919 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6920 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6921 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6923 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6924 Win8 and Win10 handle this as expected. */
6925 if (emsize > 20.0f)
6927 ppdip = 1.5f;
6928 mode = 10;
6929 gasp = get_gasp_flags(fontface, emsize, ppdip);
6930 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6931 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6932 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6933 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6935 ppdip = 2.0f;
6936 mode = 10;
6937 gasp = get_gasp_flags(fontface, emsize, ppdip);
6938 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6939 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6940 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6941 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6944 winetest_pop_context();
6947 /* IDWriteFontFace1 offers another variant of this method */
6948 if (fontface1)
6950 for (i = 0; i < ARRAY_SIZE(recmode_tests1); ++i)
6952 FLOAT dpi;
6954 winetest_push_context("%u", i);
6956 ppdip = 1.0f;
6957 dpi = 96.0f * ppdip;
6958 mode = 10;
6959 gasp = get_gasp_flags(fontface, emsize, ppdip);
6960 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6961 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6962 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6963 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6964 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
6966 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6967 Win8 and Win10 handle this as expected. */
6968 if (emsize > 20.0f)
6970 ppdip = 2.0f;
6971 dpi = 96.0f * ppdip;
6972 mode = 10;
6973 gasp = get_gasp_flags(fontface, emsize, ppdip);
6974 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6975 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6976 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6977 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6978 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
6980 ppdip = 0.5f;
6981 dpi = 96.0f * ppdip;
6982 mode = 10;
6983 gasp = get_gasp_flags(fontface, emsize, ppdip);
6984 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6985 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6986 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6987 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6988 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
6990 /* try different dpis for X and Y direction */
6991 ppdip = 1.0f;
6992 dpi = 96.0f * ppdip;
6993 mode = 10;
6994 gasp = get_gasp_flags(fontface, emsize, ppdip);
6995 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6996 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6997 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6998 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6999 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
7001 ppdip = 1.0f;
7002 dpi = 96.0f * ppdip;
7003 mode = 10;
7004 gasp = get_gasp_flags(fontface, emsize, ppdip);
7005 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7006 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
7007 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
7008 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7009 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
7011 ppdip = 2.0f;
7012 dpi = 96.0f * ppdip;
7013 mode = 10;
7014 gasp = get_gasp_flags(fontface, emsize, ppdip);
7015 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7016 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
7017 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
7018 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7019 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
7021 ppdip = 2.0f;
7022 dpi = 96.0f * ppdip;
7023 mode = 10;
7024 gasp = get_gasp_flags(fontface, emsize, ppdip);
7025 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7026 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
7027 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
7028 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7029 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
7032 winetest_pop_context();
7036 /* IDWriteFontFace2 - another one */
7037 if (fontface2) {
7038 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
7040 gasp = get_gasp_flags(fontface, emsize, 1.0f);
7041 for (i = 0; i < ARRAY_SIZE(recmode_tests1); ++i)
7043 winetest_push_context("%u", i);
7045 mode = 10;
7046 expected = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7047 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7048 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, emsize, 96.0f, 96.0f,
7049 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode, &gridfit);
7050 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7051 ok(mode == expected, "got %d, flags 0x%04x, expected %d.\n", mode, gasp, expected);
7052 ok(gridfit == expected_gridfit, "gridfit: got %d, flags 0x%04x, expected %d.\n", gridfit, gasp, expected_gridfit);
7054 winetest_pop_context();
7058 /* IDWriteFontFace3 - and another one */
7059 if (fontface3) {
7060 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
7061 DWRITE_RENDERING_MODE1 mode1;
7062 unsigned int expected1;
7064 gasp = get_gasp_flags(fontface, emsize, 1.0f);
7065 for (i = 0; i < ARRAY_SIZE(recmode_tests1); ++i)
7067 winetest_push_context("%u", i);
7069 mode1 = 10;
7070 expected1 = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7071 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7072 hr = IDWriteFontFace3_GetRecommendedRenderingMode(fontface3, emsize, 96.0f, 96.0f,
7073 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode1, &gridfit);
7074 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7075 ok(mode1 == expected1, "got %d, flags 0x%04x, expected %d.\n", mode1, gasp, expected1);
7076 ok(gridfit == expected_gridfit, "gridfit: got %d, flags 0x%04x, expected %d.\n", gridfit, gasp, expected_gridfit);
7078 winetest_pop_context();
7082 winetest_pop_context();
7085 IDWriteRenderingParams_Release(params);
7087 /* test how parameters override returned modes */
7088 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
7089 DWRITE_RENDERING_MODE_GDI_CLASSIC, &params);
7090 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7092 mode = 10;
7093 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode);
7094 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7095 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7097 IDWriteRenderingParams_Release(params);
7099 if (fontface2) {
7100 IDWriteRenderingParams2 *params2;
7101 IDWriteFactory2 *factory2;
7102 DWRITE_GRID_FIT_MODE gridfit;
7104 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
7105 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7107 hr = IDWriteFactory2_CreateCustomRenderingParams(factory2, 1.0, 0.0, 0.0, 0.5, DWRITE_PIXEL_GEOMETRY_FLAT,
7108 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_GRID_FIT_MODE_ENABLED, &params2);
7109 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7111 mode = 10;
7112 gridfit = 10;
7113 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
7114 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7115 NULL, &mode, &gridfit);
7116 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7117 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7118 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7120 mode = 10;
7121 gridfit = 10;
7122 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
7123 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7124 (IDWriteRenderingParams*)params2, &mode, &gridfit);
7125 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7126 ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode);
7127 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7129 IDWriteRenderingParams2_Release(params2);
7130 IDWriteFactory2_Release(factory2);
7133 if (fontface3) {
7134 IDWriteRenderingParams3 *params3;
7135 IDWriteRenderingParams2 *params2;
7136 IDWriteRenderingParams *params;
7137 IDWriteFactory3 *factory3;
7138 DWRITE_GRID_FIT_MODE gridfit;
7139 DWRITE_RENDERING_MODE1 mode1;
7141 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
7142 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7144 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 0.5f, DWRITE_PIXEL_GEOMETRY_FLAT,
7145 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_ENABLED, &params3);
7146 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7148 mode1 = IDWriteRenderingParams3_GetRenderingMode1(params3);
7149 ok(mode1 == DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, "got %d\n", mode1);
7151 mode = IDWriteRenderingParams3_GetRenderingMode(params3);
7152 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7154 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
7155 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7156 ok(params == (IDWriteRenderingParams*)params3, "got %p, %p\n", params3, params);
7157 mode = IDWriteRenderingParams_GetRenderingMode(params);
7158 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7159 IDWriteRenderingParams_Release(params);
7161 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams2, (void**)&params2);
7162 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7163 ok(params2 == (IDWriteRenderingParams2*)params3, "got %p, %p\n", params3, params2);
7164 mode = IDWriteRenderingParams2_GetRenderingMode(params2);
7165 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7166 IDWriteRenderingParams2_Release(params2);
7168 mode = 10;
7169 gridfit = 10;
7170 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
7171 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7172 NULL, &mode, &gridfit);
7173 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7174 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7175 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7177 mode = 10;
7178 gridfit = 10;
7179 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
7180 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7181 (IDWriteRenderingParams*)params3, &mode, &gridfit);
7182 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7183 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7184 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7186 IDWriteRenderingParams3_Release(params3);
7187 IDWriteFactory3_Release(factory3);
7190 if (fontface3)
7191 IDWriteFontFace3_Release(fontface3);
7192 if (fontface2)
7193 IDWriteFontFace2_Release(fontface2);
7194 if (fontface1)
7195 IDWriteFontFace1_Release(fontface1);
7196 IDWriteFontFace_Release(fontface);
7197 ref = IDWriteFactory_Release(factory);
7198 ok(ref == 0, "factory not released, %lu\n", ref);
7201 static inline BOOL float_eq(FLOAT left, FLOAT right)
7203 int x = *(int *)&left;
7204 int y = *(int *)&right;
7206 if (x < 0)
7207 x = INT_MIN - x;
7208 if (y < 0)
7209 y = INT_MIN - y;
7211 return abs(x - y) <= 8;
7214 static void test_GetAlphaBlendParams(void)
7216 static const DWRITE_RENDERING_MODE rendermodes[] = {
7217 DWRITE_RENDERING_MODE_ALIASED,
7218 DWRITE_RENDERING_MODE_GDI_CLASSIC,
7219 DWRITE_RENDERING_MODE_GDI_NATURAL,
7220 DWRITE_RENDERING_MODE_NATURAL,
7221 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
7224 IDWriteGlyphRunAnalysis *analysis;
7225 FLOAT gamma, contrast, ctlevel;
7226 IDWriteRenderingParams *params;
7227 DWRITE_GLYPH_METRICS metrics;
7228 DWRITE_GLYPH_OFFSET offset;
7229 IDWriteFontFace *fontface;
7230 IDWriteFactory *factory;
7231 DWRITE_GLYPH_RUN run;
7232 FLOAT advance, expected_gdi_gamma;
7233 UINT value = 0;
7234 UINT16 glyph;
7235 UINT32 ch, i;
7236 HRESULT hr;
7237 ULONG ref;
7238 BOOL ret;
7240 factory = create_factory();
7241 fontface = create_fontface(factory);
7243 ch = 'A';
7244 glyph = 0;
7245 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
7246 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7247 ok(glyph > 0, "got %u\n", glyph);
7249 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
7250 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7251 advance = metrics.advanceWidth;
7253 offset.advanceOffset = 0.0;
7254 offset.ascenderOffset = 0.0;
7256 run.fontFace = fontface;
7257 run.fontEmSize = 24.0;
7258 run.glyphCount = 1;
7259 run.glyphIndices = &glyph;
7260 run.glyphAdvances = &advance;
7261 run.glyphOffsets = &offset;
7262 run.isSideways = FALSE;
7263 run.bidiLevel = 0;
7265 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.9, 0.3, 0.1, DWRITE_PIXEL_GEOMETRY_RGB,
7266 DWRITE_RENDERING_MODE_DEFAULT, &params);
7267 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7269 value = 0;
7270 ret = SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
7271 ok(ret, "got %d\n", ret);
7272 expected_gdi_gamma = (FLOAT)(value / 1000.0);
7274 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
7275 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7276 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
7277 0.0, 0.0, &analysis);
7278 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7280 gamma = contrast = ctlevel = -1.0;
7281 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, NULL, &gamma, &contrast, &ctlevel);
7282 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7283 ok(gamma == -1.0, "got %.2f\n", gamma);
7284 ok(contrast == -1.0, "got %.2f\n", contrast);
7285 ok(ctlevel == -1.0, "got %.2f\n", ctlevel);
7287 gamma = contrast = ctlevel = -1.0;
7288 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &ctlevel);
7289 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7291 if (rendermodes[i] == DWRITE_RENDERING_MODE_GDI_CLASSIC || rendermodes[i] == DWRITE_RENDERING_MODE_GDI_NATURAL) {
7292 ok(float_eq(gamma, expected_gdi_gamma), "got %.2f, expected %.2f\n", gamma, expected_gdi_gamma);
7293 ok(contrast == 0.0f, "got %.2f\n", contrast);
7294 ok(ctlevel == 1.0f, "got %.2f\n", ctlevel);
7296 else {
7297 ok(gamma == 0.9f, "got %.2f\n", gamma);
7298 ok(contrast == 0.3f, "got %.2f\n", contrast);
7299 ok(ctlevel == 0.1f, "got %.2f\n", ctlevel);
7302 IDWriteGlyphRunAnalysis_Release(analysis);
7305 IDWriteRenderingParams_Release(params);
7306 IDWriteFontFace_Release(fontface);
7307 ref = IDWriteFactory_Release(factory);
7308 ok(ref == 0, "factory not released, %lu\n", ref);
7311 static void test_CreateAlphaTexture(void)
7313 IDWriteGlyphRunAnalysis *analysis;
7314 DWRITE_GLYPH_METRICS metrics;
7315 DWRITE_GLYPH_OFFSET offset;
7316 IDWriteFontFace *fontface;
7317 IDWriteFactory *factory;
7318 DWRITE_GLYPH_RUN run;
7319 UINT32 ch, size;
7320 BYTE buff[1024];
7321 RECT bounds, r;
7322 FLOAT advance;
7323 UINT16 glyph;
7324 HRESULT hr;
7325 ULONG ref;
7327 factory = create_factory();
7328 fontface = create_fontface(factory);
7330 ch = 'A';
7331 glyph = 0;
7332 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
7333 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7334 ok(glyph > 0, "got %u\n", glyph);
7336 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
7337 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7338 advance = metrics.advanceWidth;
7340 offset.advanceOffset = 0.0;
7341 offset.ascenderOffset = 0.0;
7343 run.fontFace = fontface;
7344 run.fontEmSize = 24.0;
7345 run.glyphCount = 1;
7346 run.glyphIndices = &glyph;
7347 run.glyphAdvances = &advance;
7348 run.glyphOffsets = &offset;
7349 run.isSideways = FALSE;
7350 run.bidiLevel = 0;
7352 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7353 DWRITE_RENDERING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
7354 0.0, 0.0, &analysis);
7355 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7357 SetRectEmpty(&bounds);
7358 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
7359 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7360 ok(!IsRectEmpty(&bounds), "got empty rect\n");
7361 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top)*3;
7362 ok(sizeof(buff) >= size, "required %u\n", size);
7364 /* invalid type value */
7365 memset(buff, 0xcf, sizeof(buff));
7366 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &bounds, buff, sizeof(buff));
7367 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7368 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7370 memset(buff, 0xcf, sizeof(buff));
7371 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, 2);
7372 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7373 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7375 /* vista version allows texture type mismatch, mark it broken for now */
7376 memset(buff, 0xcf, sizeof(buff));
7377 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, sizeof(buff));
7378 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr);
7379 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
7381 memset(buff, 0xcf, sizeof(buff));
7382 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, size-1);
7383 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7384 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7386 IDWriteGlyphRunAnalysis_Release(analysis);
7388 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7389 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7390 0.0, 0.0, &analysis);
7391 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7393 SetRectEmpty(&bounds);
7394 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
7395 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7396 ok(!IsRectEmpty(&bounds), "got empty rect\n");
7397 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
7398 ok(sizeof(buff) >= size, "required %u\n", size);
7400 memset(buff, 0xcf, sizeof(buff));
7401 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, sizeof(buff));
7402 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7403 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7405 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, NULL, sizeof(buff));
7406 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7408 memset(buff, 0xcf, sizeof(buff));
7409 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, 0);
7410 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7411 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7413 /* buffer size is not enough */
7414 memset(buff, 0xcf, sizeof(buff));
7415 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, size-1);
7416 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7417 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7419 /* request texture for rectangle that doesn't intersect */
7420 memset(buff, 0xcf, sizeof(buff));
7421 r = bounds;
7422 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7423 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
7424 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7425 ok(buff[0] == 0, "got %1x\n", buff[0]);
7427 memset(buff, 0xcf, sizeof(buff));
7428 r = bounds;
7429 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7430 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
7431 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7432 ok(buff[0] == 0, "got %1x\n", buff[0]);
7434 /* request texture for rectangle that doesn't intersect, small buffer */
7435 memset(buff, 0xcf, sizeof(buff));
7436 r = bounds;
7437 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7438 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, size-1);
7439 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7440 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7442 /* vista version allows texture type mismatch, mark it broken for now */
7443 memset(buff, 0xcf, sizeof(buff));
7444 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, sizeof(buff));
7445 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr);
7446 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
7448 IDWriteGlyphRunAnalysis_Release(analysis);
7449 IDWriteFontFace_Release(fontface);
7450 ref = IDWriteFactory_Release(factory);
7451 ok(ref == 0, "factory not released, %lu\n", ref);
7454 static BOOL get_expected_is_symbol(IDWriteFontFace *fontface)
7456 BOOL exists, is_symbol = FALSE;
7457 struct dwrite_fonttable cmap;
7458 const struct tt_os2 *tt_os2;
7459 const BYTE *tables;
7460 void *os2_context;
7461 WORD num_tables;
7462 unsigned int i;
7463 UINT32 size;
7464 HRESULT hr;
7466 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
7467 ok(hr == S_OK, "Failed to get OS/2 table, hr %#lx.\n", hr);
7469 if (tt_os2)
7471 is_symbol = tt_os2->panose.bFamilyType == PAN_FAMILY_PICTORIAL;
7472 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
7475 if (is_symbol)
7476 return is_symbol;
7478 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, (const void **)&cmap.data,
7479 &cmap.size, &cmap.context, &exists);
7480 if (FAILED(hr) || !exists)
7481 return is_symbol;
7483 num_tables = table_read_be_word(&cmap, 0, FIELD_OFFSET(struct cmap_header, num_tables));
7484 tables = cmap.data + FIELD_OFFSET(struct cmap_header, tables);
7486 for (i = 0; i < num_tables; ++i)
7488 struct cmap_encoding_record *record = (struct cmap_encoding_record *)(tables + i * sizeof(*record));
7489 WORD platform, encoding;
7491 platform = table_read_be_word(&cmap, record, FIELD_OFFSET(struct cmap_encoding_record, platformID));
7492 encoding = table_read_be_word(&cmap, record, FIELD_OFFSET(struct cmap_encoding_record, encodingID));
7494 if (platform == OPENTYPE_CMAP_TABLE_PLATFORM_WIN && encoding == OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL)
7496 is_symbol = TRUE;
7497 break;
7501 IDWriteFontFace_ReleaseFontTable(fontface, cmap.context);
7503 return is_symbol;
7506 static void test_IsSymbolFont(void)
7508 IDWriteFontCollection *collection;
7509 IDWriteFontFace *fontface;
7510 IDWriteFactory *factory;
7511 IDWriteFont *font;
7512 UINT32 count, i;
7513 HRESULT hr;
7514 ULONG ref;
7516 factory = create_factory();
7518 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
7519 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7521 count = IDWriteFontCollection_GetFontFamilyCount(collection);
7522 for (i = 0; i < count; ++i)
7524 IDWriteLocalizedStrings *names;
7525 IDWriteFontFamily *family;
7526 UINT32 font_count, j;
7527 WCHAR nameW[256];
7529 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
7530 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
7532 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7533 ok(hr == S_OK, "Failed to get names, hr %#lx.\n", hr);
7534 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
7535 IDWriteLocalizedStrings_Release(names);
7537 font_count = IDWriteFontFamily_GetFontCount(family);
7539 for (j = 0; j < font_count; ++j)
7541 BOOL is_symbol_font, is_symbol_face, is_symbol_expected;
7543 hr = IDWriteFontFamily_GetFont(family, j, &font);
7544 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
7546 hr = IDWriteFont_CreateFontFace(font, &fontface);
7547 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
7549 is_symbol_font = IDWriteFont_IsSymbolFont(font);
7550 is_symbol_face = IDWriteFontFace_IsSymbolFont(fontface);
7551 ok(is_symbol_font == is_symbol_face, "Unexpected symbol flag.\n");
7553 is_symbol_expected = get_expected_is_symbol(fontface);
7554 ok(is_symbol_expected == is_symbol_face, "Unexpected is_symbol flag %d for %s, font %d.\n",
7555 is_symbol_face, wine_dbgstr_w(nameW), j);
7557 IDWriteFontFace_Release(fontface);
7558 IDWriteFont_Release(font);
7561 IDWriteFontFamily_Release(family);
7564 IDWriteFontCollection_Release(collection);
7566 ref = IDWriteFactory_Release(factory);
7567 ok(ref == 0, "factory not released, %lu\n", ref);
7570 struct CPAL_Header_0
7572 USHORT version;
7573 USHORT numPaletteEntries;
7574 USHORT numPalette;
7575 USHORT numColorRecords;
7576 ULONG offsetFirstColorRecord;
7577 USHORT colorRecordIndices[1];
7580 static void test_GetPaletteEntries(void)
7582 IDWriteFontFace2 *fontface2;
7583 IDWriteFontFace *fontface;
7584 IDWriteFactory *factory;
7585 IDWriteFont *font;
7586 DWRITE_COLOR_F color;
7587 UINT32 palettecount, entrycount, size, colorrecords;
7588 void *ctxt;
7589 const struct CPAL_Header_0 *cpal_header;
7590 HRESULT hr;
7591 BOOL exists;
7592 ULONG ref;
7594 factory = create_factory();
7596 /* Tahoma, no color support */
7597 fontface = create_fontface(factory);
7598 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7599 IDWriteFontFace_Release(fontface);
7600 if (hr != S_OK) {
7601 ref = IDWriteFactory_Release(factory);
7602 ok(ref == 0, "factory not released, %lu\n", ref);
7603 win_skip("GetPaletteEntries() is not supported.\n");
7604 return;
7607 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 1, &color);
7608 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7609 IDWriteFontFace2_Release(fontface2);
7611 /* Segoe UI Emoji, with color support */
7612 font = get_font(factory, L"Segoe UI Emoji", DWRITE_FONT_STYLE_NORMAL);
7613 if (!font) {
7614 ref = IDWriteFactory_Release(factory);
7615 ok(ref == 0, "factory not released, %lu\n", ref);
7616 skip("Segoe UI Emoji font not found.\n");
7617 return;
7620 hr = IDWriteFont_CreateFontFace(font, &fontface);
7621 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7622 IDWriteFont_Release(font);
7624 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7625 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7626 IDWriteFontFace_Release(fontface);
7628 palettecount = IDWriteFontFace2_GetColorPaletteCount(fontface2);
7629 ok(palettecount >= 1, "got %u\n", palettecount);
7631 entrycount = IDWriteFontFace2_GetPaletteEntryCount(fontface2);
7632 ok(entrycount >= 1, "got %u\n", entrycount);
7634 exists = FALSE;
7635 hr = IDWriteFontFace2_TryGetFontTable(fontface2, MS_CPAL_TAG, (const void**)&cpal_header, &size, &ctxt, &exists);
7636 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7637 ok(exists, "got %d\n", exists);
7638 colorrecords = GET_BE_WORD(cpal_header->numColorRecords);
7639 ok(colorrecords >= 1, "got %u\n", colorrecords);
7641 /* invalid palette index */
7642 color.r = color.g = color.b = color.a = 123.0;
7643 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, palettecount, 0, 1, &color);
7644 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7645 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
7646 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7648 /* invalid entry index */
7649 color.r = color.g = color.b = color.a = 123.0;
7650 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount, 1, &color);
7651 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7652 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
7653 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7655 color.r = color.g = color.b = color.a = 123.0;
7656 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount - 1, 1, &color);
7657 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7658 ok(color.r != 123.0 && color.g != 123.0 && color.b != 123.0 && color.a != 123.0,
7659 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7661 /* zero return length */
7662 color.r = color.g = color.b = color.a = 123.0;
7663 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 0, &color);
7664 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7665 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
7666 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7668 IDWriteFontFace2_Release(fontface2);
7669 ref = IDWriteFactory_Release(factory);
7670 ok(ref == 0, "factory not released, %lu\n", ref);
7673 static void test_TranslateColorGlyphRun(void)
7675 IDWriteColorGlyphRunEnumerator1 *layers1;
7676 IDWriteColorGlyphRunEnumerator *layers;
7677 const DWRITE_COLOR_GLYPH_RUN1 *colorrun1;
7678 const DWRITE_COLOR_GLYPH_RUN *colorrun;
7679 IDWriteFontFace2 *fontface2;
7680 IDWriteFontFace *fontface;
7681 IDWriteFactory4 *factory4;
7682 IDWriteFactory2 *factory;
7683 DWRITE_GLYPH_RUN run;
7684 UINT32 codepoints[2];
7685 IDWriteFont *font;
7686 UINT16 glyphs[2];
7687 BOOL hasrun;
7688 HRESULT hr;
7689 ULONG ref;
7691 factory = create_factory_iid(&IID_IDWriteFactory2);
7692 if (!factory) {
7693 win_skip("TranslateColorGlyphRun() is not supported.\n");
7694 return;
7697 /* Tahoma, no color support */
7698 fontface = create_fontface((IDWriteFactory *)factory);
7700 codepoints[0] = 'A';
7701 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7702 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7704 run.fontFace = fontface;
7705 run.fontEmSize = 20.0f;
7706 run.glyphCount = 1;
7707 run.glyphIndices = glyphs;
7708 run.glyphAdvances = NULL;
7709 run.glyphOffsets = NULL;
7710 run.isSideways = FALSE;
7711 run.bidiLevel = 0;
7713 layers = (void*)0xdeadbeef;
7714 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7715 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7716 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7717 ok(layers == NULL, "got %p\n", layers);
7718 IDWriteFontFace_Release(fontface);
7720 /* Segoe UI Emoji, with color support */
7721 font = get_font((IDWriteFactory *)factory, L"Segoe UI Emoji", DWRITE_FONT_STYLE_NORMAL);
7722 if (!font) {
7723 IDWriteFactory2_Release(factory);
7724 skip("Segoe UI Emoji font not found.\n");
7725 return;
7728 hr = IDWriteFont_CreateFontFace(font, &fontface);
7729 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7730 IDWriteFont_Release(font);
7732 codepoints[0] = 0x26c4;
7733 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7734 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7736 run.fontFace = fontface;
7738 layers = NULL;
7739 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7740 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7741 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7742 ok(layers != NULL, "got %p\n", layers);
7744 hr = IDWriteColorGlyphRunEnumerator_QueryInterface(layers, &IID_IDWriteColorGlyphRunEnumerator1, (void **)&layers1);
7745 if (FAILED(hr))
7747 layers1 = NULL;
7748 win_skip("IDWriteColorGlyphRunEnumerator1 is not supported.\n");
7751 for (;;)
7753 hasrun = FALSE;
7754 hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &hasrun);
7755 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7757 if (!hasrun)
7758 break;
7760 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
7761 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7762 ok(colorrun->glyphRun.fontFace == fontface, "Unexpected fontface %p.\n", colorrun->glyphRun.fontFace);
7763 ok(colorrun->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun->glyphRun.fontEmSize);
7764 ok(colorrun->glyphRun.glyphCount == 1, "Unexpected glyph count %u.\n", colorrun->glyphRun.glyphCount);
7765 ok(colorrun->glyphRun.glyphIndices != NULL, "got null glyph indices %p\n", colorrun->glyphRun.glyphIndices);
7766 ok(colorrun->glyphRun.glyphAdvances != NULL, "got null glyph advances %p\n", colorrun->glyphRun.glyphAdvances);
7767 ok(!colorrun->glyphRunDescription, "Unexpected description pointer.\n");
7769 if (layers1)
7771 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7772 ok(hr == S_OK, "Failed to get color runt, hr %#lx.\n", hr);
7773 ok((const DWRITE_COLOR_GLYPH_RUN *)colorrun1 == colorrun, "Unexpected pointer.\n");
7774 ok(colorrun1->glyphImageFormat == (DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE | DWRITE_GLYPH_IMAGE_FORMATS_COLR) ||
7775 colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_NONE,
7776 "Unexpected glyph image format %#x.\n", colorrun1->glyphImageFormat);
7777 ok(colorrun1->measuringMode == DWRITE_MEASURING_MODE_NATURAL, "Unexpected measuring mode %d.\n",
7778 colorrun1->measuringMode);
7782 /* iterated all way through */
7783 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
7784 ok(hr == E_NOT_VALID_STATE, "Unexpected hr %#lx.\n", hr);
7786 if (layers1)
7788 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7789 ok(hr == E_NOT_VALID_STATE, "Unexpected hr %#lx.\n", hr);
7792 IDWriteColorGlyphRunEnumerator_Release(layers);
7793 if (layers1)
7794 IDWriteColorGlyphRunEnumerator1_Release(layers1);
7796 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7797 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7799 /* invalid palette index */
7800 layers = (void*)0xdeadbeef;
7801 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7802 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2),
7803 &layers);
7804 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7805 ok(layers == NULL, "got %p\n", layers);
7807 layers = NULL;
7808 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7809 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2) - 1,
7810 &layers);
7811 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7812 IDWriteColorGlyphRunEnumerator_Release(layers);
7814 /* color font, glyph without color info */
7815 codepoints[0] = 'A';
7816 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7817 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7818 ok(!!*glyphs, "Unexpected glyph.\n");
7820 layers = (void*)0xdeadbeef;
7821 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7822 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7823 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7824 ok(layers == NULL, "got %p\n", layers);
7826 /* one glyph with, one without */
7827 codepoints[0] = 'A';
7828 codepoints[1] = 0x26c4;
7830 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 2, glyphs);
7831 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7833 run.glyphCount = 2;
7835 layers = NULL;
7836 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7837 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7838 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7839 ok(layers != NULL, "got %p\n", layers);
7841 hr = IDWriteColorGlyphRunEnumerator_QueryInterface(layers, &IID_IDWriteColorGlyphRunEnumerator1, (void **)&layers1);
7842 if (SUCCEEDED(hr))
7844 for (;;)
7846 hasrun = FALSE;
7847 hr = IDWriteColorGlyphRunEnumerator1_MoveNext(layers1, &hasrun);
7848 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7850 if (!hasrun)
7851 break;
7853 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7854 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7855 ok(!!colorrun1->glyphRun.fontFace, "Unexpected fontface %p.\n", colorrun1->glyphRun.fontFace);
7856 ok(colorrun1->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun1->glyphRun.fontEmSize);
7857 ok(colorrun1->glyphRun.glyphCount > 0, "Unexpected glyph count %u.\n", colorrun1->glyphRun.glyphCount);
7858 ok(!!colorrun1->glyphRun.glyphIndices, "Unexpected indices %p.\n", colorrun1->glyphRun.glyphIndices);
7859 ok(!!colorrun1->glyphRun.glyphAdvances, "Unexpected advances %p.\n", colorrun1->glyphRun.glyphAdvances);
7860 ok(!colorrun1->glyphRunDescription, "Unexpected description pointer.\n");
7861 todo_wine
7862 ok(colorrun1->glyphImageFormat == (DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE | DWRITE_GLYPH_IMAGE_FORMATS_COLR) ||
7863 colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE, "Unexpected glyph image format %#x.\n",
7864 colorrun1->glyphImageFormat);
7865 ok(colorrun1->measuringMode == DWRITE_MEASURING_MODE_NATURAL, "Unexpected measuring mode %d.\n",
7866 colorrun1->measuringMode);
7869 IDWriteColorGlyphRunEnumerator1_Release(layers1);
7871 IDWriteColorGlyphRunEnumerator_Release(layers);
7873 if (SUCCEEDED(IDWriteFactory2_QueryInterface(factory, &IID_IDWriteFactory4, (void **)&factory4)))
7875 D2D1_POINT_2F origin;
7877 origin.x = origin.y = 0.0f;
7878 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7879 DWRITE_GLYPH_IMAGE_FORMATS_NONE, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7880 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7882 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7883 DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7884 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7886 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7887 DWRITE_GLYPH_IMAGE_FORMATS_CFF, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7888 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7890 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7891 DWRITE_GLYPH_IMAGE_FORMATS_COLR, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7892 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7894 for (;;)
7896 hasrun = FALSE;
7897 hr = IDWriteColorGlyphRunEnumerator1_MoveNext(layers1, &hasrun);
7898 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7900 if (!hasrun)
7901 break;
7903 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7904 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7905 ok(!!colorrun1->glyphRun.fontFace, "Unexpected fontface %p.\n", colorrun1->glyphRun.fontFace);
7906 ok(colorrun1->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun1->glyphRun.fontEmSize);
7907 ok(colorrun1->glyphRun.glyphCount > 0, "Unexpected glyph count %u.\n", colorrun1->glyphRun.glyphCount);
7908 ok(!!colorrun1->glyphRun.glyphIndices, "Unexpected indices %p.\n", colorrun1->glyphRun.glyphIndices);
7909 ok(!!colorrun1->glyphRun.glyphAdvances, "Unexpected advances %p.\n", colorrun1->glyphRun.glyphAdvances);
7910 ok(!colorrun1->glyphRunDescription, "Unexpected description pointer.\n");
7911 ok(colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_COLR ||
7912 colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_NONE, "Unexpected glyph image format %#x.\n",
7913 colorrun1->glyphImageFormat);
7914 ok(colorrun1->measuringMode == DWRITE_MEASURING_MODE_NATURAL, "Unexpected measuring mode %d.\n",
7915 colorrun1->measuringMode);
7918 IDWriteColorGlyphRunEnumerator1_Release(layers1);
7920 IDWriteFactory4_Release(factory4);
7922 else
7923 win_skip("IDWriteFactory4::TranslateColorGlyphRun() is not supported.\n");
7925 IDWriteFontFace2_Release(fontface2);
7926 IDWriteFontFace_Release(fontface);
7927 ref = IDWriteFactory2_Release(factory);
7928 ok(ref == 0, "factory not released, %lu\n", ref);
7931 static void test_HasCharacter(void)
7933 IDWriteFactory3 *factory3;
7934 IDWriteFactory *factory;
7935 IDWriteFont3 *font3;
7936 IDWriteFont *font;
7937 HRESULT hr;
7938 ULONG ref;
7939 BOOL ret;
7941 factory = create_factory();
7943 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
7944 ok(font != NULL, "failed to create font\n");
7946 /* Win8 is broken, QI claims to support IDWriteFont3, but in fact it does not */
7947 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
7948 if (hr == S_OK) {
7949 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
7950 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7952 ret = IDWriteFont3_HasCharacter(font3, 'A');
7953 ok(ret, "got %d\n", ret);
7955 IDWriteFont3_Release(font3);
7956 IDWriteFactory3_Release(factory3);
7958 else
7959 win_skip("IDWriteFont3 is not supported.\n");
7961 IDWriteFont_Release(font);
7962 ref = IDWriteFactory_Release(factory);
7963 ok(ref == 0, "factory not released, %lu\n", ref);
7966 static BOOL has_main_axis_values(const DWRITE_FONT_AXIS_VALUE *values, unsigned int count)
7968 BOOL has_wght = FALSE, has_wdth = FALSE, has_ital = FALSE, has_slnt = FALSE;
7969 unsigned int i;
7971 for (i = 0; i < count; ++i)
7973 if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT)
7974 has_wght = TRUE;
7975 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_WIDTH)
7976 has_wdth = TRUE;
7977 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_ITALIC)
7978 has_ital = TRUE;
7979 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_SLANT)
7980 has_slnt = TRUE;
7983 return has_wght && has_wdth && has_ital && has_slnt;
7986 static void test_CreateFontFaceReference(void)
7988 IDWriteFontFaceReference *ref, *ref1, *ref3;
7989 IDWriteFontFace3 *fontface, *fontface1;
7990 DWRITE_FONT_AXIS_VALUE axis_values[16];
7991 IDWriteFontCollection1 *collection;
7992 UINT32 axis_count, index, count, i;
7993 IDWriteFontFaceReference1 *ref2;
7994 IDWriteFontFile *file, *file1;
7995 IDWriteFactory3 *factory;
7996 IDWriteFont3 *font3;
7997 ULONG refcount;
7998 WCHAR *path;
7999 HRESULT hr;
8000 BOOL ret;
8002 factory = create_factory_iid(&IID_IDWriteFactory3);
8003 if (!factory) {
8004 win_skip("CreateFontFaceReference() is not supported.\n");
8005 return;
8008 path = create_testfontfile(test_fontfile);
8010 hr = IDWriteFactory3_CreateFontFaceReference(factory, NULL, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8011 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
8013 /* out of range simulation flags */
8014 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, ~0u, &ref);
8015 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
8017 /* test file is not a collection, but reference could still be created with non-zero face index */
8018 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8019 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8021 index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
8022 ok(index == 1, "got %u\n", index);
8024 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
8025 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8026 IDWriteFontFile_Release(file);
8028 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
8029 todo_wine
8030 ok(hr == DWRITE_E_FILEFORMAT, "Unexpected hr %#lx.\n", hr);
8032 IDWriteFontFaceReference_Release(ref);
8034 /* path however has to be valid */
8035 hr = IDWriteFactory3_CreateFontFaceReference(factory, L"dummy", NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8036 todo_wine
8037 ok(hr == DWRITE_E_FILENOTFOUND, "Unexpected hr %#lx.\n", hr);
8038 if (hr == S_OK)
8039 IDWriteFontFaceReference_Release(ref);
8041 EXPECT_REF(factory, 1);
8042 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8043 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8044 EXPECT_REF(factory, 2);
8046 /* new file is returned */
8047 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
8048 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8050 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
8051 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8052 ok(file != file1, "got %p, previous file %p\n", file1, file);
8054 IDWriteFontFile_Release(file);
8055 IDWriteFontFile_Release(file1);
8057 /* references are not reused */
8058 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
8059 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8060 ok(ref1 != ref, "got %p, previous ref %p\n", ref1, ref);
8062 /* created fontfaces are cached */
8063 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
8064 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8066 hr = IDWriteFontFaceReference_CreateFontFace(ref1, &fontface1);
8067 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8068 ok(fontface == fontface1, "got %p, expected %p\n", fontface1, fontface);
8069 IDWriteFontFace3_Release(fontface);
8070 IDWriteFontFace3_Release(fontface1);
8072 /* reference equality */
8073 ret = IDWriteFontFaceReference_Equals(ref, ref1);
8074 ok(ret, "got %d\n", ret);
8075 IDWriteFontFaceReference_Release(ref1);
8077 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
8078 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8079 ret = IDWriteFontFaceReference_Equals(ref, ref1);
8080 ok(!ret, "got %d\n", ret);
8081 IDWriteFontFaceReference_Release(ref1);
8083 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_BOLD, &ref1);
8084 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8085 ret = IDWriteFontFaceReference_Equals(ref, ref1);
8086 ok(!ret, "got %d\n", ret);
8087 IDWriteFontFaceReference_Release(ref1);
8089 IDWriteFontFaceReference_Release(ref);
8091 /* create reference from a file */
8092 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
8093 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8095 hr = IDWriteFactory3_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8096 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8098 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
8099 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8100 ok(file != file1, "got %p, previous file %p\n", file1, file);
8102 if (SUCCEEDED(IDWriteFontFaceReference_QueryInterface(ref, &IID_IDWriteFontFaceReference1, (void **)&ref2)))
8104 axis_count = IDWriteFontFaceReference1_GetFontAxisValueCount(ref2);
8105 ok(!axis_count, "Unexpected axis value count.\n");
8106 IDWriteFontFaceReference1_Release(ref2);
8109 IDWriteFontFaceReference_Release(ref);
8110 IDWriteFontFile_Release(file);
8111 IDWriteFontFile_Release(file1);
8113 /* References returned from IDWriteFont3/IDWriteFontFace3. */
8114 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
8115 ok(hr == S_OK, "Failed to get system collection, hr %#lx.\n", hr);
8117 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
8118 for (i = 0; i < count; i++)
8120 IDWriteFontFamily1 *family;
8121 UINT32 font_count, j;
8123 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
8124 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
8126 font_count = IDWriteFontFamily1_GetFontCount(family);
8128 for (j = 0; j < font_count; j++)
8130 hr = IDWriteFontFamily1_GetFont(family, j, &font3);
8131 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
8133 hr = IDWriteFont3_GetFontFaceReference(font3, &ref);
8134 ok(hr == S_OK, "Failed to get reference object, hr %#lx.\n", hr);
8136 hr = IDWriteFont3_GetFontFaceReference(font3, &ref1);
8137 ok(hr == S_OK, "Failed to get reference object, hr %#lx.\n", hr);
8138 ok(ref != ref1, "Unexpected reference object %p, %p.\n", ref1, ref);
8140 hr = IDWriteFont3_CreateFontFace(font3, &fontface);
8141 ok(hr == S_OK, "Failed to create a fontface, hr %#lx.\n", hr);
8143 /* Fonts present regular properties as axis values, for non-variable fonts too.
8144 Normally it would include weight/width/slant/italic, but could also contain optical size axis. */
8145 if (SUCCEEDED(hr = IDWriteFontFaceReference_QueryInterface(ref, &IID_IDWriteFontFaceReference1,
8146 (void **)&ref2)))
8148 axis_count = IDWriteFontFaceReference1_GetFontAxisValueCount(ref2);
8149 todo_wine
8150 ok(axis_count >= 4, "Unexpected axis value count.\n");
8152 hr = IDWriteFontFaceReference1_GetFontAxisValues(ref2, axis_values, ARRAY_SIZE(axis_values));
8153 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8155 todo_wine
8156 ok(has_main_axis_values(axis_values, axis_count), "Unexpected axis returned.\n");
8158 IDWriteFontFaceReference1_Release(ref2);
8161 IDWriteFontFaceReference_Release(ref);
8162 IDWriteFontFaceReference_Release(ref1);
8164 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref);
8165 ok(hr == S_OK, "Failed to get a reference, hr %#lx.\n", hr);
8166 EXPECT_REF(fontface, 2);
8168 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref1);
8169 ok(hr == S_OK, "Failed to get a reference, hr %#lx.\n", hr);
8170 ok(ref == ref1, "Unexpected reference %p, %p.\n", ref1, ref);
8171 EXPECT_REF(fontface, 3);
8173 hr = IDWriteFontFace3_QueryInterface(fontface, &IID_IDWriteFontFaceReference, (void **)&ref3);
8174 ok(hr == S_OK || broken(FAILED(hr)), "Failed to get interface, hr %#lx.\n", hr);
8175 if (SUCCEEDED(hr))
8177 ok(ref == ref3, "Unexpected reference %p.\n", ref3);
8178 IDWriteFontFaceReference_Release(ref3);
8181 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface1);
8182 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
8183 ok(fontface1 == fontface, "Unexpected fontface %p, %p.\n", fontface1, fontface);
8184 IDWriteFontFace3_Release(fontface1);
8186 IDWriteFontFaceReference_Release(ref);
8187 IDWriteFontFaceReference_Release(ref1);
8189 IDWriteFontFace3_Release(fontface);
8190 IDWriteFont3_Release(font3);
8193 IDWriteFontFamily1_Release(family);
8195 IDWriteFontCollection1_Release(collection);
8197 refcount = IDWriteFactory3_Release(factory);
8198 ok(refcount == 0, "factory not released, %lu\n", refcount);
8199 DELETE_FONTFILE(path);
8202 static void get_expected_fontsig(IDWriteFont *font, FONTSIGNATURE *fontsig)
8204 struct dwrite_fonttable os2;
8205 IDWriteFontFace *fontface;
8206 WORD version;
8207 BOOL exists;
8208 HRESULT hr;
8210 memset(fontsig, 0, sizeof(*fontsig));
8212 hr = IDWriteFont_CreateFontFace(font, &fontface);
8213 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8215 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&os2.data, &os2.size, &os2.context, &exists);
8216 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8218 if (os2.data)
8220 fontsig->fsUsb[0] = table_read_be_dword(&os2, NULL, FIELD_OFFSET(struct tt_os2, ulUnicodeRange1));
8221 fontsig->fsUsb[1] = table_read_be_dword(&os2, NULL, FIELD_OFFSET(struct tt_os2, ulUnicodeRange2));
8222 fontsig->fsUsb[2] = table_read_be_dword(&os2, NULL, FIELD_OFFSET(struct tt_os2, ulUnicodeRange3));
8223 fontsig->fsUsb[3] = table_read_be_dword(&os2, NULL, FIELD_OFFSET(struct tt_os2, ulUnicodeRange4));
8225 version = table_read_be_word(&os2, NULL, FIELD_OFFSET(struct tt_os2, version));
8226 if (version == 0)
8228 fontsig->fsCsb[0] = 0;
8229 fontsig->fsCsb[1] = 0;
8231 else
8233 fontsig->fsCsb[0] = table_read_be_dword(&os2, NULL, FIELD_OFFSET(struct tt_os2, ulCodePageRange1));
8234 fontsig->fsCsb[1] = table_read_be_dword(&os2, NULL, FIELD_OFFSET(struct tt_os2, ulCodePageRange2));
8237 IDWriteFontFace_ReleaseFontTable(fontface, os2.context);
8240 IDWriteFontFace_Release(fontface);
8243 static void test_GetFontSignature(void)
8245 IDWriteFontCollection *syscollection;
8246 IDWriteGdiInterop1 *interop1;
8247 IDWriteGdiInterop *interop;
8248 IDWriteFactory *factory;
8249 FONTSIGNATURE fontsig;
8250 UINT count, i;
8251 HRESULT hr;
8252 ULONG ref;
8254 factory = create_factory();
8256 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
8257 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8259 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
8260 IDWriteGdiInterop_Release(interop);
8261 if (FAILED(hr)) {
8262 win_skip("GetFontSignature() is not supported.\n");
8263 IDWriteGdiInterop_Release(interop);
8264 IDWriteFactory_Release(factory);
8265 return;
8267 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8269 hr = IDWriteGdiInterop1_GetFontSignature(interop1, NULL, &fontsig);
8270 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
8272 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8273 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8274 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8276 for (i = 0; i < count; i++) {
8277 FONTSIGNATURE expected_signature;
8278 IDWriteLocalizedStrings *names;
8279 IDWriteFontFamily *family;
8280 IDWriteFont *font;
8281 WCHAR nameW[256];
8283 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8284 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8286 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8287 DWRITE_FONT_STYLE_NORMAL, &font);
8288 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8290 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8291 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8293 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8295 IDWriteLocalizedStrings_Release(names);
8297 hr = IDWriteGdiInterop1_GetFontSignature(interop1, font, &fontsig);
8298 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8300 get_expected_fontsig(font, &expected_signature);
8302 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
8304 ok(fontsig.fsUsb[0] == expected_signature.fsUsb[0], "fsUsb[0] %#lx, expected %#lx.\n",
8305 fontsig.fsUsb[0], expected_signature.fsUsb[0]);
8306 ok(fontsig.fsUsb[1] == expected_signature.fsUsb[1], "fsUsb[1] %#lx, expected %#lx.\n",
8307 fontsig.fsUsb[1], expected_signature.fsUsb[1]);
8308 ok(fontsig.fsUsb[2] == expected_signature.fsUsb[2], "fsUsb[2] %#lx, expected %#lx.\n",
8309 fontsig.fsUsb[2], expected_signature.fsUsb[2]);
8310 ok(fontsig.fsUsb[3] == expected_signature.fsUsb[3], "fsUsb[3] %#lx, expected %#lx.\n",
8311 fontsig.fsUsb[3], expected_signature.fsUsb[3]);
8313 ok(fontsig.fsCsb[0] == expected_signature.fsCsb[0], "fsCsb[0] %#lx, expected %#lx.\n",
8314 fontsig.fsCsb[0], expected_signature.fsCsb[0]);
8315 ok(fontsig.fsCsb[1] == expected_signature.fsCsb[1], "fsCsb[1] %#lx, expected %#lx.\n",
8316 fontsig.fsCsb[1], expected_signature.fsCsb[1]);
8318 winetest_pop_context();
8320 IDWriteFont_Release(font);
8321 IDWriteFontFamily_Release(family);
8324 IDWriteGdiInterop1_Release(interop1);
8325 IDWriteFontCollection_Release(syscollection);
8326 ref = IDWriteFactory_Release(factory);
8327 ok(ref == 0, "factory not released, %lu\n", ref);
8330 static void test_font_properties(void)
8332 IDWriteFontFace3 *fontface3;
8333 IDWriteFontFace *fontface;
8334 IDWriteFactory *factory;
8335 DWRITE_FONT_STYLE style;
8336 IDWriteFont *font;
8337 HRESULT hr;
8338 ULONG ref;
8340 factory = create_factory();
8342 /* this creates simulated font */
8343 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
8345 style = IDWriteFont_GetStyle(font);
8346 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
8348 hr = IDWriteFont_CreateFontFace(font, &fontface);
8349 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8351 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
8352 IDWriteFontFace_Release(fontface);
8353 if (hr == S_OK) {
8354 style = IDWriteFontFace3_GetStyle(fontface3);
8355 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
8357 IDWriteFontFace3_Release(fontface3);
8360 IDWriteFont_Release(font);
8361 ref = IDWriteFactory_Release(factory);
8362 ok(ref == 0, "factory not released, %lu\n", ref);
8365 static BOOL has_vertical_glyph_variants(IDWriteFontFace1 *fontface)
8367 const OT_FeatureList *featurelist;
8368 const OT_LookupList *lookup_list;
8369 BOOL exists = FALSE, ret = FALSE;
8370 const GSUB_Header *header;
8371 const void *data;
8372 void *context;
8373 UINT32 size;
8374 HRESULT hr;
8375 UINT16 i;
8377 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
8378 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8380 if (!exists)
8381 return FALSE;
8383 header = data;
8384 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
8385 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
8387 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
8388 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
8389 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
8390 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
8391 const GSUB_SingleSubstFormat2 *subst2;
8392 const OT_LookupTable *lookup_table;
8393 UINT32 offset;
8395 if (lookup_count == 0)
8396 continue;
8398 for (i = 0; i < lookup_count; i++) {
8399 /* check if lookup is empty */
8400 index = GET_BE_WORD(feature->LookupListIndex[i]);
8401 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
8403 type = GET_BE_WORD(lookup_table->LookupType);
8404 ok(type == 1 || type == 7, "got unexpected lookup type %u\n", type);
8406 count = GET_BE_WORD(lookup_table->SubTableCount);
8407 if (count == 0)
8408 continue;
8410 ok(count > 0, "got unexpected subtable count %u\n", count);
8412 offset = GET_BE_WORD(lookup_table->SubTable[0]);
8413 if (type == 7) {
8414 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
8415 if (GET_BE_WORD(ext->SubstFormat) == 1)
8416 offset += GET_BE_DWORD(ext->ExtensionOffset);
8417 else
8418 ok(0, "Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
8421 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
8422 index = GET_BE_WORD(subst2->SubstFormat);
8423 if (index == 1)
8424 ret = TRUE;
8425 else if (index == 2) {
8426 /* SimSun-ExtB has 0 glyph count for this substitution */
8427 if (GET_BE_WORD(subst2->GlyphCount) > 0)
8428 ret = TRUE;
8430 else
8431 ok(0, "unknown Single Substitution Format, %u\n", index);
8433 if (ret)
8434 break;
8439 IDWriteFontFace1_ReleaseFontTable(fontface, context);
8441 return ret;
8444 static void test_HasVerticalGlyphVariants(void)
8446 IDWriteFontCollection *syscollection;
8447 IDWriteFontFace1 *fontface1;
8448 IDWriteFontFace *fontface;
8449 IDWriteFactory *factory;
8450 UINT32 count, i;
8451 HRESULT hr;
8452 ULONG ref;
8454 factory = create_factory();
8455 fontface = create_fontface(factory);
8457 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8458 IDWriteFontFace_Release(fontface);
8459 if (hr != S_OK) {
8460 win_skip("HasVerticalGlyphVariants() is not supported.\n");
8461 IDWriteFactory_Release(factory);
8462 return;
8464 IDWriteFontFace1_Release(fontface1);
8466 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8467 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8468 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8470 for (i = 0; i < count; i++) {
8471 IDWriteLocalizedStrings *names;
8472 BOOL expected_vert, has_vert;
8473 IDWriteFontFamily *family;
8474 IDWriteFont *font;
8475 WCHAR nameW[256];
8477 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8478 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8480 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8481 DWRITE_FONT_STYLE_NORMAL, &font);
8482 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8484 hr = IDWriteFont_CreateFontFace(font, &fontface);
8485 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8487 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8488 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8490 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8491 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8493 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8495 expected_vert = has_vertical_glyph_variants(fontface1);
8496 has_vert = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
8498 ok(expected_vert == has_vert, "%s: expected vertical feature %d, got %d\n",
8499 wine_dbgstr_w(nameW), expected_vert, has_vert);
8501 IDWriteLocalizedStrings_Release(names);
8502 IDWriteFont_Release(font);
8504 IDWriteFontFace1_Release(fontface1);
8505 IDWriteFontFace_Release(fontface);
8506 IDWriteFontFamily_Release(family);
8509 IDWriteFontCollection_Release(syscollection);
8510 ref = IDWriteFactory_Release(factory);
8511 ok(ref == 0, "factory not released, %lu\n", ref);
8514 static void test_HasKerningPairs(void)
8516 IDWriteFontCollection *syscollection;
8517 IDWriteFontFace1 *fontface1;
8518 IDWriteFontFace *fontface;
8519 IDWriteFactory *factory;
8520 UINT32 count, i;
8521 HRESULT hr;
8522 ULONG ref;
8524 factory = create_factory();
8525 fontface = create_fontface(factory);
8527 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8528 IDWriteFontFace_Release(fontface);
8529 if (hr != S_OK) {
8530 win_skip("HasKerningPairs() is not supported.\n");
8531 IDWriteFactory_Release(factory);
8532 return;
8534 IDWriteFontFace1_Release(fontface1);
8536 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8537 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8538 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8540 for (i = 0; i < count; i++) {
8541 IDWriteLocalizedStrings *names;
8542 BOOL exists, has_kerningpairs;
8543 IDWriteFontFamily *family;
8544 IDWriteFont *font;
8545 WCHAR nameW[256];
8546 const void *data;
8547 void *context;
8548 UINT32 size;
8550 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8551 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8553 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8554 DWRITE_FONT_STYLE_NORMAL, &font);
8555 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8557 hr = IDWriteFont_CreateFontFace(font, &fontface);
8558 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8560 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
8561 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8563 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8564 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8566 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8568 exists = FALSE;
8569 hr = IDWriteFontFace1_TryGetFontTable(fontface1, MS_KERN_TAG, &data, &size, &context, &exists);
8570 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8571 IDWriteFontFace1_ReleaseFontTable(fontface1, context);
8573 has_kerningpairs = IDWriteFontFace1_HasKerningPairs(fontface1);
8574 if (!exists)
8575 ok(!has_kerningpairs, "%s: expected %d, got %d\n", wine_dbgstr_w(nameW), exists, has_kerningpairs);
8577 IDWriteLocalizedStrings_Release(names);
8578 IDWriteFont_Release(font);
8580 IDWriteFontFace1_Release(fontface1);
8581 IDWriteFontFace_Release(fontface);
8582 IDWriteFontFamily_Release(family);
8585 IDWriteFontCollection_Release(syscollection);
8586 ref = IDWriteFactory_Release(factory);
8587 ok(ref == 0, "factory not released, %lu\n", ref);
8590 static float get_scaled_metric(const DWRITE_GLYPH_RUN *run, float metric, const DWRITE_FONT_METRICS *m)
8592 return run->fontEmSize * metric / m->designUnitsPerEm;
8595 static void get_expected_glyph_origins(D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *run,
8596 D2D1_POINT_2F *origins)
8598 DWRITE_GLYPH_METRICS glyph_metrics[2];
8599 DWRITE_FONT_METRICS metrics;
8600 unsigned int i;
8601 HRESULT hr;
8603 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
8605 hr = IDWriteFontFace_GetDesignGlyphMetrics(run->fontFace, run->glyphIndices, run->glyphCount, glyph_metrics,
8606 run->isSideways);
8607 ok(hr == S_OK, "Failed to get glyph metrics, hr %#lx.\n", hr);
8609 if (run->bidiLevel & 1)
8611 float advance;
8613 advance = get_scaled_metric(run, run->isSideways ? glyph_metrics[0].advanceHeight :
8614 glyph_metrics[0].advanceWidth, &metrics);
8616 baseline_origin.x -= advance;
8618 for (i = 0; i < run->glyphCount; ++i)
8620 origins[i] = baseline_origin;
8622 if (run->isSideways)
8624 origins[i].x += get_scaled_metric(run, glyph_metrics[i].verticalOriginY, &metrics);
8625 origins[i].y += metrics.designUnitsPerEm / (4.0f * run->fontEmSize);
8628 origins[i].x -= run->glyphOffsets[i].advanceOffset;
8629 origins[i].y -= run->glyphOffsets[i].ascenderOffset;
8631 baseline_origin.x -= run->glyphAdvances[i];
8634 else
8636 for (i = 0; i < run->glyphCount; ++i)
8638 origins[i] = baseline_origin;
8640 if (run->isSideways)
8642 origins[i].x += get_scaled_metric(run, glyph_metrics[i].verticalOriginY, &metrics);
8643 origins[i].y += metrics.designUnitsPerEm / (4.0f * run->fontEmSize);
8646 origins[i].x += run->glyphOffsets[i].advanceOffset;
8647 origins[i].y -= run->glyphOffsets[i].ascenderOffset;
8649 baseline_origin.x += run->glyphAdvances[i];
8654 static void test_ComputeGlyphOrigins(void)
8656 static const struct origins_test
8658 D2D1_POINT_2F baseline_origin;
8659 float advances[2];
8660 DWRITE_GLYPH_OFFSET offsets[2];
8661 unsigned int bidi_level;
8662 unsigned int sideways;
8664 origins_tests[] =
8666 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } } },
8667 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } } },
8668 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 1 },
8670 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 0, 1 },
8671 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } }, 0, 1 },
8672 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 1, 1 },
8673 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } }, 1, 1 },
8675 IDWriteFactory4 *factory;
8676 DWRITE_GLYPH_RUN run;
8677 HRESULT hr;
8678 D2D1_POINT_2F origins[2], expected_origins[2];
8679 D2D1_POINT_2F baseline_origin;
8680 UINT16 glyphs[2] = { 0 };
8681 FLOAT advances[2];
8682 DWRITE_MATRIX m;
8683 ULONG ref;
8684 unsigned int i, j;
8685 IDWriteFontFace *fontface;
8687 factory = create_factory_iid(&IID_IDWriteFactory4);
8688 if (!factory) {
8689 win_skip("ComputeGlyphOrigins() is not supported.\n");
8690 return;
8693 fontface = create_fontface((IDWriteFactory *)factory);
8695 for (i = 0; i < ARRAY_SIZE(origins_tests); ++i)
8697 run.fontFace = fontface;
8698 run.fontEmSize = 32.0f;
8699 run.glyphCount = 2;
8700 run.glyphIndices = glyphs;
8701 run.glyphAdvances = origins_tests[i].advances;
8702 run.glyphOffsets = origins_tests[i].offsets;
8703 run.isSideways = !!origins_tests[i].sideways;
8704 run.bidiLevel = origins_tests[i].bidi_level;
8706 get_expected_glyph_origins(origins_tests[i].baseline_origin, &run, expected_origins);
8708 memset(origins, 0, sizeof(origins));
8709 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, origins_tests[i].baseline_origin, origins);
8710 ok(hr == S_OK, "%u: failed to compute glyph origins, hr %#lx.\n", i, hr);
8711 for (j = 0; j < run.glyphCount; ++j)
8713 todo_wine_if(run.isSideways)
8714 ok(!memcmp(&origins[j], &expected_origins[j], sizeof(origins[j])),
8715 "%u: unexpected origin[%u] (%f, %f) - (%f, %f).\n", i, j, origins[j].x, origins[j].y,
8716 expected_origins[j].x, expected_origins[j].y);
8720 IDWriteFontFace_Release(fontface);
8722 advances[0] = 10.0f;
8723 advances[1] = 20.0f;
8725 run.fontFace = NULL;
8726 run.fontEmSize = 16.0f;
8727 run.glyphCount = 2;
8728 run.glyphIndices = glyphs;
8729 run.glyphAdvances = advances;
8730 run.glyphOffsets = NULL;
8731 run.isSideways = FALSE;
8732 run.bidiLevel = 0;
8734 baseline_origin.x = 123.0f;
8735 baseline_origin.y = 321.0f;
8737 memset(origins, 0, sizeof(origins));
8738 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, baseline_origin, origins);
8739 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8740 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8741 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8743 memset(origins, 0, sizeof(origins));
8744 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
8745 NULL, origins);
8746 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8747 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8749 /* transform is not applied to returned origins */
8750 m.m11 = 2.0f;
8751 m.m12 = 0.0f;
8752 m.m21 = 0.0f;
8753 m.m22 = 1.0f;
8754 m.dx = 0.0f;
8755 m.dy = 0.0f;
8757 memset(origins, 0, sizeof(origins));
8758 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
8759 &m, origins);
8760 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8761 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8763 ref = IDWriteFactory4_Release(factory);
8764 ok(ref == 0, "factory not released, %lu\n", ref);
8767 static void test_object_lifetime(void)
8769 IDWriteFontCollection *collection, *collection2;
8770 IDWriteFontList *fontlist, *fontlist2;
8771 IDWriteGdiInterop *interop, *interop2;
8772 IDWriteFontFamily *family, *family2;
8773 IDWriteFontFace *fontface;
8774 IDWriteFont *font, *font2;
8775 IDWriteFactory *factory;
8776 HRESULT hr;
8777 ULONG ref;
8779 factory = create_factory();
8780 EXPECT_REF(factory, 1);
8782 /* system collection takes factory reference */
8783 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
8784 ok(hr == S_OK, "got %#lx\n", hr);
8786 EXPECT_REF(collection, 1);
8787 EXPECT_REF(factory, 2);
8789 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection2, FALSE);
8790 ok(hr == S_OK, "got %#lx\n", hr);
8791 ok(collection2 == collection, "expected same collection\n");
8793 EXPECT_REF(collection, 2);
8794 EXPECT_REF(factory, 2);
8796 IDWriteFontCollection_Release(collection2);
8798 IDWriteFontCollection_AddRef(collection);
8799 EXPECT_REF(collection, 2);
8800 EXPECT_REF(factory, 2);
8801 IDWriteFontCollection_Release(collection);
8803 EXPECT_REF(collection, 1);
8805 /* family takes collection reference */
8806 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
8807 ok(hr == S_OK, "got %#lx\n", hr);
8809 EXPECT_REF(family, 1);
8810 EXPECT_REF(collection, 2);
8811 EXPECT_REF(factory, 2);
8813 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family2);
8814 ok(hr == S_OK, "got %#lx\n", hr);
8816 EXPECT_REF(family2, 1);
8817 EXPECT_REF(collection, 3);
8818 EXPECT_REF(factory, 2);
8820 IDWriteFontFamily_Release(family2);
8822 EXPECT_REF(family, 1);
8823 EXPECT_REF(collection, 2);
8824 EXPECT_REF(factory, 2);
8826 /* font takes family reference */
8827 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
8828 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
8829 ok(hr == S_OK, "got %#lx\n", hr);
8831 EXPECT_REF(family, 2);
8832 EXPECT_REF(collection, 2);
8833 EXPECT_REF(factory, 2);
8835 hr = IDWriteFont_GetFontFamily(font, &family2);
8836 ok(hr == S_OK, "got %#lx\n", hr);
8837 ok(family2 == family, "unexpected family pointer\n");
8838 IDWriteFontFamily_Release(family2);
8840 EXPECT_REF(font, 1);
8841 EXPECT_REF(factory, 2);
8843 /* Fontface takes factory reference and nothing else. */
8844 hr = IDWriteFont_CreateFontFace(font, &fontface);
8845 ok(hr == S_OK, "got %#lx\n", hr);
8847 EXPECT_REF(font, 1);
8848 EXPECT_REF_BROKEN(fontface, 1, 2);
8849 EXPECT_REF(family, 2);
8850 EXPECT_REF(collection, 2);
8851 EXPECT_REF_BROKEN(factory, 3, 2);
8853 /* get font from fontface */
8854 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
8855 ok(hr == S_OK, "got %#lx\n", hr);
8857 EXPECT_REF(font, 1);
8858 EXPECT_REF(font2, 1);
8859 EXPECT_REF_BROKEN(fontface, 1, 2);
8860 EXPECT_REF(family, 2);
8861 EXPECT_REF(collection, 3);
8862 EXPECT_REF_BROKEN(factory, 3, 2);
8864 IDWriteFont_Release(font2);
8865 IDWriteFontFace_Release(fontface);
8867 EXPECT_REF(font, 1);
8868 EXPECT_REF(family, 2);
8869 EXPECT_REF(collection, 2);
8870 EXPECT_REF(factory, 2);
8872 IDWriteFont_Release(font);
8874 EXPECT_REF(family, 1);
8875 EXPECT_REF(collection, 2);
8876 EXPECT_REF(factory, 2);
8878 /* Matching fonts list takes family reference. */
8879 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
8880 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
8881 ok(hr == S_OK, "got %#lx\n", hr);
8883 EXPECT_REF(family, 2);
8884 EXPECT_REF(collection, 2);
8885 EXPECT_REF(factory, 2);
8887 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
8888 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
8889 ok(hr == S_OK, "got %#lx\n", hr);
8890 ok(fontlist2 != fontlist, "unexpected font list\n");
8891 IDWriteFontList_Release(fontlist2);
8893 IDWriteFontList_Release(fontlist);
8895 IDWriteFontFamily_Release(family);
8896 EXPECT_REF(collection, 1);
8898 EXPECT_REF(factory, 2);
8899 ref = IDWriteFontCollection_Release(collection);
8900 ok(ref == 0, "collection not released, %lu\n", ref);
8901 EXPECT_REF(factory, 1);
8903 /* GDI interop object takes factory reference */
8904 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
8905 ok(hr == S_OK, "got %#lx\n", hr);
8906 EXPECT_REF(interop, 1);
8907 EXPECT_REF(factory, 2);
8909 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
8910 ok(hr == S_OK, "got %#lx\n", hr);
8911 ok(interop == interop2, "got unexpected interop pointer\n");
8913 EXPECT_REF(interop, 2);
8914 EXPECT_REF(factory, 2);
8916 IDWriteGdiInterop_Release(interop2);
8917 ref = IDWriteGdiInterop_Release(interop);
8918 ok(ref == 0, "interop not released, %lu\n", ref);
8920 ref = IDWriteFactory_Release(factory);
8921 ok(ref == 0, "factory not released, %lu\n", ref);
8924 struct testowner_object
8926 IUnknown IUnknown_iface;
8927 LONG ref;
8930 static inline struct testowner_object *impl_from_IUnknown(IUnknown *iface)
8932 return CONTAINING_RECORD(iface, struct testowner_object, IUnknown_iface);
8935 static HRESULT WINAPI testowner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
8937 if (IsEqualIID(riid, &IID_IUnknown)) {
8938 *obj = iface;
8939 IUnknown_AddRef(iface);
8940 return S_OK;
8943 *obj = NULL;
8944 return E_NOINTERFACE;
8947 static ULONG WINAPI testowner_AddRef(IUnknown *iface)
8949 struct testowner_object *object = impl_from_IUnknown(iface);
8950 return InterlockedIncrement(&object->ref);
8953 static ULONG WINAPI testowner_Release(IUnknown *iface)
8955 struct testowner_object *object = impl_from_IUnknown(iface);
8956 return InterlockedDecrement(&object->ref);
8959 static const IUnknownVtbl testownervtbl = {
8960 testowner_QueryInterface,
8961 testowner_AddRef,
8962 testowner_Release,
8965 static void testowner_init(struct testowner_object *object)
8967 object->IUnknown_iface.lpVtbl = &testownervtbl;
8968 object->ref = 1;
8971 static void test_inmemory_file_loader(void)
8973 IDWriteFontFileStream *stream, *stream2, *stream3;
8974 IDWriteInMemoryFontFileLoader *loader, *loader2;
8975 IDWriteInMemoryFontFileLoader *inmemory;
8976 IDWriteFontFileLoader *fileloader;
8977 struct testowner_object ownerobject;
8978 const void *key, *data, *frag_start;
8979 UINT64 file_size, size, writetime;
8980 IDWriteFontFile *file, *file2;
8981 IDWriteFontFace *fontface;
8982 void *context, *context2;
8983 IDWriteFactory5 *factory;
8984 UINT32 count, key_size;
8985 DWORD ref_key;
8986 HRESULT hr;
8987 ULONG ref;
8989 factory = create_factory_iid(&IID_IDWriteFactory5);
8990 if (!factory) {
8991 win_skip("CreateInMemoryFontFileLoader() is not supported\n");
8992 return;
8995 EXPECT_REF(factory, 1);
8996 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
8997 ok(hr == S_OK, "got %#lx\n", hr);
8998 EXPECT_REF(factory, 1);
9000 testowner_init(&ownerobject);
9001 fontface = create_fontface((IDWriteFactory *)factory);
9003 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader2);
9004 ok(hr == S_OK, "got %#lx\n", hr);
9005 ok(loader != loader2, "unexpected pointer\n");
9006 IDWriteInMemoryFontFileLoader_Release(loader2);
9008 inmemory = loader;
9010 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9011 ok(!count, "Unexpected file count %u.\n", count);
9013 /* Use whole font blob to construct in-memory file. */
9014 count = 1;
9015 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
9016 ok(hr == S_OK, "got %#lx\n", hr);
9018 hr = IDWriteFontFile_GetLoader(file, &fileloader);
9019 ok(hr == S_OK, "got %#lx\n", hr);
9021 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
9022 ok(hr == S_OK, "got %#lx\n", hr);
9024 hr = IDWriteFontFileLoader_CreateStreamFromKey(fileloader, key, key_size, &stream);
9025 ok(hr == S_OK, "got %#lx\n", hr);
9026 IDWriteFontFileLoader_Release(fileloader);
9027 IDWriteFontFile_Release(file);
9029 hr = IDWriteFontFileStream_GetFileSize(stream, &file_size);
9030 ok(hr == S_OK, "got %#lx\n", hr);
9032 hr = IDWriteFontFileStream_ReadFileFragment(stream, &data, 0, file_size, &context);
9033 ok(hr == S_OK, "got %#lx\n", hr);
9035 /* Not registered yet. */
9036 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9037 file_size, NULL, &file);
9038 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
9040 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9041 ok(count == 1, "Unexpected file count %u.\n", count);
9043 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9044 ok(hr == S_OK, "got %#lx\n", hr);
9045 EXPECT_REF(inmemory, 2);
9047 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
9048 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9049 file_size, &ownerobject.IUnknown_iface, &file);
9050 ok(hr == S_OK, "got %#lx\n", hr);
9051 EXPECT_REF(&ownerobject.IUnknown_iface, 2);
9052 EXPECT_REF(inmemory, 3);
9054 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9055 ok(count == 2, "Unexpected file count %u.\n", count);
9057 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9058 file_size, &ownerobject.IUnknown_iface, &file2);
9059 ok(hr == S_OK, "got %#lx\n", hr);
9060 ok(file2 != file, "got unexpected file\n");
9061 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9062 EXPECT_REF(inmemory, 4);
9064 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9065 ok(count == 3, "Unexpected file count %u.\n", count);
9067 /* Check in-memory reference key format. */
9068 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
9069 ok(hr == S_OK, "got %#lx\n", hr);
9071 ok(key && *(DWORD*)key == 1, "got wrong ref key\n");
9072 ok(key_size == 4, "ref key size %u\n", key_size);
9074 hr = IDWriteFontFile_GetReferenceKey(file2, &key, &key_size);
9075 ok(hr == S_OK, "got %#lx\n", hr);
9077 ok(key && *(DWORD*)key == 2, "got wrong ref key\n");
9078 ok(key_size == 4, "ref key size %u\n", key_size);
9080 EXPECT_REF(inmemory, 4);
9081 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream2);
9082 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9083 EXPECT_REF(stream2, 1);
9084 EXPECT_REF(inmemory, 4);
9086 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream3);
9087 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9089 ok(stream2 != stream3, "Unexpected stream.\n");
9091 IDWriteFontFileStream_Release(stream2);
9092 IDWriteFontFileStream_Release(stream3);
9094 /* Release file at index 1, create new one to see if index is reused. */
9095 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9096 ref = IDWriteFontFile_Release(file);
9097 ok(ref == 0, "File object not released, %lu.\n", ref);
9098 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9100 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9101 ok(count == 3, "Unexpected file count %u.\n", count);
9103 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9104 ref = IDWriteFontFile_Release(file2);
9105 ok(ref == 0, "File object not released, %lu.\n", ref);
9106 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9108 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9109 ok(count == 3, "Unexpected file count %u.\n", count);
9111 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9112 ok(hr == S_OK, "got %#lx\n", hr);
9113 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9115 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9116 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
9117 ok(ref == 0, "loader not released, %lu.\n", ref);
9118 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
9120 /* Test reference key for first added file. */
9121 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
9122 ok(hr == S_OK, "Failed to create loader, hr %#lx.\n", hr);
9124 inmemory = loader;
9126 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9127 ok(hr == S_OK, "Failed to register loader, hr %#lx.\n", hr);
9129 ref_key = 0;
9130 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
9131 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9133 /* With owner object. */
9134 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9135 file_size, &ownerobject.IUnknown_iface, &file);
9136 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#lx.\n", hr);
9138 ref_key = 0;
9139 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
9140 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9142 context2 = (void *)0xdeadbeef;
9143 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
9144 ok(hr == S_OK, "Failed to read a fragment, hr %#lx.\n", hr);
9145 ok(context2 == NULL, "Unexpected context %p.\n", context2);
9146 ok(frag_start == data, "Unexpected fragment pointer %p.\n", frag_start);
9148 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
9149 ok(hr == S_OK, "Failed to get file size, hr %#lx.\n", hr);
9150 ok(size == file_size, "Unexpected file size.\n");
9152 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
9154 writetime = 1;
9155 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
9156 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
9157 ok(writetime == 0, "Unexpected writetime.\n");
9159 IDWriteFontFileStream_Release(stream2);
9161 /* Without owner object. */
9162 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9163 file_size, NULL, &file2);
9164 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#lx.\n", hr);
9166 ref_key = 1;
9167 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
9168 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9170 context2 = (void *)0xdeadbeef;
9171 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
9172 ok(hr == S_OK, "Failed to read a fragment, hr %#lx.\n", hr);
9173 ok(context2 == NULL, "Unexpected context %p.\n", context2);
9174 ok(frag_start != data, "Unexpected fragment pointer %p.\n", frag_start);
9176 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
9177 ok(hr == S_OK, "Failed to get file size, hr %#lx.\n", hr);
9178 ok(size == file_size, "Unexpected file size.\n");
9180 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
9182 writetime = 1;
9183 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
9184 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
9185 ok(writetime == 0, "Unexpected writetime.\n");
9187 IDWriteFontFileStream_Release(stream2);
9188 IDWriteFontFile_Release(file2);
9190 /* Key size validation. */
9191 ref_key = 0;
9192 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, NULL, sizeof(ref_key) - 1, &stream2);
9193 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9195 ref_key = 0;
9196 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) - 1, &stream2);
9197 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9199 ref_key = 0;
9200 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) + 1, &stream2);
9201 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9203 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9204 ok(count == 2, "Unexpected file count %u.\n", count);
9206 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
9207 ok(hr == S_OK, "Failed to get reference key, hr %#lx.\n", hr);
9209 ok(key && *(DWORD*)key == 0, "Unexpected reference key.\n");
9210 ok(key_size == 4, "Unexpected key size %u.\n", key_size);
9212 IDWriteFontFile_Release(file);
9214 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9215 ok(count == 2, "Unexpected file count %u.\n", count);
9217 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9218 ok(hr == S_OK, "Failed to unregister loader, hr %#lx.\n", hr);
9220 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
9221 IDWriteFontFileStream_Release(stream);
9222 IDWriteFontFace_Release(fontface);
9224 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
9225 ok(ref == 0, "loader not released, %lu.\n", ref);
9227 ref = IDWriteFactory5_Release(factory);
9228 ok(ref == 0, "factory not released, %lu\n", ref);
9231 static BOOL face_has_table(IDWriteFontFace4 *fontface, UINT32 tag)
9233 BOOL exists = FALSE;
9234 const void *data;
9235 void *context;
9236 UINT32 size;
9237 HRESULT hr;
9239 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
9240 ok(hr == S_OK, "TryGetFontTable() failed, %#lx\n", hr);
9241 if (exists)
9242 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9244 return exists;
9247 static DWORD get_sbix_formats(IDWriteFontFace4 *fontface)
9249 UINT32 size, s, num_strikes;
9250 const sbix_header *header;
9251 UINT16 g, num_glyphs;
9252 BOOL exists = FALSE;
9253 const maxp *maxp;
9254 const void *data;
9255 DWORD ret = 0;
9256 void *context;
9257 HRESULT hr;
9259 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
9260 ok(hr == S_OK, "TryGetFontTable() failed, %#lx\n", hr);
9261 ok(exists, "Expected maxp table\n");
9263 if (!exists)
9264 return 0;
9266 maxp = data;
9267 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
9269 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists);
9270 ok(hr == S_OK, "TryGetFontTable() failed, %#lx\n", hr);
9271 ok(exists, "Expected sbix table\n");
9273 header = data;
9274 num_strikes = GET_BE_DWORD(header->numStrikes);
9276 for (s = 0; s < num_strikes; s++) {
9277 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
9279 for (g = 0; g < num_glyphs; g++) {
9280 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
9281 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
9282 sbix_glyph_data *glyph_data;
9283 DWORD format;
9285 if (offset == offset_next)
9286 continue;
9288 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
9289 switch (format = glyph_data->graphicType)
9291 case MS_PNG__TAG:
9292 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
9293 break;
9294 case MS_JPG__TAG:
9295 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
9296 break;
9297 case MS_TIFF_TAG:
9298 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
9299 break;
9300 default:
9301 ok(0, "unexpected format, %#lx\n", GET_BE_DWORD(format));
9306 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9308 return ret;
9311 static DWORD get_cblc_formats(IDWriteFontFace4 *fontface)
9313 const CBLCBitmapSizeTable *sizes;
9314 struct dwrite_fonttable cblc;
9315 unsigned int i, num_sizes;
9316 BOOL exists = FALSE;
9317 DWORD ret = 0;
9318 HRESULT hr;
9320 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&cblc.data, &cblc.size, &cblc.context, &exists);
9321 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9322 ok(exists, "Expected CBLC table.\n");
9324 if (!exists)
9325 return 0;
9327 num_sizes = table_read_be_dword(&cblc, NULL, FIELD_OFFSET(struct cblc_header, numSizes));
9328 if (!(sizes = table_read_ensure(&cblc, sizeof(struct cblc_header), num_sizes * sizeof(*sizes))))
9330 skip("Malformed CBLC table.\n");
9331 num_sizes = 0;
9334 for (i = 0; i < num_sizes; ++i)
9336 BYTE bpp = sizes[i].bitDepth;
9337 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
9338 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
9339 else if (bpp == 32)
9340 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
9342 if (ret == (DWRITE_GLYPH_IMAGE_FORMATS_PNG | DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8))
9343 break;
9346 IDWriteFontFace4_ReleaseFontTable(fontface, cblc.context);
9348 return ret;
9351 static DWORD get_face_glyph_image_formats(IDWriteFontFace4 *fontface)
9353 DWORD ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
9355 if (face_has_table(fontface, MS_GLYF_TAG))
9356 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
9358 if (face_has_table(fontface, MS_CFF__TAG) ||
9359 face_has_table(fontface, MS_CFF2_TAG))
9360 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
9362 if (face_has_table(fontface, MS_COLR_TAG))
9363 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
9365 if (face_has_table(fontface, MS_SVG__TAG))
9366 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
9368 if (face_has_table(fontface, MS_SBIX_TAG))
9369 ret |= get_sbix_formats(fontface);
9371 if (face_has_table(fontface, MS_CBLC_TAG))
9372 ret |= get_cblc_formats(fontface);
9374 return ret;
9377 static void test_GetGlyphImageFormats(void)
9379 IDWriteFontCollection *syscollection;
9380 IDWriteFactory *factory;
9381 UINT32 i, count;
9382 HRESULT hr;
9383 ULONG ref;
9384 IDWriteFontFace *fontface;
9385 IDWriteFontFace4 *fontface4;
9387 factory = create_factory();
9389 fontface = create_fontface(factory);
9390 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
9391 IDWriteFontFace_Release(fontface);
9392 if (FAILED(hr)) {
9393 win_skip("GetGlyphImageFormats() is not supported\n");
9394 IDWriteFactory_Release(factory);
9395 return;
9397 IDWriteFontFace4_Release(fontface4);
9399 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
9400 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9401 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
9403 for (i = 0; i < count; i++) {
9404 WCHAR familynameW[256], facenameW[128];
9405 IDWriteLocalizedStrings *names;
9406 IDWriteFontFamily *family;
9407 UINT32 j, fontcount;
9408 IDWriteFont *font;
9410 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
9411 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9413 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
9414 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9416 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
9417 IDWriteLocalizedStrings_Release(names);
9419 fontcount = IDWriteFontFamily_GetFontCount(family);
9420 for (j = 0; j < fontcount; j++) {
9421 DWORD formats, expected_formats;
9423 hr = IDWriteFontFamily_GetFont(family, j, &font);
9424 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9426 hr = IDWriteFont_CreateFontFace(font, &fontface);
9427 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9429 hr = IDWriteFont_GetFaceNames(font, &names);
9430 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9432 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
9434 IDWriteLocalizedStrings_Release(names);
9436 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
9438 /* Mask describes font as a whole. */
9439 formats = IDWriteFontFace4_GetGlyphImageFormats(fontface4);
9440 expected_formats = get_face_glyph_image_formats(fontface4);
9441 ok(formats == expected_formats, "%s - %s, expected formats %#lx, got formats %#lx.\n",
9442 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), expected_formats, formats);
9444 IDWriteFontFace4_Release(fontface4);
9445 IDWriteFontFace_Release(fontface);
9446 IDWriteFont_Release(font);
9449 IDWriteFontFamily_Release(family);
9452 IDWriteFontCollection_Release(syscollection);
9453 ref = IDWriteFactory_Release(factory);
9454 ok(ref == 0, "factory not released, %lu\n", ref);
9457 static void test_CreateCustomRenderingParams(void)
9459 static const struct custom_params_test
9461 FLOAT gamma;
9462 FLOAT contrast;
9463 FLOAT cleartype_level;
9464 DWRITE_PIXEL_GEOMETRY geometry;
9465 DWRITE_RENDERING_MODE rendering_mode;
9466 HRESULT hr;
9467 } params_tests[] =
9469 { 0.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9470 { 0.0f, 0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9471 { 0.0f, 0.0f, 0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9472 { -0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9473 { 0.1f, -0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9474 { 0.1f, 0.0f, -0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9475 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
9476 { 0.01f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
9477 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR + 1, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9478 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_OUTLINE + 1, E_INVALIDARG },
9479 { 0.1f, 0.0f, 2.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_NATURAL },
9481 IDWriteFactory *factory;
9482 unsigned int i;
9483 HRESULT hr;
9484 ULONG ref;
9486 factory = create_factory();
9488 for (i = 0; i < ARRAY_SIZE(params_tests); i++) {
9489 IDWriteRenderingParams *params;
9491 winetest_push_context("%u", i);
9493 params = (void *)0xdeadbeef;
9494 hr = IDWriteFactory_CreateCustomRenderingParams(factory, params_tests[i].gamma, params_tests[i].contrast,
9495 params_tests[i].cleartype_level, params_tests[i].geometry, params_tests[i].rendering_mode, &params);
9496 ok(hr == params_tests[i].hr, "unexpected hr %#lx, expected %#lx.\n", hr, params_tests[i].hr);
9498 if (hr == S_OK) {
9499 ok(params_tests[i].gamma == IDWriteRenderingParams_GetGamma(params), "unexpected gamma %f, expected %f.\n",
9500 IDWriteRenderingParams_GetGamma(params), params_tests[i].gamma);
9501 ok(params_tests[i].contrast == IDWriteRenderingParams_GetEnhancedContrast(params),
9502 "unexpected contrast %f, expected %f.\n",
9503 IDWriteRenderingParams_GetEnhancedContrast(params), params_tests[i].contrast);
9504 ok(params_tests[i].cleartype_level == IDWriteRenderingParams_GetClearTypeLevel(params),
9505 "unexpected ClearType level %f, expected %f.\n",
9506 IDWriteRenderingParams_GetClearTypeLevel(params), params_tests[i].cleartype_level);
9507 ok(params_tests[i].geometry == IDWriteRenderingParams_GetPixelGeometry(params),
9508 "unexpected pixel geometry %u, expected %u.\n", IDWriteRenderingParams_GetPixelGeometry(params),
9509 params_tests[i].geometry);
9510 ok(params_tests[i].rendering_mode == IDWriteRenderingParams_GetRenderingMode(params),
9511 "unexpected rendering mode %u, expected %u.\n", IDWriteRenderingParams_GetRenderingMode(params),
9512 params_tests[i].rendering_mode);
9513 IDWriteRenderingParams_Release(params);
9515 else
9516 ok(params == NULL, "%u: expected NULL interface pointer on failure.\n", i);
9518 winetest_pop_context();
9521 ref = IDWriteFactory_Release(factory);
9522 ok(ref == 0, "factory not released, %lu\n", ref);
9525 static void test_localfontfileloader(void)
9527 IDWriteFontFileLoader *loader, *loader2;
9528 IDWriteFactory *factory, *factory2;
9529 IDWriteFontFile *file, *file2;
9530 WCHAR *path;
9531 HRESULT hr;
9532 ULONG ref;
9534 factory = create_factory();
9535 factory2 = create_factory();
9537 path = create_testfontfile(test_fontfile);
9539 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
9540 ok(hr == S_OK, "Failed to create file reference, hr %#lx.\n", hr);
9542 hr = IDWriteFactory_CreateFontFileReference(factory2, path, NULL, &file2);
9543 ok(hr == S_OK, "Failed to create file reference, hr %#lx.\n", hr);
9544 ok(file != file2, "Unexpected file instance.\n");
9546 hr = IDWriteFontFile_GetLoader(file, &loader);
9547 ok(hr == S_OK, "Failed to get loader, hr %#lx.\n", hr);
9549 hr = IDWriteFontFile_GetLoader(file2, &loader2);
9550 ok(hr == S_OK, "Failed to get loader, hr %#lx.\n", hr);
9551 ok(loader == loader2, "Unexpected loader instance\n");
9553 IDWriteFontFile_Release(file);
9554 IDWriteFontFile_Release(file2);
9555 IDWriteFontFileLoader_Release(loader);
9556 IDWriteFontFileLoader_Release(loader2);
9557 ref = IDWriteFactory_Release(factory);
9558 ok(ref == 0, "factory not released, %lu\n", ref);
9559 ref = IDWriteFactory_Release(factory2);
9560 ok(ref == 0, "factory not released, %lu\n", ref);
9561 DELETE_FONTFILE(path);
9564 static void test_AnalyzeContainerType(void)
9566 struct WOFFHeader2 woff2_header;
9567 struct WOFFHeader woff_header;
9568 DWRITE_CONTAINER_TYPE type;
9569 IDWriteFactory5 *factory;
9571 factory = create_factory_iid(&IID_IDWriteFactory5);
9572 if (!factory) {
9573 win_skip("AnalyzeContainerType() is not supported.\n");
9574 return;
9577 type = IDWriteFactory5_AnalyzeContainerType(factory, NULL, 0);
9578 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9580 type = IDWriteFactory5_AnalyzeContainerType(factory, (void const *)0xdeadbeef, 0);
9581 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9583 memset(&woff_header, 0xff, sizeof(woff_header));
9584 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9585 woff_header.length = 0;
9586 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header));
9587 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
9589 memset(&woff_header, 0xff, sizeof(woff_header));
9590 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9591 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature));
9592 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
9594 memset(&woff_header, 0xff, sizeof(woff_header));
9595 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9596 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature) - 1);
9597 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9599 memset(&woff2_header, 0xff, sizeof(woff2_header));
9600 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9601 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header));
9602 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
9604 memset(&woff2_header, 0xff, sizeof(woff2_header));
9605 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9606 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature));
9607 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
9609 memset(&woff2_header, 0xff, sizeof(woff2_header));
9610 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9611 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature) - 1);
9612 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9614 IDWriteFactory5_Release(factory);
9617 static void test_fontsetbuilder(void)
9619 IDWriteFontFaceReference *ref, *ref2, *ref3;
9620 IDWriteFontCollection1 *collection;
9621 IDWriteFontFaceReference1 *ref1;
9622 IDWriteFontSetBuilder1 *builder1;
9623 IDWriteFontSetBuilder *builder;
9624 DWRITE_FONT_AXIS_VALUE axis_values[4];
9625 IDWriteFactory3 *factory;
9626 UINT32 count, i, refcount;
9627 IDWriteFontSet *fontset;
9628 IDWriteFontFile *file;
9629 WCHAR *path;
9630 HRESULT hr;
9632 factory = create_factory_iid(&IID_IDWriteFactory3);
9633 if (!factory)
9635 win_skip("IDWriteFontSetBuilder is not supported.\n");
9636 return;
9639 EXPECT_REF(factory, 1);
9640 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
9641 ok(hr == S_OK, "Failed to create font set builder, hr %#lx.\n", hr);
9642 EXPECT_REF(factory, 2);
9644 if (SUCCEEDED(hr = IDWriteFontSetBuilder_QueryInterface(builder, &IID_IDWriteFontSetBuilder1, (void **)&builder1)))
9646 path = create_testfontfile(test_fontfile);
9648 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
9649 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9651 hr = IDWriteFontSetBuilder1_AddFontFile(builder1, file);
9652 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9654 hr = IDWriteFontSetBuilder1_CreateFontSet(builder1, &fontset);
9655 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9656 hr = IDWriteFactory3_CreateFontCollectionFromFontSet(factory, fontset, &collection);
9657 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9658 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9659 ok(count == 1, "Unexpected family count %u.\n", count);
9660 IDWriteFontCollection1_Release(collection);
9661 IDWriteFontSet_Release(fontset);
9663 hr = IDWriteFontSetBuilder1_AddFontFile(builder1, file);
9664 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9666 hr = IDWriteFontSetBuilder1_CreateFontSet(builder1, &fontset);
9667 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9669 hr = IDWriteFactory3_CreateFontCollectionFromFontSet(factory, fontset, &collection);
9670 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9671 check_familymodel(collection, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE);
9672 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9673 ok(count == 1, "Unexpected family count %u.\n", count);
9674 IDWriteFontCollection1_Release(collection);
9676 /* No attempt to eliminate duplicates. */
9677 count = IDWriteFontSet_GetFontCount(fontset);
9678 ok(count == 2, "Unexpected font count %u.\n", count);
9680 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref);
9681 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9683 hr = IDWriteFontFaceReference_QueryInterface(ref, &IID_IDWriteFontFaceReference1, (void **)&ref1);
9684 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9686 count = IDWriteFontFaceReference1_GetFontAxisValueCount(ref1);
9687 todo_wine
9688 ok(count == 4, "Unexpected axis count %u.\n", count);
9690 if (count == 4)
9692 hr = IDWriteFontFaceReference1_GetFontAxisValues(ref1, axis_values, ARRAY_SIZE(axis_values));
9693 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9695 ok(axis_values[0].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT, "Unexpected tag[0] %s.\n",
9696 wine_dbgstr_an((char *)&axis_values[0].axisTag, 4));
9697 ok(axis_values[0].value == 500.0f, "Unexpected value[0] %f.\n", axis_values[0].value);
9698 ok(axis_values[1].axisTag == DWRITE_FONT_AXIS_TAG_WIDTH, "Unexpected tag[1] %s.\n",
9699 wine_dbgstr_an((char *)&axis_values[1].axisTag, 4));
9700 ok(axis_values[1].value == 100.0f, "Unexpected value[1] %f.\n", axis_values[1].value);
9701 ok(axis_values[2].axisTag == DWRITE_FONT_AXIS_TAG_ITALIC, "Unexpected tag[2] %s.\n",
9702 wine_dbgstr_an((char *)&axis_values[2].axisTag, 4));
9703 ok(axis_values[2].value == 0.0f, "Unexpected value[2] %f.\n", axis_values[2].value);
9704 ok(axis_values[3].axisTag == DWRITE_FONT_AXIS_TAG_SLANT, "Unexpected tag[3] %s.\n",
9705 wine_dbgstr_an((char *)&axis_values[3].axisTag, 4));
9706 ok(axis_values[3].value == 0.0f, "Unexpected value[3] %f.\n", axis_values[3].value);
9709 IDWriteFontFaceReference1_Release(ref1);
9711 IDWriteFontFaceReference_Release(ref);
9713 IDWriteFontSet_Release(fontset);
9715 IDWriteFontFile_Release(file);
9716 IDWriteFontSetBuilder1_Release(builder1);
9718 else
9719 win_skip("IDWriteFontSetBuilder1 is not available.\n");
9720 IDWriteFontSetBuilder_Release(builder);
9722 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
9723 ok(hr == S_OK, "Failed to get system collection, hr %#lx.\n", hr);
9724 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9726 for (i = 0; i < count; i++) {
9727 IDWriteFontFamily1 *family;
9728 UINT32 j, fontcount;
9729 IDWriteFont3 *font;
9731 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
9732 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
9734 fontcount = IDWriteFontFamily1_GetFontCount(family);
9735 for (j = 0; j < fontcount; ++j)
9737 IDWriteFontSet *fontset;
9738 UINT32 setcount, id;
9740 hr = IDWriteFontFamily1_GetFont(family, j, &font);
9741 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
9743 /* Create a set with a single font reference, test set properties. */
9744 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
9745 ok(hr == S_OK, "Failed to create font set builder, hr %#lx.\n", hr);
9747 hr = IDWriteFont3_GetFontFaceReference(font, &ref);
9748 ok(hr == S_OK, "Failed to get fontface reference, hr %#lx.\n", hr);
9750 EXPECT_REF(ref, 1);
9751 hr = IDWriteFontSetBuilder_AddFontFaceReference(builder, ref);
9752 ok(hr == S_OK, "Failed to add fontface reference, hr %#lx.\n", hr);
9753 EXPECT_REF(ref, 1);
9755 hr = IDWriteFontSetBuilder_CreateFontSet(builder, &fontset);
9756 ok(hr == S_OK, "Failed to create a font set, hr %#lx.\n", hr);
9758 setcount = IDWriteFontSet_GetFontCount(fontset);
9759 ok(setcount == 1, "Unexpected font count %u.\n", setcount);
9761 ref2 = (void *)0xdeadbeef;
9762 hr = IDWriteFontSet_GetFontFaceReference(fontset, setcount, &ref2);
9763 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9764 ok(!ref2, "Unexpected pointer.\n");
9766 ref2 = NULL;
9767 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref2);
9768 ok(hr == S_OK, "Failed to get font face reference, hr %#lx.\n", hr);
9769 ok(ref2 != ref, "Unexpected reference.\n");
9771 ref3 = NULL;
9772 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref3);
9773 ok(hr == S_OK, "Failed to get font face reference, hr %#lx.\n", hr);
9774 ok(ref2 != ref3, "Unexpected reference.\n");
9776 IDWriteFontFaceReference_Release(ref3);
9777 IDWriteFontFaceReference_Release(ref2);
9779 for (id = DWRITE_FONT_PROPERTY_ID_FAMILY_NAME; id < DWRITE_FONT_PROPERTY_ID_TOTAL; ++id)
9781 IDWriteLocalizedStrings *values;
9782 WCHAR buffW[255], buff2W[255];
9783 UINT32 c, ivalue = 0;
9784 BOOL exists = FALSE;
9786 hr = IDWriteFontSet_GetPropertyValues(fontset, 0, id, &exists, &values);
9787 ok(hr == S_OK, "Failed to get property value, hr %#lx.\n", hr);
9789 if (id == DWRITE_FONT_PROPERTY_ID_WEIGHT || id == DWRITE_FONT_PROPERTY_ID_STRETCH
9790 || id == DWRITE_FONT_PROPERTY_ID_STYLE)
9792 todo_wine
9793 ok(exists, "Property %u expected to exist.\n", id);
9796 if (!exists)
9797 continue;
9799 switch (id)
9801 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
9802 ivalue = IDWriteFont3_GetWeight(font);
9803 break;
9804 case DWRITE_FONT_PROPERTY_ID_STRETCH:
9805 ivalue = IDWriteFont3_GetStretch(font);
9806 break;
9807 case DWRITE_FONT_PROPERTY_ID_STYLE:
9808 ivalue = IDWriteFont3_GetStyle(font);
9809 break;
9810 default:
9814 switch (id)
9816 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
9817 case DWRITE_FONT_PROPERTY_ID_STRETCH:
9818 case DWRITE_FONT_PROPERTY_ID_STYLE:
9819 c = IDWriteLocalizedStrings_GetCount(values);
9820 ok(c == 1, "Unexpected string count %u.\n", c);
9822 buffW[0] = 'a';
9823 hr = IDWriteLocalizedStrings_GetLocaleName(values, 0, buffW, ARRAY_SIZE(buffW));
9824 ok(hr == S_OK, "Failed to get locale name, hr %#lx.\n", hr);
9825 ok(!*buffW, "Unexpected locale %s.\n", wine_dbgstr_w(buffW));
9827 buff2W[0] = 0;
9828 hr = IDWriteLocalizedStrings_GetString(values, 0, buff2W, ARRAY_SIZE(buff2W));
9829 ok(hr == S_OK, "Failed to get property string, hr %#lx.\n", hr);
9831 wsprintfW(buffW, L"%u", ivalue);
9832 ok(!lstrcmpW(buffW, buff2W), "Unexpected property value %s, expected %s.\n", wine_dbgstr_w(buff2W),
9833 wine_dbgstr_w(buffW));
9834 break;
9835 default:
9839 IDWriteLocalizedStrings_Release(values);
9842 IDWriteFontSet_Release(fontset);
9843 IDWriteFontFaceReference_Release(ref);
9844 IDWriteFontSetBuilder_Release(builder);
9846 IDWriteFont3_Release(font);
9849 IDWriteFontFamily1_Release(family);
9852 IDWriteFontCollection1_Release(collection);
9854 refcount = IDWriteFactory3_Release(factory);
9855 ok(!refcount, "Factory not released, %u.\n", refcount);
9858 static void test_font_resource(void)
9860 IDWriteFontFaceReference1 *reference, *reference2;
9861 IDWriteFontResource *resource, *resource2;
9862 IDWriteFontFile *fontfile, *fontfile2;
9863 DWRITE_FONT_AXIS_VALUE axis_values[2];
9864 IDWriteFontFace5 *fontface5;
9865 IDWriteFontFace *fontface;
9866 IDWriteFactory6 *factory;
9867 UINT32 count, index;
9868 HRESULT hr;
9869 ULONG ref;
9870 BOOL ret;
9872 if (!(factory = create_factory_iid(&IID_IDWriteFactory6)))
9874 win_skip("IDWriteFactory6 is not supported.\n");
9875 return;
9878 fontface = create_fontface((IDWriteFactory *)factory);
9880 count = 1;
9881 hr = IDWriteFontFace_GetFiles(fontface, &count, &fontfile);
9882 ok(hr == S_OK, "Failed to get file object, hr %#lx.\n", hr);
9884 hr = IDWriteFactory6_CreateFontResource(factory, fontfile, 0, &resource);
9885 ok(hr == S_OK, "Failed to create font resource, hr %#lx.\n", hr);
9887 hr = IDWriteFactory6_CreateFontResource(factory, fontfile, 0, &resource2);
9888 ok(hr == S_OK, "Failed to create font resource, hr %#lx.\n", hr);
9889 ok(resource != resource2, "Unexpected instance.\n");
9890 IDWriteFontResource_Release(resource2);
9892 hr = IDWriteFontResource_GetFontFile(resource, &fontfile2);
9893 ok(hr == S_OK, "Failed to get font file, hr %#lx.\n", hr);
9894 ok(fontfile2 == fontfile, "Unexpected file instance.\n");
9895 IDWriteFontFile_Release(fontfile2);
9897 index = IDWriteFontResource_GetFontFaceIndex(resource);
9898 ok(!index, "Unexpected index %u.\n", index);
9900 /* Specify axis value, font has no variations. */
9901 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9902 axis_values[0].value = 400.0f;
9903 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 1, &reference);
9904 ok(hr == S_OK, "Failed to create reference object, hr %#lx.\n", hr);
9906 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9907 ok(count == 1, "Unexpected axis value count.\n");
9909 IDWriteFontFaceReference1_Release(reference);
9911 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 1,
9912 &reference);
9913 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9914 ok(count == 1, "Unexpected axis value count.\n");
9915 IDWriteFontFaceReference1_Release(reference);
9917 EXPECT_REF(resource, 1);
9918 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0, &reference);
9919 ok(hr == S_OK, "Failed to create reference object, hr %#lx.\n", hr);
9920 EXPECT_REF(resource, 1);
9922 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0, &reference2);
9923 ok(hr == S_OK, "Failed to create reference object, hr %#lx.\n", hr);
9924 ok(reference != reference2, "Unexpected reference instance.\n");
9925 IDWriteFontFaceReference1_Release(reference2);
9926 IDWriteFontFaceReference1_Release(reference);
9928 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5);
9929 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
9931 hr = IDWriteFontFace5_GetFontResource(fontface5, &resource2);
9932 ok(hr == S_OK, "Failed to get font resource, hr %#lx.\n", hr);
9933 ok(resource != resource2, "Unexpected resource instance.\n");
9934 IDWriteFontResource_Release(resource);
9936 hr = IDWriteFontFace5_GetFontResource(fontface5, &resource);
9937 ok(hr == S_OK, "Failed to get font resource, hr %#lx.\n", hr);
9938 ok(resource != resource2, "Unexpected resource instance.\n");
9939 EXPECT_REF(resource, 1);
9940 IDWriteFontResource_Release(resource);
9941 IDWriteFontResource_Release(resource2);
9943 IDWriteFontFace5_Release(fontface5);
9945 /* Reference equality regarding set axis values. */
9946 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9947 axis_values[0].value = 400.0f;
9948 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9949 axis_values[1].value = 1.0f;
9950 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9951 &reference);
9952 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9953 ok(count == 2, "Unexpected axis value count.\n");
9955 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0,
9956 &reference2);
9957 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9958 ok(!count, "Unexpected axis value count.\n");
9960 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9961 ok(!ret, "Unexpected result.\n");
9962 IDWriteFontFaceReference1_Release(reference2);
9964 /* Different values order. */
9965 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9966 axis_values[0].value = 1.0f;
9967 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9968 axis_values[1].value = 400.0f;
9969 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9970 &reference2);
9971 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9972 ok(count == 2, "Unexpected axis value count.\n");
9974 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9975 ok(!ret, "Unexpected result.\n");
9976 IDWriteFontFaceReference1_Release(reference2);
9978 /* Different axis values. */
9979 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9980 axis_values[0].value = 1.0f;
9981 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9982 axis_values[1].value = 401.0f;
9983 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9984 &reference2);
9985 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9986 ok(count == 2, "Unexpected axis value count.\n");
9988 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9989 ok(!ret, "Unexpected result.\n");
9990 IDWriteFontFaceReference1_Release(reference2);
9992 memset(axis_values, 0, sizeof(axis_values));
9993 hr = IDWriteFontFaceReference1_GetFontAxisValues(reference, axis_values, 1);
9994 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
9995 ok(!axis_values[0].axisTag, "Unexpected axis tag.\n");
9997 memset(axis_values, 0, sizeof(axis_values));
9998 hr = IDWriteFontFaceReference1_GetFontAxisValues(reference, axis_values, 2);
9999 ok(hr == S_OK, "Failed to get axis values, hr %#lx.\n", hr);
10000 ok(axis_values[0].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT, "Unexpected axis tag.\n");
10002 hr = IDWriteFontFaceReference1_CreateFontFace(reference, &fontface5);
10003 ok(hr == S_OK, "Failed to create a font face, hr %#lx.\n", hr);
10004 IDWriteFontFace5_Release(fontface5);
10006 IDWriteFontFaceReference1_Release(reference);
10008 IDWriteFontFile_Release(fontfile);
10010 IDWriteFontFace_Release(fontface);
10011 ref = IDWriteFactory6_Release(factory);
10012 ok(ref == 0, "Factory wasn't released, %lu.\n", ref);
10015 static BOOL get_expected_is_color(IDWriteFontFace2 *fontface)
10017 void *context;
10018 UINT32 size;
10019 BOOL exists;
10020 void *data;
10021 HRESULT hr;
10023 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_CPAL_TAG, (const void **)&data, &size, &context, &exists);
10024 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10025 if (context)
10026 IDWriteFontFace2_ReleaseFontTable(fontface, context);
10028 if (exists)
10030 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_COLR_TAG, (const void **)&data, &size, &context, &exists);
10031 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10032 if (context)
10033 IDWriteFontFace2_ReleaseFontTable(fontface, context);
10036 return exists;
10039 static void test_IsColorFont(void)
10041 IDWriteFontCollection *collection;
10042 IDWriteFactory2 *factory;
10043 UINT32 count, i;
10044 ULONG refcount;
10045 HRESULT hr;
10047 factory = create_factory_iid(&IID_IDWriteFactory2);
10049 if (!factory)
10051 win_skip("IsColorFont() is not supported.\n");
10052 return;
10055 hr = IDWriteFactory2_GetSystemFontCollection(factory, &collection, FALSE);
10056 ok(hr == S_OK, "Failed to get font collection, hr %#lx.\n", hr);
10058 count = IDWriteFontCollection_GetFontFamilyCount(collection);
10059 for (i = 0; i < count; ++i)
10061 IDWriteLocalizedStrings *names;
10062 IDWriteFontFamily *family;
10063 UINT32 font_count, j;
10064 WCHAR nameW[256];
10066 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
10067 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
10069 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
10070 ok(hr == S_OK, "Failed to get names, hr %#lx.\n", hr);
10071 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
10072 IDWriteLocalizedStrings_Release(names);
10074 font_count = IDWriteFontFamily_GetFontCount(family);
10076 for (j = 0; j < font_count; ++j)
10078 BOOL is_color_font, is_color_face, is_color_expected;
10079 IDWriteFontFace2 *fontface2;
10080 IDWriteFontFace *fontface;
10081 IDWriteFont2 *font2;
10082 IDWriteFont *font;
10084 hr = IDWriteFontFamily_GetFont(family, j, &font);
10085 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
10087 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont2, (void **)&font2);
10088 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
10089 IDWriteFont_Release(font);
10091 hr = IDWriteFont2_CreateFontFace(font2, &fontface);
10092 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
10094 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void **)&fontface2);
10095 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
10096 IDWriteFontFace_Release(fontface);
10098 is_color_font = IDWriteFont2_IsColorFont(font2);
10099 is_color_face = IDWriteFontFace2_IsColorFont(fontface2);
10100 ok(is_color_font == is_color_face, "Unexpected color flag.\n");
10102 is_color_expected = get_expected_is_color(fontface2);
10103 ok(is_color_expected == is_color_face, "Unexpected is_color flag %d for %s, font %d.\n",
10104 is_color_face, wine_dbgstr_w(nameW), j);
10106 IDWriteFontFace2_Release(fontface2);
10107 IDWriteFont2_Release(font2);
10110 IDWriteFontFamily_Release(family);
10113 IDWriteFontCollection_Release(collection);
10114 refcount = IDWriteFactory2_Release(factory);
10115 ok(refcount == 0, "Factory not released, refcount %lu.\n", refcount);
10118 static void test_GetVerticalGlyphVariants(void)
10120 UINT16 glyphs[1], glyph_variants[1];
10121 IDWriteFontFace1 *fontface1;
10122 IDWriteFontFace *fontface;
10123 IDWriteFactory *factory;
10124 unsigned int ch;
10125 ULONG refcount;
10126 HRESULT hr;
10127 BOOL ret;
10129 factory = create_factory();
10131 fontface = create_fontface(factory);
10132 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
10133 IDWriteFontFace_Release(fontface);
10134 if (FAILED(hr))
10136 win_skip("GetVerticalGlyphVariants() is not supported.\n");
10137 IDWriteFactory_Release(factory);
10138 return;
10141 ch = 'A';
10142 *glyphs = 0;
10143 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &ch, 1, glyphs);
10144 ok(hr == S_OK, "Failed to get glyph, hr %#lx.\n", hr);
10145 ok(!!*glyphs, "Unexpected glyph %u.\n", glyphs[0]);
10147 memset(glyph_variants, 0, sizeof(glyph_variants));
10148 hr = IDWriteFontFace1_GetVerticalGlyphVariants(fontface1, 1, glyphs, glyph_variants);
10149 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10150 ok(glyphs[0] == glyph_variants[0], "Unexpected glyph.\n");
10152 ret = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
10153 ok(!ret, "Unexpected flag.\n");
10155 IDWriteFontFace1_Release(fontface1);
10156 refcount = IDWriteFactory_Release(factory);
10157 ok(!refcount, "Factory not released, refcount %lu.\n", refcount);
10160 static HANDLE get_collection_expiration_event(IDWriteFontCollection *collection)
10162 IDWriteFontCollection3 *collection3;
10163 HANDLE event;
10164 HRESULT hr;
10166 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
10167 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10168 event = IDWriteFontCollection3_GetExpirationEvent(collection3);
10169 IDWriteFontCollection3_Release(collection3);
10171 return event;
10174 static void test_expiration_event(void)
10176 IDWriteFontCollection *collection, *collection2;
10177 IDWriteFontCollection3 *collection3;
10178 IDWriteFactory *factory, *factory2;
10179 unsigned int refcount;
10180 HANDLE event, event2;
10181 HRESULT hr;
10183 factory = create_factory();
10185 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
10186 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10188 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
10189 if (FAILED(hr))
10191 win_skip("Expiration events are not supported.\n");
10192 IDWriteFontCollection_Release(collection);
10193 IDWriteFactory_Release(factory);
10194 return;
10196 IDWriteFontCollection3_Release(collection3);
10198 event = get_collection_expiration_event(collection);
10199 todo_wine
10200 ok(!!event, "Unexpected event handle.\n");
10202 /* Compare handles with another isolated factory. */
10203 factory2 = create_factory();
10205 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection2, FALSE);
10206 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10207 event2 = get_collection_expiration_event(collection2);
10208 todo_wine {
10209 ok(!!event2, "Unexpected event handle.\n");
10210 ok(event != event2, "Unexpected event handle.\n");
10212 IDWriteFontCollection_Release(collection2);
10214 IDWriteFontCollection_Release(collection);
10216 refcount = IDWriteFactory_Release(factory2);
10217 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10218 refcount = IDWriteFactory_Release(factory);
10219 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10222 static void test_family_font_set(void)
10224 IDWriteFontCollection *collection;
10225 IDWriteFontFamily2 *family2;
10226 IDWriteFontFamily *family;
10227 IDWriteFactory *factory;
10228 unsigned int count, refcount;
10229 IDWriteFontSet1 *fontset, *fontset2;
10230 IDWriteLocalizedStrings *values;
10231 IDWriteFontResource *resource;
10232 WCHAR buffW[64];
10233 BOOL exists;
10234 HRESULT hr;
10236 factory = create_factory();
10238 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
10239 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10241 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
10242 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10244 if (SUCCEEDED(IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily2, (void **)&family2)))
10246 hr = IDWriteFontFamily2_GetFontSet(family2, &fontset);
10247 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10248 hr = IDWriteFontFamily2_GetFontSet(family2, &fontset2);
10249 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10250 ok(fontset != fontset2, "Unexpected fontset instance.\n");
10252 count = IDWriteFontSet1_GetFontCount(fontset);
10254 /* Invalid property id. */
10255 exists = TRUE;
10256 values = (void *)0xdeadbeef;
10257 hr = IDWriteFontSet1_GetPropertyValues(fontset, 0, 100, &exists, &values);
10258 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
10259 ok(!exists && !values, "Unexpected return value.\n");
10261 /* Invalid index. */
10262 exists = TRUE;
10263 values = (void *)0xdeadbeef;
10264 hr = IDWriteFontSet1_GetPropertyValues(fontset, count, DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, &exists, &values);
10265 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
10266 ok(!exists && !values, "Unexpected return value.\n");
10268 exists = TRUE;
10269 values = (void *)0xdeadbeef;
10270 hr = IDWriteFontSet1_GetPropertyValues(fontset, count, 100, &exists, &values);
10271 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
10272 ok(!exists && !values, "Unexpected return value.\n");
10274 hr = IDWriteFontSet1_GetPropertyValues(fontset, 0, DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, &exists, &values);
10275 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10276 ok(exists == !!values, "Unexpected return value.\n");
10277 if (values)
10279 hr = IDWriteLocalizedStrings_GetString(values, 0, buffW, ARRAY_SIZE(buffW));
10280 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10281 IDWriteLocalizedStrings_Release(values);
10284 hr = IDWriteFontSet1_CreateFontResource(fontset, 100, &resource);
10285 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
10287 hr = IDWriteFontSet1_CreateFontResource(fontset, 0, &resource);
10288 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10289 IDWriteFontResource_Release(resource);
10291 IDWriteFontSet1_Release(fontset2);
10292 IDWriteFontSet1_Release(fontset);
10294 IDWriteFontFamily2_Release(family2);
10296 else
10297 win_skip("IDWriteFontFamily2 is not supported.\n");
10299 IDWriteFontFamily_Release(family);
10300 IDWriteFontCollection_Release(collection);
10302 refcount = IDWriteFactory_Release(factory);
10303 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10306 static void test_system_font_set(void)
10308 IDWriteFontSet *fontset, *filtered_set;
10309 IDWriteFontFaceReference *ref;
10310 IDWriteFontFace3 *fontface;
10311 IDWriteFactory3 *factory;
10312 DWRITE_FONT_PROPERTY p;
10313 unsigned int count;
10314 HRESULT hr;
10316 if (!(factory = create_factory_iid(&IID_IDWriteFactory3)))
10318 win_skip("System font set is not supported.\n");
10319 return;
10322 hr = IDWriteFactory3_GetSystemFontSet(factory, &fontset);
10323 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10325 count = IDWriteFontSet_GetFontCount(fontset);
10326 ok(!!count, "Unexpected font count %u.\n", count);
10328 p.propertyId = DWRITE_FONT_PROPERTY_ID_FULL_NAME;
10329 p.propertyValue = L"Tahoma";
10330 p.localeName = L"";
10331 hr = IDWriteFontSet_GetMatchingFonts(fontset, &p, 1, &filtered_set);
10332 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10333 count = IDWriteFontSet_GetFontCount(filtered_set);
10334 ok(!!count, "Unexpected font count %u.\n", count);
10336 hr = IDWriteFontSet_GetFontFaceReference(filtered_set, 0, &ref);
10337 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10339 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
10340 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10342 IDWriteFontFace3_Release(fontface);
10343 IDWriteFontFaceReference_Release(ref);
10345 IDWriteFontSet_Release(filtered_set);
10347 IDWriteFontSet_Release(fontset);
10349 IDWriteFactory3_Release(factory);
10352 static void test_CreateFontCollectionFromFontSet(void)
10354 unsigned int index, count, refcount;
10355 IDWriteFontCollection1 *collection;
10356 IDWriteFontSetBuilder1 *builder;
10357 DWRITE_FONT_PROPERTY props[1];
10358 IDWriteFontFaceReference *ref;
10359 IDWriteFactory5 *factory;
10360 IDWriteFontSet *fontset;
10361 IDWriteFontFile *file;
10362 WCHAR *path;
10363 BOOL exists;
10364 HRESULT hr;
10366 if (!(factory = create_factory_iid(&IID_IDWriteFactory5)))
10368 win_skip("_CreateFontCollectionFromFontSet() is not available.\n");
10369 return;
10372 hr = IDWriteFactory5_CreateFontSetBuilder(factory, &builder);
10373 ok(hr == S_OK, "Failed to create font set builder, hr %#lx.\n", hr);
10375 path = create_testfontfile(test_fontfile);
10377 hr = IDWriteFactory5_CreateFontFileReference(factory, path, NULL, &file);
10378 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10380 hr = IDWriteFontSetBuilder1_AddFontFile(builder, file);
10381 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10383 /* Add same file, with explicit properties. */
10384 hr = IDWriteFactory5_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
10385 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10386 props[0].propertyId = DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME;
10387 props[0].propertyValue = L"Another Font";
10388 props[0].localeName = L"en-US";
10389 hr = IDWriteFontSetBuilder1_AddFontFaceReference_(builder, ref, props, 1);
10390 todo_wine
10391 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10392 IDWriteFontFaceReference_Release(ref);
10394 hr = IDWriteFontSetBuilder1_CreateFontSet(builder, &fontset);
10395 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10397 hr = IDWriteFactory5_CreateFontCollectionFromFontSet(factory, fontset, &collection);
10398 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10400 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
10401 todo_wine
10402 ok(count == 2, "Unexpected family count %u.\n", count);
10404 /* Explicit fontset properties are prioritized and not replaced by actual properties from a file. */
10405 exists = FALSE;
10406 hr = IDWriteFontCollection1_FindFamilyName(collection, L"Another Font", &index, &exists);
10407 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10408 todo_wine
10409 ok(!!exists, "Unexpected return value %d.\n", exists);
10411 IDWriteFontCollection1_Release(collection);
10412 IDWriteFontSet_Release(fontset);
10414 IDWriteFontSetBuilder1_Release(builder);
10416 IDWriteFontFile_Release(file);
10417 refcount = IDWriteFactory5_Release(factory);
10418 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10419 DELETE_FONTFILE(path);
10422 static void test_GetMatchingFontsByLOGFONT(void)
10424 IDWriteFontSet *systemset, *set;
10425 IDWriteGdiInterop1 *interop;
10426 IDWriteGdiInterop *interop0;
10427 IDWriteFactory3 *factory;
10428 ULONG refcount, count;
10429 LOGFONTW logfont;
10430 HRESULT hr;
10432 factory = create_factory_iid(&IID_IDWriteFactory3);
10433 if (!factory)
10435 win_skip("Skipping GetMatchingFontsByLOGFONT() tests.\n");
10436 return;
10439 hr = IDWriteFactory3_GetSystemFontSet(factory, &systemset);
10440 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10442 interop = NULL;
10443 hr = IDWriteFactory3_GetGdiInterop(factory, &interop0);
10444 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10446 hr = IDWriteGdiInterop_QueryInterface(interop0, &IID_IDWriteGdiInterop1, (void **)&interop);
10447 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10448 IDWriteGdiInterop_Release(interop0);
10450 memset(&logfont, 0, sizeof(logfont));
10451 logfont.lfHeight = 12;
10452 logfont.lfWidth = 12;
10453 logfont.lfWeight = FW_BOLD;
10454 logfont.lfItalic = 1;
10455 lstrcpyW(logfont.lfFaceName, L"tahoma");
10457 hr = IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(interop, NULL, systemset, &set);
10458 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
10460 hr = IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(interop, &logfont, NULL, &set);
10461 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
10463 hr = IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(interop, &logfont, systemset, &set);
10464 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10466 count = IDWriteFontSet_GetFontCount(set);
10467 ok(count > 0, "Unexpected count %lu.\n", count);
10469 IDWriteFontSet_Release(set);
10471 IDWriteGdiInterop1_Release(interop);
10472 IDWriteFontSet_Release(systemset);
10474 refcount = IDWriteFactory3_Release(factory);
10475 ok(!refcount, "Factory wasn't released, %lu.\n", refcount);
10478 START_TEST(font)
10480 IDWriteFactory *factory;
10482 if (!(factory = create_factory())) {
10483 win_skip("failed to create factory\n");
10484 return;
10487 test_object_lifetime();
10488 test_CreateFontFromLOGFONT();
10489 test_CreateBitmapRenderTarget();
10490 test_GetFontFamily();
10491 test_GetFamilyNames();
10492 test_CreateFontFace();
10493 test_GetMetrics();
10494 test_system_fontcollection();
10495 test_ConvertFontFaceToLOGFONT();
10496 test_CustomFontCollection();
10497 test_CreateCustomFontFileReference();
10498 test_CreateFontFileReference();
10499 test_shared_isolated();
10500 test_GetUnicodeRanges();
10501 test_GetFontFromFontFace();
10502 test_GetFirstMatchingFont();
10503 test_GetMatchingFonts();
10504 test_GetInformationalStrings();
10505 test_GetGdiInterop();
10506 test_CreateFontFaceFromHdc();
10507 test_GetSimulations();
10508 test_GetFaceNames();
10509 test_TryGetFontTable();
10510 test_ConvertFontToLOGFONT();
10511 test_CreateStreamFromKey();
10512 test_ReadFileFragment();
10513 test_GetDesignGlyphMetrics();
10514 test_GetDesignGlyphAdvances();
10515 test_IsMonospacedFont();
10516 test_GetGlyphRunOutline();
10517 test_GetEudcFontCollection();
10518 test_GetCaretMetrics();
10519 test_GetGlyphCount();
10520 test_GetKerningPairAdjustments();
10521 test_CreateRenderingParams();
10522 test_CreateGlyphRunAnalysis();
10523 test_GetGdiCompatibleMetrics();
10524 test_GetPanose();
10525 test_GetGdiCompatibleGlyphAdvances();
10526 test_GetRecommendedRenderingMode();
10527 test_GetAlphaBlendParams();
10528 test_CreateAlphaTexture();
10529 test_IsSymbolFont();
10530 test_GetPaletteEntries();
10531 test_TranslateColorGlyphRun();
10532 test_HasCharacter();
10533 test_CreateFontFaceReference();
10534 test_GetFontSignature();
10535 test_font_properties();
10536 test_HasVerticalGlyphVariants();
10537 test_HasKerningPairs();
10538 test_ComputeGlyphOrigins();
10539 test_inmemory_file_loader();
10540 test_GetGlyphImageFormats();
10541 test_CreateCustomRenderingParams();
10542 test_localfontfileloader();
10543 test_AnalyzeContainerType();
10544 test_fontsetbuilder();
10545 test_font_resource();
10546 test_IsColorFont();
10547 test_GetVerticalGlyphVariants();
10548 test_expiration_event();
10549 test_family_font_set();
10550 test_system_font_set();
10551 test_CreateFontCollectionFromFontSet();
10552 test_GetMatchingFontsByLOGFONT();
10554 IDWriteFactory_Release(factory);