msvcrt: Use EnumSystemLocalesEx instead of directly accessing kernel32 resources.
[wine.git] / dlls / dwrite / tests / font.c
blob0a02ba1236de51d4d94a369b8b5422ed9ae398f6
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 typedef struct
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;
205 } TT_OS2_V2;
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 typedef struct {
325 WORD majorVersion;
326 WORD minorVersion;
327 DWORD numSizes;
328 } CBLCHeader;
330 typedef struct {
331 BYTE res[12];
332 } sbitLineMetrics;
334 typedef struct {
335 DWORD indexSubTableArrayOffset;
336 DWORD indexTablesSize;
337 DWORD numberofIndexSubTables;
338 DWORD colorRef;
339 sbitLineMetrics hori;
340 sbitLineMetrics vert;
341 WORD startGlyphIndex;
342 WORD endGlyphIndex;
343 BYTE ppemX;
344 BYTE ppemY;
345 BYTE bitDepth;
346 BYTE flags;
347 } CBLCBitmapSizeTable;
349 typedef struct {
350 DWORD version;
351 WORD numGlyphs;
352 } maxp;
354 struct WOFFHeader
356 ULONG signature;
357 ULONG flavor;
358 ULONG length;
359 USHORT numTables;
360 USHORT reserved;
361 ULONG totalSfntSize;
362 USHORT majorVersion;
363 USHORT minorVersion;
364 ULONG metaOffset;
365 ULONG metaLength;
366 ULONG metaOrigLength;
367 ULONG privOffset;
368 ULONG privLength;
371 struct WOFFHeader2
373 ULONG signature;
374 ULONG flavor;
375 ULONG length;
376 USHORT numTables;
377 USHORT reserved;
378 ULONG totalSfntSize;
379 ULONG totalCompressedSize;
380 USHORT majorVersion;
381 USHORT minorVersion;
382 ULONG metaOffset;
383 ULONG metaLength;
384 ULONG metaOrigLength;
385 ULONG privOffset;
386 ULONG privLength;
389 struct cmap_encoding_record
391 WORD platformID;
392 WORD encodingID;
393 DWORD offset;
396 struct cmap_header
398 WORD version;
399 WORD num_tables;
400 struct cmap_encoding_record tables[1];
403 struct cmap_segmented_coverage_group
405 DWORD startCharCode;
406 DWORD endCharCode;
407 DWORD startGlyphID;
410 struct cmap_segmented_coverage
412 WORD format;
413 WORD reserved;
414 DWORD length;
415 DWORD language;
416 DWORD nGroups;
417 struct cmap_segmented_coverage_group groups[1];
420 struct cmap_segmented_mapping_0
422 WORD format;
423 WORD length;
424 WORD language;
425 WORD segCountX2;
426 WORD searchRange;
427 WORD entrySelector;
428 WORD rangeShift;
429 WORD endCode[1];
432 enum opentype_cmap_table_platform
434 OPENTYPE_CMAP_TABLE_PLATFORM_WIN = 3,
437 enum opentype_cmap_table_encoding
439 OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL = 0,
440 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP = 1,
441 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL = 10,
444 enum opentype_cmap_table_format
446 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
447 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12,
450 #include "poppack.h"
452 static void *create_factory_iid(REFIID riid)
454 IUnknown *factory = NULL;
455 DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, riid, &factory);
456 return factory;
459 static IDWriteFactory *create_factory(void)
461 IDWriteFactory *factory = create_factory_iid(&IID_IDWriteFactory);
462 ok(factory != NULL, "Failed to create factory.\n");
463 return factory;
466 static IDWriteFontFace *create_fontface(IDWriteFactory *factory)
468 IDWriteGdiInterop *interop;
469 IDWriteFontFace *fontface;
470 IDWriteFont *font;
471 LOGFONTW logfont;
472 HRESULT hr;
474 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
475 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
477 memset(&logfont, 0, sizeof(logfont));
478 logfont.lfHeight = 12;
479 logfont.lfWidth = 12;
480 logfont.lfWeight = FW_NORMAL;
481 logfont.lfItalic = 1;
482 lstrcpyW(logfont.lfFaceName, L"Tahoma");
484 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
485 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
487 hr = IDWriteFont_CreateFontFace(font, &fontface);
488 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
490 IDWriteFont_Release(font);
491 IDWriteGdiInterop_Release(interop);
493 return fontface;
496 static IDWriteFont *get_font(IDWriteFactory *factory, const WCHAR *name, DWRITE_FONT_STYLE style)
498 IDWriteFontCollection *collection;
499 IDWriteFontFamily *family;
500 IDWriteFont *font = NULL;
501 UINT32 index;
502 BOOL exists;
503 HRESULT hr;
505 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
506 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
508 index = ~0;
509 exists = FALSE;
510 hr = IDWriteFontCollection_FindFamilyName(collection, name, &index, &exists);
511 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
512 if (!exists) goto not_found;
514 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
515 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
517 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
518 DWRITE_FONT_STRETCH_NORMAL, style, &font);
519 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
521 IDWriteFontFamily_Release(family);
522 not_found:
523 IDWriteFontCollection_Release(collection);
524 return font;
527 static IDWriteFont *get_tahoma_instance(IDWriteFactory *factory, DWRITE_FONT_STYLE style)
529 IDWriteFont *font = get_font(factory, L"Tahoma", style);
530 ok(font != NULL, "failed to get Tahoma\n");
531 return font;
534 static WCHAR *create_testfontfile(const WCHAR *filename)
536 static WCHAR pathW[MAX_PATH];
537 DWORD written;
538 HANDLE file;
539 HRSRC res;
540 void *ptr;
542 GetTempPathW(ARRAY_SIZE(pathW), pathW);
543 lstrcatW(pathW, filename);
545 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
546 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", wine_dbgstr_w(pathW),
547 GetLastError());
549 res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
550 ok( res != 0, "couldn't find resource\n" );
551 ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
552 WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
553 ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
554 CloseHandle( file );
556 return pathW;
559 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
560 static void _delete_testfontfile(const WCHAR *filename, int line)
562 BOOL ret = DeleteFileW(filename);
563 ok_(__FILE__,line)(ret, "failed to delete file %s, error %ld\n", wine_dbgstr_w(filename), GetLastError());
566 static void get_combined_font_name(const WCHAR *familyW, const WCHAR *faceW, WCHAR *nameW)
568 lstrcpyW(nameW, familyW);
569 lstrcatW(nameW, L" ");
570 lstrcatW(nameW, faceW);
573 static BOOL has_face_variations(IDWriteFontFace *fontface)
575 IDWriteFontFace5 *fontface5;
576 BOOL ret = FALSE;
578 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5))) {
579 ret = IDWriteFontFace5_HasVariations(fontface5);
580 IDWriteFontFace5_Release(fontface5);
583 return ret;
586 #define check_familymodel(a,b) _check_familymodel(a,b,__LINE__)
587 static void _check_familymodel(void *iface_ptr, DWRITE_FONT_FAMILY_MODEL expected_model, unsigned int line)
589 IDWriteFontCollection2 *collection;
590 DWRITE_FONT_FAMILY_MODEL model;
592 if (SUCCEEDED(IUnknown_QueryInterface((IUnknown *)iface_ptr, &IID_IDWriteFontCollection2, (void **)&collection)))
594 model = IDWriteFontCollection2_GetFontFamilyModel(collection);
595 ok_(__FILE__,line)(model == expected_model, "Unexpected family model %d, expected %d.\n", model, expected_model);
596 IDWriteFontCollection2_Release(collection);
600 struct test_fontenumerator
602 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
603 LONG ref;
605 DWORD index;
606 IDWriteFontFile *font_file;
609 static inline struct test_fontenumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
611 return CONTAINING_RECORD(iface, struct test_fontenumerator, IDWriteFontFileEnumerator_iface);
614 static HRESULT WINAPI singlefontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
616 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
618 *obj = iface;
619 IDWriteFontFileEnumerator_AddRef(iface);
620 return S_OK;
622 return E_NOINTERFACE;
625 static ULONG WINAPI singlefontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
627 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
628 return InterlockedIncrement(&This->ref);
631 static ULONG WINAPI singlefontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
633 struct test_fontenumerator *enumerator = impl_from_IDWriteFontFileEnumerator(iface);
634 ULONG ref = InterlockedDecrement(&enumerator->ref);
635 if (!ref)
637 IDWriteFontFile_Release(enumerator->font_file);
638 free(enumerator);
640 return ref;
643 static HRESULT WINAPI singlefontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **font_file)
645 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
646 IDWriteFontFile_AddRef(This->font_file);
647 *font_file = This->font_file;
648 return S_OK;
651 static HRESULT WINAPI singlefontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
653 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
655 if (This->index > 1) {
656 *current = FALSE;
657 return S_OK;
660 This->index++;
661 *current = TRUE;
662 return S_OK;
665 static const struct IDWriteFontFileEnumeratorVtbl singlefontfileenumeratorvtbl =
667 singlefontfileenumerator_QueryInterface,
668 singlefontfileenumerator_AddRef,
669 singlefontfileenumerator_Release,
670 singlefontfileenumerator_MoveNext,
671 singlefontfileenumerator_GetCurrentFontFile
674 static HRESULT create_enumerator(IDWriteFontFile *font_file, IDWriteFontFileEnumerator **ret)
676 struct test_fontenumerator *enumerator;
678 if (!(enumerator = calloc(1, sizeof(*enumerator))))
679 return E_OUTOFMEMORY;
681 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &singlefontfileenumeratorvtbl;
682 enumerator->ref = 1;
683 enumerator->index = 0;
684 enumerator->font_file = font_file;
685 IDWriteFontFile_AddRef(font_file);
687 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
688 return S_OK;
691 struct test_fontcollectionloader
693 IDWriteFontCollectionLoader IDWriteFontFileCollectionLoader_iface;
694 IDWriteFontFileLoader *loader;
697 static inline struct test_fontcollectionloader *impl_from_IDWriteFontFileCollectionLoader(IDWriteFontCollectionLoader* iface)
699 return CONTAINING_RECORD(iface, struct test_fontcollectionloader, IDWriteFontFileCollectionLoader_iface);
702 static HRESULT WINAPI resourcecollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
704 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontCollectionLoader))
706 *obj = iface;
707 IDWriteFontCollectionLoader_AddRef(iface);
708 return S_OK;
710 return E_NOINTERFACE;
713 static ULONG WINAPI resourcecollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
715 return 2;
718 static ULONG WINAPI resourcecollectionloader_Release(IDWriteFontCollectionLoader *iface)
720 return 1;
723 static HRESULT WINAPI resourcecollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory,
724 const void * collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator ** fontFileEnumerator)
726 struct test_fontcollectionloader *This = impl_from_IDWriteFontFileCollectionLoader(iface);
727 IDWriteFontFile *font_file;
728 HRESULT hr;
730 hr = IDWriteFactory_CreateCustomFontFileReference(factory, collectionKey, collectionKeySize, This->loader, &font_file);
731 ok(hr == S_OK, "Failed to create custom file reference, hr %#lx.\n", hr);
733 hr = create_enumerator(font_file, fontFileEnumerator);
734 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
736 IDWriteFontFile_Release(font_file);
737 return hr;
740 static const struct IDWriteFontCollectionLoaderVtbl resourcecollectionloadervtbl = {
741 resourcecollectionloader_QueryInterface,
742 resourcecollectionloader_AddRef,
743 resourcecollectionloader_Release,
744 resourcecollectionloader_CreateEnumeratorFromKey
747 /* Here is a functional custom font set of interfaces */
748 struct test_fontdatastream
750 IDWriteFontFileStream IDWriteFontFileStream_iface;
751 LONG ref;
753 LPVOID data;
754 DWORD size;
757 static inline struct test_fontdatastream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream* iface)
759 return CONTAINING_RECORD(iface, struct test_fontdatastream, IDWriteFontFileStream_iface);
762 static HRESULT WINAPI fontdatastream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
764 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
766 *obj = iface;
767 IDWriteFontFileStream_AddRef(iface);
768 return S_OK;
770 *obj = NULL;
771 return E_NOINTERFACE;
774 static ULONG WINAPI fontdatastream_AddRef(IDWriteFontFileStream *iface)
776 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
777 ULONG ref = InterlockedIncrement(&This->ref);
778 return ref;
781 static ULONG WINAPI fontdatastream_Release(IDWriteFontFileStream *iface)
783 struct test_fontdatastream *stream = impl_from_IDWriteFontFileStream(iface);
784 ULONG refcount = InterlockedDecrement(&stream->ref);
786 if (!refcount)
787 free(stream);
789 return refcount;
792 static HRESULT WINAPI fontdatastream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
794 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
795 *fragment_context = NULL;
796 if (offset+fragment_size > This->size)
798 *fragment_start = NULL;
799 return E_FAIL;
801 else
803 *fragment_start = (BYTE*)This->data + offset;
804 return S_OK;
808 static void WINAPI fontdatastream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
810 /* Do Nothing */
813 static HRESULT WINAPI fontdatastream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
815 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
816 *size = This->size;
817 return S_OK;
820 static HRESULT WINAPI fontdatastream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
822 return E_NOTIMPL;
825 static const IDWriteFontFileStreamVtbl fontdatastreamvtbl =
827 fontdatastream_QueryInterface,
828 fontdatastream_AddRef,
829 fontdatastream_Release,
830 fontdatastream_ReadFileFragment,
831 fontdatastream_ReleaseFileFragment,
832 fontdatastream_GetFileSize,
833 fontdatastream_GetLastWriteTime
836 static HRESULT create_fontdatastream(LPVOID data, UINT size, IDWriteFontFileStream** iface)
838 struct test_fontdatastream *object = calloc(1, sizeof(*object));
839 if (!object)
840 return E_OUTOFMEMORY;
842 object->IDWriteFontFileStream_iface.lpVtbl = &fontdatastreamvtbl;
843 object->ref = 1;
844 object->data = data;
845 object->size = size;
847 *iface = &object->IDWriteFontFileStream_iface;
849 return S_OK;
852 static HRESULT WINAPI resourcefontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
854 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
856 *obj = iface;
857 return S_OK;
859 *obj = NULL;
860 return E_NOINTERFACE;
863 static ULONG WINAPI resourcefontfileloader_AddRef(IDWriteFontFileLoader *iface)
865 return 2;
868 static ULONG WINAPI resourcefontfileloader_Release(IDWriteFontFileLoader *iface)
870 return 1;
873 static HRESULT WINAPI resourcefontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
874 IDWriteFontFileStream **stream)
876 LPVOID data;
877 DWORD size;
878 HGLOBAL mem;
880 mem = LoadResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
881 ok(mem != NULL, "Failed to lock font resource\n");
882 if (mem)
884 size = SizeofResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
885 data = LockResource(mem);
886 return create_fontdatastream(data, size, stream);
888 return E_FAIL;
891 static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = {
892 resourcefontfileloader_QueryInterface,
893 resourcefontfileloader_AddRef,
894 resourcefontfileloader_Release,
895 resourcefontfileloader_CreateStreamFromKey
898 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
900 static D2D1_POINT_2F g_startpoints[2];
901 static int g_startpoint_count;
903 static HRESULT WINAPI test_geometrysink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **ret)
905 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
906 IsEqualIID(riid, &IID_IUnknown))
908 *ret = iface;
909 ID2D1SimplifiedGeometrySink_AddRef(iface);
910 return S_OK;
913 *ret = NULL;
914 return E_NOINTERFACE;
917 static ULONG WINAPI test_geometrysink_AddRef(ID2D1SimplifiedGeometrySink *iface)
919 return 2;
922 static ULONG WINAPI test_geometrysink_Release(ID2D1SimplifiedGeometrySink *iface)
924 return 1;
927 static void WINAPI test_geometrysink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
929 CHECK_EXPECT(setfillmode);
930 ok(mode == D2D1_FILL_MODE_WINDING, "fill mode %d\n", mode);
933 static void WINAPI test_geometrysink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT flags)
935 ok(0, "unexpected SetSegmentFlags() - flags %d\n", flags);
938 static void WINAPI test_geometrysink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
939 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
941 ok(figureBegin == D2D1_FIGURE_BEGIN_FILLED, "begin figure %d\n", figureBegin);
942 if (g_startpoint_count < ARRAY_SIZE(g_startpoints))
943 g_startpoints[g_startpoint_count] = startPoint;
944 g_startpoint_count++;
947 static void WINAPI test_geometrysink_AddLines(ID2D1SimplifiedGeometrySink *iface,
948 const D2D1_POINT_2F *points, UINT32 count)
952 static void WINAPI test_geometrysink_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
953 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
957 static void WINAPI test_geometrysink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
959 ok(figureEnd == D2D1_FIGURE_END_CLOSED, "end figure %d\n", figureEnd);
962 static HRESULT WINAPI test_geometrysink_Close(ID2D1SimplifiedGeometrySink *iface)
964 ok(0, "unexpected Close()\n");
965 return E_NOTIMPL;
968 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink_vtbl = {
969 test_geometrysink_QueryInterface,
970 test_geometrysink_AddRef,
971 test_geometrysink_Release,
972 test_geometrysink_SetFillMode,
973 test_geometrysink_SetSegmentFlags,
974 test_geometrysink_BeginFigure,
975 test_geometrysink_AddLines,
976 test_geometrysink_AddBeziers,
977 test_geometrysink_EndFigure,
978 test_geometrysink_Close
981 static void WINAPI test_geometrysink2_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
982 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
984 ok(0, "unexpected call\n");
987 static void WINAPI test_geometrysink2_AddLines(ID2D1SimplifiedGeometrySink *iface,
988 const D2D1_POINT_2F *points, UINT32 count)
990 ok(0, "unexpected call\n");
993 static void WINAPI test_geometrysink2_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
994 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
996 ok(0, "unexpected call\n");
999 static void WINAPI test_geometrysink2_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
1001 ok(0, "unexpected call\n");
1004 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink2_vtbl = {
1005 test_geometrysink_QueryInterface,
1006 test_geometrysink_AddRef,
1007 test_geometrysink_Release,
1008 test_geometrysink_SetFillMode,
1009 test_geometrysink_SetSegmentFlags,
1010 test_geometrysink2_BeginFigure,
1011 test_geometrysink2_AddLines,
1012 test_geometrysink2_AddBeziers,
1013 test_geometrysink2_EndFigure,
1014 test_geometrysink_Close
1017 static ID2D1SimplifiedGeometrySink test_geomsink = { &test_geometrysink_vtbl };
1018 static ID2D1SimplifiedGeometrySink test_geomsink2 = { &test_geometrysink2_vtbl };
1020 static void test_CreateFontFromLOGFONT(void)
1022 IDWriteGdiInterop1 *interop1;
1023 IDWriteGdiInterop *interop;
1024 DWRITE_FONT_WEIGHT weight;
1025 DWRITE_FONT_STYLE style;
1026 IDWriteFont *font;
1027 LOGFONTW logfont;
1028 LONG weights[][2] = {
1029 {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
1030 {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
1031 { 0, DWRITE_FONT_WEIGHT_NORMAL},
1032 { 50, DWRITE_FONT_WEIGHT_NORMAL},
1033 {150, DWRITE_FONT_WEIGHT_NORMAL},
1034 {250, DWRITE_FONT_WEIGHT_NORMAL},
1035 {350, DWRITE_FONT_WEIGHT_NORMAL},
1036 {450, DWRITE_FONT_WEIGHT_NORMAL},
1037 {650, DWRITE_FONT_WEIGHT_BOLD},
1038 {750, DWRITE_FONT_WEIGHT_BOLD},
1039 {850, DWRITE_FONT_WEIGHT_BOLD},
1040 {950, DWRITE_FONT_WEIGHT_BOLD},
1041 {960, DWRITE_FONT_WEIGHT_BOLD},
1043 OUTLINETEXTMETRICW otm;
1044 IDWriteFactory *factory;
1045 HRESULT hr;
1046 BOOL ret;
1047 HDC hdc;
1048 HFONT hfont;
1049 BOOL exists;
1050 ULONG ref;
1051 int i;
1052 UINT r;
1054 factory = create_factory();
1056 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1057 ok(hr == S_OK, "got %#lx\n", hr);
1059 if (0)
1060 /* null out parameter crashes this call */
1061 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
1063 font = (void*)0xdeadbeef;
1064 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
1065 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1066 ok(font == NULL, "got %p\n", font);
1068 memset(&logfont, 0, sizeof(logfont));
1069 logfont.lfHeight = 12;
1070 logfont.lfWidth = 12;
1071 logfont.lfWeight = FW_NORMAL;
1072 logfont.lfItalic = 1;
1073 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1075 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1076 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1078 hfont = CreateFontIndirectW(&logfont);
1079 hdc = CreateCompatibleDC(0);
1080 SelectObject(hdc, hfont);
1082 otm.otmSize = sizeof(otm);
1083 r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
1084 ok(r, "got %d\n", r);
1085 DeleteDC(hdc);
1086 DeleteObject(hfont);
1088 exists = TRUE;
1089 hr = IDWriteFont_HasCharacter(font, 0xd800, &exists);
1090 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1091 ok(exists == FALSE, "got %d\n", exists);
1093 exists = FALSE;
1094 hr = IDWriteFont_HasCharacter(font, 0x20, &exists);
1095 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1096 ok(exists == TRUE, "got %d\n", exists);
1098 /* now check properties */
1099 weight = IDWriteFont_GetWeight(font);
1100 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1102 style = IDWriteFont_GetStyle(font);
1103 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1104 ok(otm.otmfsSelection & 1, "got 0x%08x\n", otm.otmfsSelection);
1106 ret = IDWriteFont_IsSymbolFont(font);
1107 ok(!ret, "got %d\n", ret);
1109 IDWriteFont_Release(font);
1111 /* weight values */
1112 for (i = 0; i < ARRAY_SIZE(weights); i++)
1114 memset(&logfont, 0, sizeof(logfont));
1115 logfont.lfHeight = 12;
1116 logfont.lfWidth = 12;
1117 logfont.lfWeight = weights[i][0];
1118 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1120 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1121 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1123 weight = IDWriteFont_GetWeight(font);
1124 ok(weight == weights[i][1],
1125 "%d: got %d, expected %ld\n", i, weight, weights[i][1]);
1127 IDWriteFont_Release(font);
1130 /* weight not from enum */
1131 memset(&logfont, 0, sizeof(logfont));
1132 logfont.lfHeight = 12;
1133 logfont.lfWidth = 12;
1134 logfont.lfWeight = 550;
1135 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1137 font = NULL;
1138 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1139 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1141 weight = IDWriteFont_GetWeight(font);
1142 ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
1143 "got %d\n", weight);
1145 IDWriteFont_Release(font);
1147 /* empty or nonexistent face name */
1148 memset(&logfont, 0, sizeof(logfont));
1149 logfont.lfHeight = 12;
1150 logfont.lfWidth = 12;
1151 logfont.lfWeight = FW_NORMAL;
1152 lstrcpyW(logfont.lfFaceName, L"Blah!");
1154 font = (void*)0xdeadbeef;
1155 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1156 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
1157 ok(font == NULL, "got %p\n", font);
1159 /* Try with name 'Tahoma ' */
1160 memset(&logfont, 0, sizeof(logfont));
1161 logfont.lfHeight = 12;
1162 logfont.lfWidth = 12;
1163 logfont.lfWeight = FW_NORMAL;
1164 lstrcpyW(logfont.lfFaceName, L"Tahoma ");
1166 font = (void*)0xdeadbeef;
1167 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1168 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
1169 ok(font == NULL, "got %p\n", font);
1171 /* empty string as a facename */
1172 memset(&logfont, 0, sizeof(logfont));
1173 logfont.lfHeight = 12;
1174 logfont.lfWidth = 12;
1175 logfont.lfWeight = FW_NORMAL;
1177 font = (void*)0xdeadbeef;
1178 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1179 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
1180 ok(font == NULL, "got %p\n", font);
1182 /* IDWriteGdiInterop1::CreateFontFromLOGFONT() */
1183 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
1184 if (hr == S_OK) {
1185 memset(&logfont, 0, sizeof(logfont));
1186 logfont.lfHeight = 12;
1187 logfont.lfWidth = 12;
1188 logfont.lfWeight = FW_NORMAL;
1189 logfont.lfItalic = 1;
1190 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1192 hr = IDWriteGdiInterop1_CreateFontFromLOGFONT(interop1, &logfont, NULL, &font);
1193 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1195 IDWriteFont_Release(font);
1196 IDWriteGdiInterop1_Release(interop1);
1198 else
1199 win_skip("IDWriteGdiInterop1 is not supported, skipping CreateFontFromLOGFONT() tests.\n");
1201 ref = IDWriteGdiInterop_Release(interop);
1202 ok(ref == 0, "interop is not released, %lu\n", ref);
1203 ref = IDWriteFactory_Release(factory);
1204 ok(ref == 0, "factory is not released, %lu\n", ref);
1207 static void test_CreateBitmapRenderTarget(void)
1209 IDWriteBitmapRenderTarget *target, *target2;
1210 IDWriteBitmapRenderTarget1 *target1;
1211 IDWriteRenderingParams *params;
1212 IDWriteGdiInterop *interop;
1213 IDWriteFontFace *fontface;
1214 IDWriteFactory *factory;
1215 DWRITE_GLYPH_RUN run;
1216 HBITMAP hbm, hbm2;
1217 UINT16 glyphs[2];
1218 DWRITE_MATRIX m;
1219 DIBSECTION ds;
1220 XFORM xform;
1221 COLORREF c;
1222 HRESULT hr;
1223 FLOAT pdip;
1224 SIZE size;
1225 ULONG ref;
1226 UINT32 ch;
1227 HDC hdc;
1228 int ret;
1230 factory = create_factory();
1232 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1233 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1235 target = NULL;
1236 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
1237 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1239 if (0) /* crashes on native */
1240 hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
1242 size.cx = size.cy = -1;
1243 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1244 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1245 ok(size.cx == 0, "got %ld\n", size.cx);
1246 ok(size.cy == 0, "got %ld\n", size.cy);
1248 target2 = NULL;
1249 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
1250 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1251 ok(target != target2, "got %p, %p\n", target2, target);
1252 IDWriteBitmapRenderTarget_Release(target2);
1254 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1255 ok(hdc != NULL, "got %p\n", hdc);
1257 /* test mode */
1258 ret = GetGraphicsMode(hdc);
1259 ok(ret == GM_ADVANCED, "got %d\n", ret);
1261 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1262 ok(hbm != NULL, "got %p\n", hbm);
1264 /* check DIB properties */
1265 ret = GetObjectW(hbm, sizeof(ds), &ds);
1266 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1267 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1268 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1269 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1270 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1271 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1273 IDWriteBitmapRenderTarget_Release(target);
1275 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1276 ok(!hbm, "got %p\n", hbm);
1278 target = NULL;
1279 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
1280 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1282 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1283 ok(hdc != NULL, "got %p\n", hdc);
1285 /* test context settings */
1286 c = GetTextColor(hdc);
1287 ok(c == RGB(0, 0, 0), "got 0x%08lx\n", c);
1288 ret = GetBkMode(hdc);
1289 ok(ret == OPAQUE, "got %d\n", ret);
1290 c = GetBkColor(hdc);
1291 ok(c == RGB(255, 255, 255), "got 0x%08lx\n", c);
1293 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1294 ok(hbm != NULL, "got %p\n", hbm);
1296 /* check DIB properties */
1297 ret = GetObjectW(hbm, sizeof(ds), &ds);
1298 ok(ret == sizeof(ds), "got %d\n", ret);
1299 ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
1300 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1301 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1302 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1303 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1305 size.cx = size.cy = -1;
1306 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1307 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1308 ok(size.cx == 10, "got %ld\n", size.cx);
1309 ok(size.cy == 5, "got %ld\n", size.cy);
1311 /* resize to same size */
1312 hr = IDWriteBitmapRenderTarget_Resize(target, 10, 5);
1313 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1315 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1316 ok(hbm2 == hbm, "got %p, %p\n", hbm2, hbm);
1318 /* shrink */
1319 hr = IDWriteBitmapRenderTarget_Resize(target, 5, 5);
1320 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1322 size.cx = size.cy = -1;
1323 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1324 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1325 ok(size.cx == 5, "got %ld\n", size.cx);
1326 ok(size.cy == 5, "got %ld\n", size.cy);
1328 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1329 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1331 hr = IDWriteBitmapRenderTarget_Resize(target, 20, 5);
1332 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1334 size.cx = size.cy = -1;
1335 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1336 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1337 ok(size.cx == 20, "got %ld\n", size.cx);
1338 ok(size.cy == 5, "got %ld\n", size.cy);
1340 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1341 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1343 hr = IDWriteBitmapRenderTarget_Resize(target, 1, 5);
1344 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1346 size.cx = size.cy = -1;
1347 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1348 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1349 ok(size.cx == 1, "got %ld\n", size.cx);
1350 ok(size.cy == 5, "got %ld\n", size.cy);
1352 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1353 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1355 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1356 ok(ret == sizeof(ds), "got %d\n", ret);
1357 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1358 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1359 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1360 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1361 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1363 /* empty rectangle */
1364 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 5);
1365 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1367 size.cx = size.cy = -1;
1368 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1369 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1370 ok(size.cx == 0, "got %ld\n", size.cx);
1371 ok(size.cy == 5, "got %ld\n", size.cy);
1373 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1374 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1376 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1377 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1378 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1379 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1380 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1381 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1382 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1384 /* transform tests, current hdc transform is not immediately affected */
1385 if (0) /* crashes on native */
1386 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, NULL);
1388 memset(&m, 0xcc, sizeof(m));
1389 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1390 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1391 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);
1392 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1393 ret = GetWorldTransform(hdc, &xform);
1394 ok(ret, "got %d\n", ret);
1395 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1396 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1398 memset(&m, 0, sizeof(m));
1399 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1400 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1402 memset(&m, 0xcc, sizeof(m));
1403 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1404 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1405 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);
1406 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1407 ret = GetWorldTransform(hdc, &xform);
1408 ok(ret, "got %d\n", ret);
1409 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1410 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1412 memset(&m, 0, sizeof(m));
1413 m.m11 = 2.0; m.m22 = 1.0;
1414 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1415 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1416 ret = GetWorldTransform(hdc, &xform);
1417 ok(ret, "got %d\n", ret);
1418 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1419 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1421 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, NULL);
1422 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1424 memset(&m, 0xcc, sizeof(m));
1425 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1426 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1427 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);
1428 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1430 /* pixels per dip */
1431 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1432 ok(pdip == 1.0, "got %.2f\n", pdip);
1434 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
1435 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1437 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, -1.0);
1438 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1440 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 0.0);
1441 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1443 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1444 ok(pdip == 2.0, "got %.2f\n", pdip);
1446 hr = IDWriteBitmapRenderTarget_QueryInterface(target, &IID_IDWriteBitmapRenderTarget1, (void**)&target1);
1447 if (hr == S_OK) {
1448 DWRITE_TEXT_ANTIALIAS_MODE mode;
1450 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1451 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1453 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE+1);
1454 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1456 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1457 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1459 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
1460 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1462 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1463 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, "got %d\n", mode);
1465 IDWriteBitmapRenderTarget1_Release(target1);
1467 else
1468 win_skip("IDWriteBitmapRenderTarget1 is not supported.\n");
1470 /* DrawGlyphRun() argument validation. */
1471 hr = IDWriteBitmapRenderTarget_Resize(target, 16, 16);
1472 ok(hr == S_OK, "Failed to resize target, hr %#lx.\n", hr);
1474 fontface = create_fontface(factory);
1476 ch = 'A';
1477 glyphs[0] = 0;
1478 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, glyphs);
1479 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1480 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
1481 glyphs[1] = glyphs[0];
1483 memset(&run, 0, sizeof(run));
1484 run.fontFace = fontface;
1485 run.fontEmSize = 12.0f;
1486 run.glyphCount = 2;
1487 run.glyphIndices = glyphs;
1489 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
1490 DWRITE_RENDERING_MODE_DEFAULT, &params);
1491 ok(hr == S_OK, "Failed to create rendering params, hr %#lx.\n", hr);
1493 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1494 &run, NULL, RGB(255, 0, 0), NULL);
1495 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1497 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1498 &run, NULL, RGB(255, 0, 0), NULL);
1499 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1501 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1502 &run, params, RGB(255, 0, 0), NULL);
1503 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Unexpected hr %#lx.\n", hr);
1505 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL,
1506 &run, params, RGB(255, 0, 0), NULL);
1507 ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr);
1509 IDWriteRenderingParams_Release(params);
1511 /* Zero sized target returns earlier. */
1512 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 16);
1513 ok(hr == S_OK, "Failed to resize target, hr %#lx.\n", hr);
1515 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1516 &run, NULL, RGB(255, 0, 0), NULL);
1517 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1519 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1520 &run, params, RGB(255, 0, 0), NULL);
1521 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1523 IDWriteFontFace_Release(fontface);
1525 ref = IDWriteBitmapRenderTarget_Release(target);
1526 ok(ref == 0, "render target not released, %lu\n", ref);
1527 ref = IDWriteGdiInterop_Release(interop);
1528 ok(ref == 0, "interop not released, %lu\n", ref);
1529 ref = IDWriteFactory_Release(factory);
1530 ok(ref == 0, "factory not released, %lu\n", ref);
1533 static void test_GetFontFamily(void)
1535 IDWriteFontCollection *collection, *collection2;
1536 IDWriteFontCollection *syscoll;
1537 IDWriteFontCollection2 *coll2;
1538 IDWriteFontFamily *family, *family2;
1539 IDWriteFontFamily1 *family1;
1540 IDWriteGdiInterop *interop;
1541 IDWriteFont *font, *font2;
1542 IDWriteFactory *factory;
1543 LOGFONTW logfont;
1544 ULONG ref, count;
1545 HRESULT hr;
1547 factory = create_factory();
1549 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1550 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1552 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1553 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1555 memset(&logfont, 0, sizeof(logfont));
1556 logfont.lfHeight = 12;
1557 logfont.lfWidth = 12;
1558 logfont.lfWeight = FW_NORMAL;
1559 logfont.lfItalic = 1;
1560 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1562 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1563 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1565 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1566 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1567 ok(font2 != font, "got %p, %p\n", font2, font);
1569 if (0) /* crashes on native */
1570 hr = IDWriteFont_GetFontFamily(font, NULL);
1572 EXPECT_REF(font, 1);
1573 hr = IDWriteFont_GetFontFamily(font, &family);
1574 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1575 EXPECT_REF(font, 1);
1576 EXPECT_REF(family, 2);
1578 hr = IDWriteFont_GetFontFamily(font, &family2);
1579 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1580 ok(family2 == family, "got %p, previous %p\n", family2, family);
1581 EXPECT_REF(font, 1);
1582 EXPECT_REF(family, 3);
1583 IDWriteFontFamily_Release(family2);
1585 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
1586 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
1587 ok(family2 == NULL, "got %p\n", family2);
1589 hr = IDWriteFont_GetFontFamily(font2, &family2);
1590 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1591 ok(family2 != family, "got %p, %p\n", family2, family);
1593 collection = NULL;
1594 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
1595 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1597 collection2 = NULL;
1598 hr = IDWriteFontFamily_GetFontCollection(family2, &collection2);
1599 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1600 ok(collection == collection2, "got %p, %p\n", collection, collection2);
1601 ok(collection == syscoll, "got %p, %p\n", collection, syscoll);
1603 IDWriteFont_Release(font);
1604 IDWriteFont_Release(font2);
1606 hr = IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily1, (void**)&family1);
1607 if (hr == S_OK) {
1608 IDWriteFontFaceReference *ref, *ref1;
1609 IDWriteFontList1 *fontlist1;
1610 IDWriteFontList2 *fontlist2;
1611 IDWriteFontList *fontlist;
1612 IDWriteFont3 *font3;
1613 IDWriteFont1 *font1;
1615 font3 = (void*)0xdeadbeef;
1616 hr = IDWriteFontFamily1_GetFont(family1, ~0u, &font3);
1617 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1618 ok(font3 == NULL, "got %p\n", font3);
1620 hr = IDWriteFontFamily1_GetFont(family1, 0, &font3);
1621 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1623 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont, (void**)&font);
1624 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1625 IDWriteFont_Release(font);
1627 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont1, (void**)&font1);
1628 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1629 IDWriteFont1_Release(font1);
1631 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList1, (void **)&fontlist1);
1632 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Failed to get interface, hr %#lx.\n", hr);
1633 if (hr == S_OK) {
1634 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void **)&fontlist);
1635 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1636 ok(fontlist == (IDWriteFontList *)fontlist1, "Unexpected interface pointer.\n");
1637 ok(fontlist != (IDWriteFontList *)family1, "Unexpected interface pointer.\n");
1638 ok(fontlist != (IDWriteFontList *)family, "Unexpected interface pointer.\n");
1640 if (SUCCEEDED(IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList2, (void **)&fontlist2)))
1642 IDWriteFontSet1 *fontset = NULL, *fontset2 = NULL;
1644 ok(fontlist == (IDWriteFontList *)fontlist2, "Unexpected interface pointer.\n");
1646 hr = IDWriteFontList2_GetFontSet(fontlist2, &fontset);
1647 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1649 hr = IDWriteFontList2_GetFontSet(fontlist2, &fontset2);
1650 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1651 ok(fontset != fontset2, "Unexpected instance.\n");
1653 IDWriteFontSet1_Release(fontset2);
1654 IDWriteFontSet1_Release(fontset);
1656 IDWriteFontList2_Release(fontlist2);
1658 else
1659 win_skip("IDWriteFontList2 is not supported.\n");
1661 IDWriteFontList1_Release(fontlist1);
1662 IDWriteFontList_Release(fontlist);
1665 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void**)&fontlist);
1666 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1667 IDWriteFontList_Release(fontlist);
1669 IDWriteFont3_Release(font3);
1671 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref);
1672 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1674 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref1);
1675 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1676 ok(ref != ref1, "got %p, %p\n", ref, ref1);
1678 IDWriteFontFaceReference_Release(ref);
1679 IDWriteFontFaceReference_Release(ref1);
1681 IDWriteFontFamily1_Release(family1);
1683 else
1684 win_skip("IDWriteFontFamily1 is not supported.\n");
1686 /* IDWriteFontCollection2::GetFontFamily() */
1687 if (SUCCEEDED(IDWriteFontCollection_QueryInterface(syscoll, &IID_IDWriteFontCollection2, (void **)&coll2)))
1689 IDWriteFontFamily2 *family2;
1691 count = IDWriteFontCollection2_GetFontFamilyCount(coll2);
1692 ok(!!count, "Unexpected family count.\n");
1694 family2 = (void *)0xdeadbeef;
1695 hr = IDWriteFontCollection2_GetFontFamily(coll2, count, &family2);
1696 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1697 ok(!family2, "Unexpected pointer.\n");
1699 hr = IDWriteFontCollection2_GetFontFamily(coll2, 0, &family2);
1700 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
1701 IDWriteFontFamily2_Release(family2);
1703 IDWriteFontCollection2_Release(coll2);
1705 else
1706 win_skip("IDWriteFontCollection2 is not supported.\n");
1708 IDWriteFontCollection_Release(syscoll);
1709 IDWriteFontCollection_Release(collection2);
1710 IDWriteFontCollection_Release(collection);
1711 IDWriteFontFamily_Release(family2);
1712 IDWriteFontFamily_Release(family);
1713 IDWriteGdiInterop_Release(interop);
1714 ref = IDWriteFactory_Release(factory);
1715 ok(ref == 0, "factory not released, %lu\n", ref);
1718 static void test_GetFamilyNames(void)
1720 IDWriteLocalizedStrings *names, *names2;
1721 IDWriteFontFace3 *fontface3;
1722 IDWriteGdiInterop *interop;
1723 IDWriteFontFamily *family;
1724 IDWriteFontFace *fontface;
1725 IDWriteFactory *factory;
1726 IDWriteFont *font;
1727 LOGFONTW logfont;
1728 WCHAR buffer[100];
1729 HRESULT hr;
1730 UINT32 len;
1731 ULONG ref;
1733 factory = create_factory();
1735 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1736 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1738 memset(&logfont, 0, sizeof(logfont));
1739 logfont.lfHeight = 12;
1740 logfont.lfWidth = 12;
1741 logfont.lfWeight = FW_NORMAL;
1742 logfont.lfItalic = 1;
1743 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1745 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1746 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1748 hr = IDWriteFont_GetFontFamily(font, &family);
1749 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1751 if (0) /* crashes on native */
1752 hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
1754 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1755 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1756 EXPECT_REF(names, 1);
1758 hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
1759 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1760 EXPECT_REF(names2, 1);
1761 ok(names != names2, "got %p, was %p\n", names2, names);
1763 IDWriteLocalizedStrings_Release(names2);
1765 /* GetStringLength */
1766 if (0) /* crashes on native */
1767 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
1769 len = 100;
1770 hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
1771 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1772 ok(len == (UINT32)-1, "got %u\n", len);
1774 len = 0;
1775 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
1776 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1777 ok(len > 0, "got %u\n", len);
1779 /* GetString */
1780 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
1781 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1783 hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
1784 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
1786 if (0)
1787 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
1789 buffer[0] = 1;
1790 hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
1791 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
1792 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1794 buffer[0] = 1;
1795 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
1796 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1797 ok(buffer[0] == 0 || broken(buffer[0] == 'T'), "Unexpected buffer contents, %#x.\n", buffer[0]);
1799 buffer[0] = 1;
1800 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
1801 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1802 ok(buffer[0] == 0 || broken(buffer[0] == 'T'), "Unexpected buffer contents, %#x.\n", buffer[0]);
1804 buffer[0] = 0;
1805 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1806 ok(hr == S_OK, "Failed to get a string, hr %#lx.\n", hr);
1807 ok(!lstrcmpW(buffer, L"Tahoma"), "Unexpected family name %s.\n", wine_dbgstr_w(buffer));
1809 IDWriteLocalizedStrings_Release(names);
1811 /* GetFamilyNames() on font face */
1812 hr = IDWriteFont_CreateFontFace(font, &fontface);
1813 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
1815 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
1817 hr = IDWriteFontFace3_GetFamilyNames(fontface3, &names);
1818 ok(hr == S_OK, "Failed to get family names, hr %#lx.\n", hr);
1820 buffer[0] = 0;
1821 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1822 ok(hr == S_OK, "Failed to get a string, hr %#lx.\n", hr);
1823 ok(!lstrcmpW(buffer, L"Tahoma"), "Unexpected family name %s.\n", wine_dbgstr_w(buffer));
1825 IDWriteLocalizedStrings_Release(names);
1826 IDWriteFontFace3_Release(fontface3);
1828 else
1829 win_skip("IDWriteFontFace3::GetFamilyNames() is not supported.\n");
1831 IDWriteFontFace_Release(fontface);
1833 IDWriteFontFamily_Release(family);
1834 IDWriteFont_Release(font);
1835 IDWriteGdiInterop_Release(interop);
1836 ref = IDWriteFactory_Release(factory);
1837 ok(ref == 0, "factory not released, %lu\n", ref);
1840 static void test_CreateFontFace(void)
1842 IDWriteFontFace *fontface, *fontface2;
1843 IDWriteFontCollection *collection;
1844 DWRITE_FONT_FILE_TYPE file_type;
1845 DWRITE_FONT_FACE_TYPE face_type;
1846 IDWriteFontFace5 *fontface5;
1847 IDWriteGdiInterop *interop;
1848 IDWriteFont *font, *font2;
1849 IDWriteFontFamily *family;
1850 IDWriteFactory *factory;
1851 IDWriteFontFile *file;
1852 BOOL supported, ret;
1853 LOGFONTW logfont;
1854 UINT32 count;
1855 WCHAR *path;
1856 HRESULT hr;
1857 ULONG ref;
1859 factory = create_factory();
1861 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1862 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1864 memset(&logfont, 0, sizeof(logfont));
1865 logfont.lfHeight = 12;
1866 logfont.lfWidth = 12;
1867 logfont.lfWeight = FW_NORMAL;
1868 logfont.lfItalic = 1;
1869 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1871 font = NULL;
1872 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1873 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1875 font2 = NULL;
1876 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1877 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1878 ok(font != font2, "got %p, %p\n", font, font2);
1880 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
1881 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
1883 if (0) /* crashes on native */
1884 hr = IDWriteFont_CreateFontFace(font, NULL);
1886 fontface = NULL;
1887 hr = IDWriteFont_CreateFontFace(font, &fontface);
1888 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1890 fontface2 = NULL;
1891 hr = IDWriteFont_CreateFontFace(font, &fontface2);
1892 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1893 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1894 IDWriteFontFace_Release(fontface2);
1896 fontface2 = NULL;
1897 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1898 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1899 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1900 IDWriteFontFace_Release(fontface2);
1902 IDWriteFont_Release(font2);
1903 IDWriteFont_Release(font);
1905 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFont, (void**)&font);
1906 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL), "Unexpected hr %#lx.\n", hr);
1908 IDWriteFontFace_Release(fontface);
1909 IDWriteGdiInterop_Release(interop);
1911 /* Create from system collection */
1912 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1913 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1915 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
1916 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1918 font = NULL;
1919 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1920 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1921 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1923 font2 = NULL;
1924 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1925 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
1926 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1927 ok(font != font2, "got %p, %p\n", font, font2);
1929 fontface = NULL;
1930 hr = IDWriteFont_CreateFontFace(font, &fontface);
1931 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1933 fontface2 = NULL;
1934 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1935 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1936 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1938 /* Trivial equality test */
1939 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5)))
1941 ret = IDWriteFontFace5_Equals(fontface5, fontface2);
1942 ok(ret, "Unexpected result %d.\n", ret);
1943 IDWriteFontFace5_Release(fontface5);
1946 IDWriteFontFace_Release(fontface);
1947 IDWriteFontFace_Release(fontface2);
1948 IDWriteFont_Release(font2);
1949 IDWriteFont_Release(font);
1950 IDWriteFontFamily_Release(family);
1951 IDWriteFontCollection_Release(collection);
1952 ref = IDWriteFactory_Release(factory);
1953 ok(ref == 0, "factory not released, %lu.\n", ref);
1955 /* IDWriteFactory::CreateFontFace() */
1956 path = create_testfontfile(test_fontfile);
1957 factory = create_factory();
1959 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
1960 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
1962 supported = FALSE;
1963 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1964 face_type = DWRITE_FONT_FACE_TYPE_CFF;
1965 count = 0;
1966 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &count);
1967 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1968 ok(supported == TRUE, "got %i\n", supported);
1969 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
1970 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
1971 ok(count == 1, "got %i\n", count);
1973 /* invalid simulation flags */
1974 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, ~0u, &fontface);
1975 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1977 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0xf, &fontface);
1978 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1980 /* try mismatching face type, the one that's not supported */
1981 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1982 ok(hr == DWRITE_E_FILEFORMAT, "Unexpected hr %#lx.\n", hr);
1984 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, 1, &file, 0,
1985 DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1986 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* < win10 */, "Unexpected hr %#lx.\n", hr);
1988 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_RAW_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1989 todo_wine
1990 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == E_INVALIDARG) /* older versions */, "Unexpected hr %#lx.\n", hr);
1992 fontface = (void*)0xdeadbeef;
1993 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TYPE1, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1994 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1995 ok(fontface == NULL, "got %p\n", fontface);
1997 fontface = (void*)0xdeadbeef;
1998 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_VECTOR, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1999 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2000 ok(fontface == NULL, "got %p\n", fontface);
2002 fontface = (void*)0xdeadbeef;
2003 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_BITMAP, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2004 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2005 ok(fontface == NULL, "got %p\n", fontface);
2007 fontface = NULL;
2008 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_UNKNOWN, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2009 todo_wine
2010 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* < win10 */, "Unexpected hr %#lx.\n", hr);
2011 if (hr == S_OK) {
2012 ok(fontface != NULL, "got %p\n", fontface);
2013 face_type = IDWriteFontFace_GetType(fontface);
2014 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %d\n", face_type);
2015 IDWriteFontFace_Release(fontface);
2018 IDWriteFontFile_Release(file);
2019 ref = IDWriteFactory_Release(factory);
2020 ok(ref == 0, "factory not released, %lu.\n", ref);
2021 DELETE_FONTFILE(path);
2024 static void get_expected_font_metrics(IDWriteFontFace *fontface, DWRITE_FONT_METRICS1 *metrics)
2026 void *os2_context, *head_context, *post_context, *hhea_context;
2027 const TT_OS2_V2 *tt_os2;
2028 const TT_HEAD *tt_head;
2029 const TT_POST *tt_post;
2030 const TT_HHEA *tt_hhea;
2031 UINT32 size;
2032 BOOL exists;
2033 HRESULT hr;
2035 memset(metrics, 0, sizeof(*metrics));
2037 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
2038 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2039 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void**)&tt_head, &size, &head_context, &exists);
2040 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2041 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HHEA_TAG, (const void**)&tt_hhea, &size, &hhea_context, &exists);
2042 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2043 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_POST_TAG, (const void**)&tt_post, &size, &post_context, &exists);
2044 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2046 if (tt_head) {
2047 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
2048 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
2049 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
2050 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
2051 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
2054 if (tt_os2) {
2055 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
2056 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
2057 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
2058 metrics->descent = descent < 0 ? -descent : 0;
2059 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
2060 metrics->hasTypographicMetrics = TRUE;
2062 else {
2063 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
2064 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
2065 interpreted as large unsigned value. */
2066 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
2068 if (tt_hhea) {
2069 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
2070 INT32 linegap;
2072 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
2073 metrics->ascent - metrics->descent;
2074 metrics->lineGap = linegap > 0 ? linegap : 0;
2078 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
2079 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
2081 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
2082 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
2083 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
2084 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
2085 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
2086 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
2087 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
2088 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
2090 else {
2091 metrics->strikethroughPosition = metrics->designUnitsPerEm / 3;
2092 if (tt_hhea) {
2093 metrics->ascent = GET_BE_WORD(tt_hhea->ascender);
2094 metrics->descent = abs((SHORT)GET_BE_WORD(tt_hhea->descender));
2098 if (tt_post) {
2099 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
2100 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
2103 if (metrics->underlineThickness == 0)
2104 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
2105 if (metrics->strikethroughThickness == 0)
2106 metrics->strikethroughThickness = metrics->underlineThickness;
2108 if (tt_os2)
2109 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2110 if (tt_head)
2111 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2112 if (tt_hhea)
2113 IDWriteFontFace_ReleaseFontTable(fontface, hhea_context);
2114 if (tt_post)
2115 IDWriteFontFace_ReleaseFontTable(fontface, post_context);
2118 static void check_font_metrics(const WCHAR *nameW, IDWriteFontFace *fontface, const DWRITE_FONT_METRICS1 *expected)
2120 IDWriteFontFace1 *fontface1 = NULL;
2121 DWRITE_FONT_METRICS1 metrics;
2122 DWORD simulations;
2123 BOOL has_metrics1;
2125 has_metrics1 = SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1));
2126 simulations = IDWriteFontFace_GetSimulations(fontface);
2128 if (fontface1) {
2129 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
2130 IDWriteFontFace1_Release(fontface1);
2132 else
2133 IDWriteFontFace_GetMetrics(fontface, (DWRITE_FONT_METRICS *)&metrics);
2135 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
2137 ok(metrics.designUnitsPerEm == expected->designUnitsPerEm, "designUnitsPerEm %u, expected %u.\n",
2138 metrics.designUnitsPerEm, expected->designUnitsPerEm);
2139 ok(metrics.ascent == expected->ascent, "ascent %u, expected %u.\n", metrics.ascent, expected->ascent);
2140 ok(metrics.descent == expected->descent, "descent %u, expected %u.\n", metrics.descent, expected->descent);
2141 ok(metrics.lineGap == expected->lineGap, "lineGap %d, expected %d.\n", metrics.lineGap, expected->lineGap);
2142 ok(metrics.underlinePosition == expected->underlinePosition, "underlinePosition %d, expected %d.\n",
2143 metrics.underlinePosition, expected->underlinePosition);
2144 ok(metrics.underlineThickness == expected->underlineThickness, "underlineThickness %u, expected %u.\n",
2145 metrics.underlineThickness, expected->underlineThickness);
2146 ok(metrics.strikethroughPosition == expected->strikethroughPosition, "strikethroughPosition %d, expected %d.\n",
2147 metrics.strikethroughPosition, expected->strikethroughPosition);
2148 ok(metrics.strikethroughThickness == expected->strikethroughThickness, "strikethroughThickness %u, "
2149 "expected %u.\n", metrics.strikethroughThickness, expected->strikethroughThickness);
2151 if (has_metrics1)
2153 /* For simulated faces metrics are adjusted. Enable tests when exact pattern is understood. */
2154 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2156 winetest_pop_context();
2157 return;
2160 ok(metrics.hasTypographicMetrics == expected->hasTypographicMetrics, "hasTypographicMetrics %d, "
2161 "expected %d.\n", metrics.hasTypographicMetrics, expected->hasTypographicMetrics);
2162 ok(metrics.glyphBoxLeft == expected->glyphBoxLeft, "glyphBoxLeft %d, expected %d.\n",
2163 metrics.glyphBoxLeft, expected->glyphBoxLeft);
2164 ok(metrics.glyphBoxTop == expected->glyphBoxTop, "glyphBoxTop %d, expected %d.\n",
2165 metrics.glyphBoxTop, expected->glyphBoxTop);
2166 ok(metrics.glyphBoxRight == expected->glyphBoxRight, "glyphBoxRight %d, expected %d.\n",
2167 metrics.glyphBoxRight, expected->glyphBoxRight);
2168 ok(metrics.glyphBoxBottom == expected->glyphBoxBottom, "glyphBoxBottom %d, expected %d.\n",
2169 metrics.glyphBoxBottom, expected->glyphBoxBottom);
2171 ok(metrics.subscriptPositionX == expected->subscriptPositionX, "subscriptPositionX %d, expected %d.\n",
2172 metrics.subscriptPositionX, expected->subscriptPositionX);
2173 ok(metrics.subscriptPositionY == expected->subscriptPositionY, "subscriptPositionY %d, expected %d.\n",
2174 metrics.subscriptPositionY, expected->subscriptPositionY);
2175 ok(metrics.subscriptSizeX == expected->subscriptSizeX, "subscriptSizeX %d, expected %d.\n",
2176 metrics.subscriptSizeX, expected->subscriptSizeX);
2177 ok(metrics.subscriptSizeY == expected->subscriptSizeY, "subscriptSizeY %d, expected %d.\n",
2178 metrics.subscriptSizeY, expected->subscriptSizeY);
2179 ok(metrics.superscriptPositionX == expected->superscriptPositionX, "superscriptPositionX %d, expected %d.\n",
2180 metrics.superscriptPositionX, expected->superscriptPositionX);
2181 ok(metrics.superscriptPositionY == expected->superscriptPositionY, "superscriptPositionY %d, expected %d.\n",
2182 metrics.superscriptPositionY, expected->superscriptPositionY);
2183 ok(metrics.superscriptSizeX == expected->superscriptSizeX, "superscriptSizeX %d, expected %d.\n",
2184 metrics.superscriptSizeX, expected->superscriptSizeX);
2185 ok(metrics.superscriptSizeY == expected->superscriptSizeY, "superscriptSizeY %d, expected %d.\n",
2186 metrics.superscriptSizeY, expected->superscriptSizeY);
2189 winetest_pop_context();
2192 static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
2194 BOOL exists = FALSE;
2195 UINT32 index;
2196 HRESULT hr;
2198 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
2199 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2200 if (!exists)
2201 index = 0;
2202 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
2203 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2206 static void test_GetMetrics(void)
2208 DWRITE_FONT_METRICS metrics, metrics2;
2209 IDWriteFontCollection *syscollection;
2210 IDWriteGdiInterop *interop;
2211 IDWriteFontFace *fontface;
2212 IDWriteFactory *factory;
2213 OUTLINETEXTMETRICW otm;
2214 IDWriteFontFile *file;
2215 IDWriteFont1 *font1;
2216 IDWriteFont *font;
2217 LOGFONTW logfont;
2218 UINT32 count, i;
2219 HRESULT hr;
2220 HDC hdc;
2221 HFONT hfont;
2222 ULONG ref;
2223 int ret;
2225 factory = create_factory();
2227 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2228 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2230 memset(&logfont, 0, sizeof(logfont));
2231 logfont.lfHeight = 12;
2232 logfont.lfWidth = 12;
2233 logfont.lfWeight = FW_NORMAL;
2234 logfont.lfItalic = 1;
2235 lstrcpyW(logfont.lfFaceName, L"Tahoma");
2237 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2238 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2240 hfont = CreateFontIndirectW(&logfont);
2241 hdc = CreateCompatibleDC(0);
2242 SelectObject(hdc, hfont);
2244 otm.otmSize = sizeof(otm);
2245 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
2246 ok(ret, "got %d\n", ret);
2247 DeleteDC(hdc);
2248 DeleteObject(hfont);
2250 if (0) /* crashes on native */
2251 IDWriteFont_GetMetrics(font, NULL);
2253 memset(&metrics, 0, sizeof(metrics));
2254 IDWriteFont_GetMetrics(font, &metrics);
2256 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2257 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2258 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2259 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2260 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2261 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2262 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2263 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2264 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2265 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2267 hr = IDWriteFont_CreateFontFace(font, &fontface);
2268 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2270 memset(&metrics, 0, sizeof(metrics));
2271 IDWriteFontFace_GetMetrics(fontface, &metrics);
2273 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2274 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2275 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2276 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2277 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2278 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2279 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2280 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2281 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2282 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2284 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
2285 if (hr == S_OK) {
2286 DWRITE_FONT_METRICS1 metrics1;
2287 IDWriteFontFace1 *fontface1;
2289 memset(&metrics1, 0, sizeof(metrics1));
2290 IDWriteFont1_GetMetrics(font1, &metrics1);
2292 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2293 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2294 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2295 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2296 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2297 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2298 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2299 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2300 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2301 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2302 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2303 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2304 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2305 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2306 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2307 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2308 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2309 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2310 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2311 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2312 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2314 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2315 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2317 memset(&metrics1, 0, sizeof(metrics1));
2318 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2320 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2321 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2322 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2323 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2324 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2325 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2326 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2327 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2328 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2329 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2330 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2331 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2332 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2333 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2334 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2335 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2336 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2337 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2338 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2339 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2340 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2342 IDWriteFontFace1_Release(fontface1);
2343 IDWriteFont1_Release(font1);
2345 else
2346 win_skip("DWRITE_FONT_METRICS1 is not supported.\n");
2348 IDWriteFontFace_Release(fontface);
2349 IDWriteFont_Release(font);
2350 IDWriteGdiInterop_Release(interop);
2352 /* bold simulation affects returned font metrics */
2353 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
2355 /* create regulat Tahoma with bold simulation */
2356 hr = IDWriteFont_CreateFontFace(font, &fontface);
2357 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2359 count = 1;
2360 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
2361 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2363 IDWriteFontFace_GetMetrics(fontface, &metrics);
2364 ok(IDWriteFontFace_GetSimulations(fontface) == 0, "wrong simulations flags\n");
2365 IDWriteFontFace_Release(fontface);
2367 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
2368 0, DWRITE_FONT_SIMULATIONS_BOLD, &fontface);
2369 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2370 IDWriteFontFace_GetMetrics(fontface, &metrics2);
2371 ok(IDWriteFontFace_GetSimulations(fontface) == DWRITE_FONT_SIMULATIONS_BOLD, "wrong simulations flags\n");
2373 ok(metrics.ascent == metrics2.ascent, "got %u, %u\n", metrics2.ascent, metrics.ascent);
2374 ok(metrics.descent == metrics2.descent, "got %u, %u\n", metrics2.descent, metrics.descent);
2375 ok(metrics.lineGap == metrics2.lineGap, "got %d, %d\n", metrics2.lineGap, metrics.lineGap);
2376 ok(metrics.capHeight == metrics2.capHeight, "got %u, %u\n", metrics2.capHeight, metrics.capHeight);
2377 ok(metrics.xHeight == metrics2.xHeight, "got %u, %u\n", metrics2.xHeight, metrics.xHeight);
2378 ok(metrics.underlinePosition == metrics2.underlinePosition, "got %d, %d\n", metrics2.underlinePosition,
2379 metrics.underlinePosition);
2380 ok(metrics.underlineThickness == metrics2.underlineThickness, "got %u, %u\n", metrics2.underlineThickness,
2381 metrics.underlineThickness);
2382 ok(metrics.strikethroughPosition == metrics2.strikethroughPosition, "got %d, %d\n", metrics2.strikethroughPosition,
2383 metrics.strikethroughPosition);
2384 ok(metrics.strikethroughThickness == metrics2.strikethroughThickness, "got %u, %u\n", metrics2.strikethroughThickness,
2385 metrics.strikethroughThickness);
2387 IDWriteFontFile_Release(file);
2388 IDWriteFontFace_Release(fontface);
2389 IDWriteFont_Release(font);
2391 /* test metrics for whole system collection */
2392 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
2393 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2394 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
2396 for (i = 0; i < count; i++) {
2397 DWRITE_FONT_METRICS1 expected_metrics;
2398 WCHAR familyW[256], faceW[256];
2399 IDWriteLocalizedStrings *names;
2400 IDWriteFontFamily *family;
2401 UINT32 fontcount, j;
2402 IDWriteFont *font;
2404 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
2405 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2407 fontcount = IDWriteFontFamily_GetFontCount(family);
2409 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2410 ok(hr == S_OK, "Failed to get family names, hr %#lx.\n", hr);
2411 get_enus_string(names, familyW, ARRAY_SIZE(familyW));
2412 IDWriteLocalizedStrings_Release(names);
2414 for (j = 0; j < fontcount; j++) {
2415 WCHAR nameW[256];
2417 hr = IDWriteFontFamily_GetFont(family, j, &font);
2418 ok(hr == S_OK, "Failed to get a font, hr %#lx.\n", hr);
2420 hr = IDWriteFont_CreateFontFace(font, &fontface);
2421 ok(hr == S_OK, "Failed to create face instance, hr %#lx.\n", hr);
2423 hr = IDWriteFont_GetFaceNames(font, &names);
2424 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
2425 get_enus_string(names, faceW, ARRAY_SIZE(faceW));
2426 IDWriteLocalizedStrings_Release(names);
2428 IDWriteFont_Release(font);
2430 get_combined_font_name(familyW, faceW, nameW);
2432 if (has_face_variations(fontface))
2434 static int once;
2435 if (!once++)
2436 skip("GetMetrics() test does not support variable fonts.\n");
2437 IDWriteFontFace_Release(fontface);
2438 continue;
2441 get_expected_font_metrics(fontface, &expected_metrics);
2442 check_font_metrics(nameW, fontface, &expected_metrics);
2444 IDWriteFontFace_Release(fontface);
2447 IDWriteFontFamily_Release(family);
2449 IDWriteFontCollection_Release(syscollection);
2450 ref = IDWriteFactory_Release(factory);
2451 ok(ref == 0, "factory not released, %lu\n", ref);
2454 static void test_system_fontcollection(void)
2456 IDWriteFontCollection *collection, *coll2;
2457 IDWriteLocalFontFileLoader *localloader;
2458 IDWriteFontCollection1 *collection1;
2459 IDWriteFontCollection2 *collection2;
2460 IDWriteFontCollection3 *collection3;
2461 IDWriteFactory *factory, *factory2;
2462 IDWriteFontFileLoader *loader;
2463 IDWriteFontFamily *family;
2464 IDWriteFontFace *fontface;
2465 IDWriteFactory6 *factory6;
2466 IDWriteFontFile *file;
2467 IDWriteFont *font;
2468 HRESULT hr;
2469 ULONG ref;
2470 UINT32 i;
2471 BOOL ret;
2473 factory = create_factory();
2475 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2476 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2478 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, FALSE);
2479 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2480 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2481 IDWriteFontCollection_Release(coll2);
2483 factory2 = create_factory();
2484 hr = IDWriteFactory_GetSystemFontCollection(factory2, &coll2, FALSE);
2485 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2486 ok(coll2 != collection, "got %p, was %p\n", coll2, collection);
2487 IDWriteFontCollection_Release(coll2);
2488 IDWriteFactory_Release(factory2);
2490 i = IDWriteFontCollection_GetFontFamilyCount(collection);
2491 ok(i, "got %u\n", i);
2493 /* invalid index */
2494 family = (void*)0xdeadbeef;
2495 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2496 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
2497 ok(family == NULL, "got %p\n", family);
2499 ret = FALSE;
2500 i = (UINT32)-1;
2501 hr = IDWriteFontCollection_FindFamilyName(collection, L"Tahoma", &i, &ret);
2502 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2503 ok(ret, "got %d\n", ret);
2504 ok(i != (UINT32)-1, "got %u\n", i);
2506 ret = FALSE;
2507 i = (UINT32)-1;
2508 hr = IDWriteFontCollection_FindFamilyName(collection, L"TAHOMA", &i, &ret);
2509 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2510 ok(ret, "got %d\n", ret);
2511 ok(i != (UINT32)-1, "got %u\n", i);
2513 ret = FALSE;
2514 i = (UINT32)-1;
2515 hr = IDWriteFontCollection_FindFamilyName(collection, L"tAhOmA", &i, &ret);
2516 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2517 ok(ret, "got %d\n", ret);
2518 ok(i != (UINT32)-1, "got %u\n", i);
2520 /* get back local file loader */
2521 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2522 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2524 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2525 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2526 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2527 IDWriteFontFamily_Release(family);
2529 hr = IDWriteFont_CreateFontFace(font, &fontface);
2530 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2531 IDWriteFont_Release(font);
2533 i = 1;
2534 file = NULL;
2535 hr = IDWriteFontFace_GetFiles(fontface, &i, &file);
2536 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2537 ok(file != NULL, "got %p\n", file);
2538 IDWriteFontFace_Release(fontface);
2540 hr = IDWriteFontFile_GetLoader(file, &loader);
2541 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2542 IDWriteFontFile_Release(file);
2544 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2545 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2546 IDWriteLocalFontFileLoader_Release(localloader);
2548 /* local loader is not registered by default */
2549 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
2550 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "Unexpected hr %#lx.\n", hr);
2551 hr = IDWriteFactory_UnregisterFontFileLoader(factory, loader);
2552 ok(hr == S_OK || broken(hr == E_INVALIDARG), "Unexpected hr %#lx.\n", hr);
2554 /* try with a different factory */
2555 factory2 = create_factory();
2556 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2557 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "Unexpected hr %#lx.\n", hr);
2558 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2559 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
2560 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2561 ok(hr == S_OK || broken(hr == E_INVALIDARG), "Unexpected hr %#lx.\n", hr);
2562 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2563 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2564 IDWriteFactory_Release(factory2);
2566 IDWriteFontFileLoader_Release(loader);
2568 ret = TRUE;
2569 i = 0;
2570 hr = IDWriteFontCollection_FindFamilyName(collection, L"Blah!", &i, &ret);
2571 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2572 ok(!ret, "got %d\n", ret);
2573 ok(i == (UINT32)-1, "got %u\n", i);
2575 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection1, (void**)&collection1);
2576 if (hr == S_OK) {
2577 IDWriteFontSet *fontset, *fontset2;
2578 IDWriteFontFamily1 *family1;
2579 IDWriteFactory3 *factory3;
2581 hr = IDWriteFontCollection1_QueryInterface(collection1, &IID_IDWriteFontCollection, (void**)&coll2);
2582 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2583 ok(coll2 == collection, "got %p, %p\n", collection, coll2);
2584 IDWriteFontCollection_Release(coll2);
2586 family1 = (void*)0xdeadbeef;
2587 hr = IDWriteFontCollection1_GetFontFamily(collection1, ~0u, &family1);
2588 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
2589 ok(family1 == NULL, "got %p\n", family1);
2591 hr = IDWriteFontCollection1_GetFontFamily(collection1, 0, &family1);
2592 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2593 IDWriteFontFamily1_Release(family1);
2595 /* system fontset */
2596 EXPECT_REF(collection1, 2);
2597 EXPECT_REF(factory, 2);
2598 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset);
2599 todo_wine
2600 ok(hr == S_OK, "Failed to get fontset, hr %#lx.\n", hr);
2601 if (hr == S_OK) {
2602 EXPECT_REF(collection1, 2);
2603 EXPECT_REF(factory, 2);
2604 EXPECT_REF(fontset, 1);
2606 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset2);
2607 ok(hr == S_OK, "Failed to get fontset, hr %#lx.\n", hr);
2608 ok(fontset != fontset2, "Expected new fontset instance.\n");
2609 EXPECT_REF(fontset2, 1);
2610 IDWriteFontSet_Release(fontset2);
2612 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3);
2613 ok(hr == S_OK, "Failed to get IDWriteFactory3 interface, hr %#lx.\n", hr);
2615 EXPECT_REF(factory, 3);
2616 hr = IDWriteFactory3_GetSystemFontSet(factory3, &fontset2);
2617 ok(hr == S_OK, "Failed to get system font set, hr %#lx.\n", hr);
2618 ok(fontset != fontset2, "Expected new fontset instance.\n");
2619 EXPECT_REF(fontset2, 1);
2620 EXPECT_REF(factory, 4);
2622 IDWriteFontSet_Release(fontset2);
2623 IDWriteFontSet_Release(fontset);
2625 IDWriteFactory3_Release(factory3);
2627 IDWriteFontCollection1_Release(collection1);
2629 else
2630 win_skip("IDWriteFontCollection1 is not supported.\n");
2632 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
2633 if (SUCCEEDED(hr))
2635 HANDLE event;
2637 event = IDWriteFontCollection3_GetExpirationEvent(collection3);
2638 todo_wine
2639 ok(!!event, "Expected event handle.\n");
2641 check_familymodel(collection3, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE);
2643 IDWriteFontCollection3_Release(collection3);
2645 else
2646 win_skip("IDWriteFontCollection3 is not supported.\n");
2648 /* With specified family model. */
2649 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory6, (void **)&factory6);
2650 if (SUCCEEDED(hr))
2652 IDWriteFontCollection2 *c2;
2654 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
2655 &collection2);
2656 todo_wine
2657 ok(hr == S_OK, "Failed to get collection, hr %#lx.\n", hr);
2658 if (SUCCEEDED(hr))
2660 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC, &c2);
2661 ok(hr == S_OK, "Failed to get collection, hr %#lx.\n", hr);
2662 ok(c2 == collection2 && collection != (IDWriteFontCollection *)c2, "Unexpected collection instance.\n");
2663 IDWriteFontCollection2_Release(c2);
2664 IDWriteFontCollection2_Release(collection2);
2666 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE,
2667 &collection2);
2668 ok(hr == S_OK, "Failed to get collection, hr %#lx.\n", hr);
2669 IDWriteFontCollection2_Release(collection2);
2671 IDWriteFactory6_Release(factory6);
2673 else
2674 win_skip("IDWriteFactory6 is not supported.\n");
2676 ref = IDWriteFontCollection_Release(collection);
2677 ok(!ref, "Collection wasn't released, %lu.\n", ref);
2678 ref = IDWriteFactory_Release(factory);
2679 ok(!ref, "Factory wasn't released, %lu.\n", ref);
2682 static void get_logfont_from_font(IDWriteFont *font, LOGFONTW *logfont)
2684 void *os2_context, *head_context;
2685 IDWriteLocalizedStrings *names;
2686 DWRITE_FONT_SIMULATIONS sim;
2687 IDWriteFontFace *fontface;
2688 const TT_OS2_V2 *tt_os2;
2689 DWRITE_FONT_STYLE style;
2690 const TT_HEAD *tt_head;
2691 LONG weight;
2692 UINT32 size;
2693 BOOL exists;
2694 HRESULT hr;
2696 /* These are rendering time properties. */
2697 logfont->lfHeight = 0;
2698 logfont->lfWidth = 0;
2699 logfont->lfEscapement = 0;
2700 logfont->lfOrientation = 0;
2701 logfont->lfUnderline = 0;
2702 logfont->lfStrikeOut = 0;
2704 logfont->lfWeight = 0;
2705 logfont->lfItalic = 0;
2707 hr = IDWriteFont_CreateFontFace(font, &fontface);
2708 ok(hr == S_OK, "Failed to create font face, %#lx\n", hr);
2710 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size,
2711 &os2_context, &exists);
2712 ok(hr == S_OK, "Failed to get OS/2 table, %#lx\n", hr);
2714 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void **)&tt_head, &size,
2715 &head_context, &exists);
2716 ok(hr == S_OK, "Failed to get head table, %#lx\n", hr);
2718 sim = IDWriteFont_GetSimulations(font);
2720 /* lfWeight */
2721 weight = FW_REGULAR;
2722 if (tt_os2) {
2723 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
2725 if (usWeightClass >= 1 && usWeightClass <= 9)
2726 usWeightClass *= 100;
2728 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
2729 weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
2730 else if (usWeightClass > 0)
2731 weight = usWeightClass;
2733 else if (tt_head) {
2734 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2735 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
2736 weight = DWRITE_FONT_WEIGHT_BOLD;
2738 if (sim & DWRITE_FONT_SIMULATIONS_BOLD)
2739 weight += (FW_BOLD - FW_REGULAR) / 2 + 1;
2740 logfont->lfWeight = weight;
2742 /* lfItalic */
2743 if (IDWriteFont_GetSimulations(font) & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2744 logfont->lfItalic = 1;
2746 style = IDWriteFont_GetStyle(font);
2747 if (!logfont->lfItalic && ((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE))) {
2748 if (tt_os2) {
2749 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
2750 logfont->lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
2752 else if (tt_head) {
2753 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2754 logfont->lfItalic = !!(macStyle & TT_HEAD_MACSTYLE_ITALIC);
2758 /* lfFaceName */
2759 exists = FALSE;
2760 logfont->lfFaceName[0] = 0;
2761 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &exists);
2762 if (SUCCEEDED(hr))
2764 if (exists)
2766 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
2767 WCHAR nameW[256];
2768 UINT32 index;
2770 /* Fallback to en-us if there's no string for user locale. */
2771 exists = FALSE;
2772 if (GetSystemDefaultLocaleName(localeW, ARRAY_SIZE(localeW)))
2773 IDWriteLocalizedStrings_FindLocaleName(names, localeW, &index, &exists);
2775 if (!exists)
2776 IDWriteLocalizedStrings_FindLocaleName(names, L"en-us", &index, &exists);
2778 if (exists) {
2779 nameW[0] = 0;
2780 hr = IDWriteLocalizedStrings_GetString(names, index, nameW, ARRAY_SIZE(nameW));
2781 ok(hr == S_OK, "Failed to get name string, hr %#lx.\n", hr);
2782 lstrcpynW(logfont->lfFaceName, nameW, ARRAY_SIZE(logfont->lfFaceName));
2786 IDWriteLocalizedStrings_Release(names);
2789 if (tt_os2)
2790 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2791 if (tt_head)
2792 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2793 IDWriteFontFace_Release(fontface);
2796 static void test_ConvertFontFaceToLOGFONT(void)
2798 IDWriteFontCollection *collection;
2799 IDWriteGdiInterop *interop;
2800 IDWriteFontFace *fontface;
2801 IDWriteFactory *factory;
2802 LOGFONTW logfont;
2803 UINT32 count, i;
2804 HRESULT hr;
2805 ULONG ref;
2807 factory = create_factory();
2809 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2810 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2812 if (0) /* crashes on native */
2814 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, NULL);
2815 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, NULL);
2817 memset(&logfont, 0xcc, sizeof(logfont));
2818 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, &logfont);
2819 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2820 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2822 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2823 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2825 count = IDWriteFontCollection_GetFontFamilyCount(collection);
2826 for (i = 0; i < count; i++) {
2827 WCHAR nameW[128], familynameW[64], facenameW[64];
2828 IDWriteLocalizedStrings *names;
2829 DWRITE_FONT_SIMULATIONS sim;
2830 IDWriteFontFamily *family;
2831 UINT32 font_count, j;
2832 IDWriteFont *font;
2833 LOGFONTW lf;
2835 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2836 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2838 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2839 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2841 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
2842 IDWriteLocalizedStrings_Release(names);
2844 font_count = IDWriteFontFamily_GetFontCount(family);
2846 for (j = 0; j < font_count; j++) {
2847 IDWriteFontFace *fontface;
2849 hr = IDWriteFontFamily_GetFont(family, j, &font);
2850 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2852 hr = IDWriteFont_GetFaceNames(font, &names);
2853 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2855 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
2856 IDWriteLocalizedStrings_Release(names);
2858 get_combined_font_name(familynameW, facenameW, nameW);
2860 hr = IDWriteFont_CreateFontFace(font, &fontface);
2861 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2863 if (has_face_variations(fontface))
2865 static int once;
2866 if (!once++)
2867 skip("ConvertFontFaceToLOGFONT() test does not support variable fonts.\n");
2868 IDWriteFontFace_Release(fontface);
2869 IDWriteFont_Release(font);
2870 continue;
2873 memset(&logfont, 0xcc, sizeof(logfont));
2874 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, &logfont);
2875 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2877 sim = IDWriteFontFace_GetSimulations(fontface);
2878 get_logfont_from_font(font, &lf);
2880 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
2882 ok(logfont.lfWeight == lf.lfWeight, "Unexpected lfWeight %ld, expected lfWeight %ld, font weight %d, "
2883 "bold simulation %s.\n", logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
2884 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
2885 ok(logfont.lfItalic == lf.lfItalic, "Unexpected italic flag %d, oblique simulation %s.\n",
2886 logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
2887 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "Unexpected facename %s, expected %s\n",
2888 wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
2890 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "Unexpected output precision %d.\n", logfont.lfOutPrecision);
2891 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "Unexpected clipping precision %d.\n", logfont.lfClipPrecision);
2892 ok(logfont.lfQuality == DEFAULT_QUALITY, "Unexpected quality %d.\n", logfont.lfQuality);
2893 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "Unexpected pitch %d.\n", logfont.lfPitchAndFamily);
2895 winetest_pop_context();
2897 IDWriteFontFace_Release(fontface);
2898 IDWriteFont_Release(font);
2901 IDWriteFontFamily_Release(family);
2904 IDWriteFontCollection_Release(collection);
2905 IDWriteGdiInterop_Release(interop);
2906 ref = IDWriteFactory_Release(factory);
2907 ok(ref == 0, "factory not released, %lu\n", ref);
2910 static HRESULT WINAPI fontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2912 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
2914 *obj = iface;
2915 IDWriteFontFileEnumerator_AddRef(iface);
2916 return S_OK;
2918 return E_NOINTERFACE;
2921 static ULONG WINAPI fontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2923 return 2;
2926 static ULONG WINAPI fontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2928 return 1;
2931 static HRESULT WINAPI fontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2933 *file = NULL;
2934 return E_FAIL;
2937 static HRESULT WINAPI fontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2939 *current = FALSE;
2940 return S_OK;
2943 static const struct IDWriteFontFileEnumeratorVtbl dwritefontfileenumeratorvtbl =
2945 fontfileenumerator_QueryInterface,
2946 fontfileenumerator_AddRef,
2947 fontfileenumerator_Release,
2948 fontfileenumerator_MoveNext,
2949 fontfileenumerator_GetCurrentFontFile,
2952 struct collection_loader
2954 IDWriteFontCollectionLoader IDWriteFontCollectionLoader_iface;
2955 LONG ref;
2958 static inline struct collection_loader *impl_from_IDWriteFontCollectionLoader(IDWriteFontCollectionLoader *iface)
2960 return CONTAINING_RECORD(iface, struct collection_loader, IDWriteFontCollectionLoader_iface);
2963 static HRESULT WINAPI fontcollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
2965 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2967 if (IsEqualIID(&IID_IDWriteFontCollectionLoader, riid) ||
2968 IsEqualIID(&IID_IUnknown, riid))
2970 *obj = &loader->IDWriteFontCollectionLoader_iface;
2971 IDWriteFontCollectionLoader_AddRef(iface);
2972 return S_OK;
2975 *obj = NULL;
2976 return E_NOINTERFACE;
2979 static ULONG WINAPI fontcollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
2981 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2982 return InterlockedIncrement(&loader->ref);
2985 static ULONG WINAPI fontcollectionloader_Release(IDWriteFontCollectionLoader *iface)
2987 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2988 ULONG ref = InterlockedDecrement(&loader->ref);
2990 if (!ref)
2991 free(loader);
2993 return ref;
2996 static HRESULT WINAPI fontcollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory, const void *key,
2997 UINT32 key_size, IDWriteFontFileEnumerator **ret)
2999 static IDWriteFontFileEnumerator enumerator = { &dwritefontfileenumeratorvtbl };
3000 *ret = &enumerator;
3001 return S_OK;
3004 static const struct IDWriteFontCollectionLoaderVtbl dwritefontcollectionloadervtbl = {
3005 fontcollectionloader_QueryInterface,
3006 fontcollectionloader_AddRef,
3007 fontcollectionloader_Release,
3008 fontcollectionloader_CreateEnumeratorFromKey
3011 static IDWriteFontCollectionLoader *create_collection_loader(void)
3013 struct collection_loader *loader = malloc(sizeof(*loader));
3015 loader->IDWriteFontCollectionLoader_iface.lpVtbl = &dwritefontcollectionloadervtbl;
3016 loader->ref = 1;
3018 return &loader->IDWriteFontCollectionLoader_iface;
3021 static void test_CustomFontCollection(void)
3023 IDWriteFontCollectionLoader *loader, *loader2, *loader3;
3024 IDWriteFontCollection *font_collection = NULL;
3025 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
3026 struct test_fontcollectionloader resource_collection = { { &resourcecollectionloadervtbl }, &rloader };
3027 IDWriteFontFamily *family, *family2, *family3;
3028 IDWriteFontFace *idfontface, *idfontface2;
3029 IDWriteFontFile *fontfile, *fontfile2;
3030 IDWriteLocalizedStrings *string;
3031 IDWriteFont *idfont, *idfont2;
3032 IDWriteFactory *factory;
3033 UINT32 index, count;
3034 BOOL exists;
3035 HRESULT hr;
3036 HRSRC font;
3037 ULONG ref;
3039 factory = create_factory();
3041 loader = create_collection_loader();
3042 loader2 = create_collection_loader();
3043 loader3 = create_collection_loader();
3045 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, NULL);
3046 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3048 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, NULL);
3049 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3051 EXPECT_REF(loader, 1);
3052 EXPECT_REF(loader2, 1);
3054 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
3055 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3056 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader2);
3057 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3058 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
3059 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
3061 EXPECT_REF(loader, 2);
3062 EXPECT_REF(loader2, 2);
3064 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3065 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3066 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
3067 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3069 /* Loader wasn't registered. */
3070 font_collection = (void*)0xdeadbeef;
3071 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader3, "Billy", 6, &font_collection);
3072 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3073 ok(font_collection == NULL, "got %p\n", font_collection);
3075 EXPECT_REF(factory, 1);
3076 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader, "Billy", 6, &font_collection);
3077 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3078 todo_wine
3079 EXPECT_REF(factory, 1);
3080 EXPECT_REF(loader, 2);
3081 IDWriteFontCollection_Release(font_collection);
3083 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader2, "Billy", 6, &font_collection);
3084 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3085 IDWriteFontCollection_Release(font_collection);
3087 font_collection = (void*)0xdeadbeef;
3088 hr = IDWriteFactory_CreateCustomFontCollection(factory, (IDWriteFontCollectionLoader*)0xdeadbeef, "Billy", 6, &font_collection);
3089 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3090 ok(font_collection == NULL, "got %p\n", font_collection);
3092 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3093 ok(font != NULL, "Failed to find font resource\n");
3095 hr = IDWriteFactory_CreateCustomFontCollection(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface,
3096 &font, sizeof(HRSRC), &font_collection);
3097 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
3098 EXPECT_REF(font_collection, 1);
3100 index = 1;
3101 exists = FALSE;
3102 hr = IDWriteFontCollection_FindFamilyName(font_collection, L"wine_test", &index, &exists);
3103 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3104 ok(index == 0, "got index %i\n", index);
3105 ok(exists, "got exists %i\n", exists);
3107 count = IDWriteFontCollection_GetFontFamilyCount(font_collection);
3108 ok(count == 1, "got %u\n", count);
3110 family = NULL;
3111 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family);
3112 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3113 EXPECT_REF(family, 1);
3115 family2 = NULL;
3116 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family2);
3117 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3118 EXPECT_REF(family2, 1);
3119 ok(family != family2, "got %p, %p\n", family, family2);
3121 hr = IDWriteFontFamily_GetFont(family, 0, &idfont);
3122 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3123 EXPECT_REF(idfont, 1);
3124 EXPECT_REF(family, 2);
3125 hr = IDWriteFontFamily_GetFont(family, 0, &idfont2);
3126 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3127 EXPECT_REF(idfont2, 1);
3128 EXPECT_REF(family, 3);
3129 ok(idfont != idfont2, "got %p, %p\n", idfont, idfont2);
3130 IDWriteFont_Release(idfont2);
3132 hr = IDWriteFont_GetInformationalStrings(idfont, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &string, &exists);
3133 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3134 ok(exists, "got %d\n", exists);
3135 EXPECT_REF(string, 1);
3136 IDWriteLocalizedStrings_Release(string);
3138 family3 = NULL;
3139 hr = IDWriteFont_GetFontFamily(idfont, &family3);
3140 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3141 EXPECT_REF(family, 3);
3142 ok(family == family3, "got %p, %p\n", family, family3);
3143 IDWriteFontFamily_Release(family3);
3145 idfontface = NULL;
3146 hr = IDWriteFont_CreateFontFace(idfont, &idfontface);
3147 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3148 EXPECT_REF(idfont, 1);
3150 idfont2 = NULL;
3151 hr = IDWriteFontFamily_GetFont(family2, 0, &idfont2);
3152 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3153 EXPECT_REF(idfont2, 1);
3154 EXPECT_REF(idfont, 1);
3155 ok(idfont2 != idfont, "Font instances should not match\n");
3157 idfontface2 = NULL;
3158 hr = IDWriteFont_CreateFontFace(idfont2, &idfontface2);
3159 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3160 ok(idfontface2 == idfontface, "fontfaces should match\n");
3162 index = 1;
3163 fontfile = NULL;
3164 hr = IDWriteFontFace_GetFiles(idfontface, &index, &fontfile);
3165 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3167 index = 1;
3168 fontfile2 = NULL;
3169 hr = IDWriteFontFace_GetFiles(idfontface2, &index, &fontfile2);
3170 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3171 ok(fontfile == fontfile2, "fontfiles should match\n");
3173 IDWriteFont_Release(idfont);
3174 IDWriteFont_Release(idfont2);
3175 IDWriteFontFile_Release(fontfile);
3176 IDWriteFontFile_Release(fontfile2);
3177 IDWriteFontFace_Release(idfontface);
3178 IDWriteFontFace_Release(idfontface2);
3179 IDWriteFontFamily_Release(family2);
3180 IDWriteFontFamily_Release(family);
3181 IDWriteFontCollection_Release(font_collection);
3183 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
3184 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3185 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
3186 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3187 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader2);
3188 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3189 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
3190 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3191 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3192 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3194 IDWriteFontCollectionLoader_Release(loader);
3195 IDWriteFontCollectionLoader_Release(loader2);
3196 IDWriteFontCollectionLoader_Release(loader3);
3198 ref = IDWriteFactory_Release(factory);
3199 ok(ref == 0, "factory not released, %lu\n", ref);
3202 static HRESULT WINAPI fontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
3204 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
3206 *obj = iface;
3207 IDWriteFontFileLoader_AddRef(iface);
3208 return S_OK;
3211 *obj = NULL;
3212 return E_NOINTERFACE;
3215 static ULONG WINAPI fontfileloader_AddRef(IDWriteFontFileLoader *iface)
3217 return 2;
3220 static ULONG WINAPI fontfileloader_Release(IDWriteFontFileLoader *iface)
3222 return 1;
3225 static HRESULT WINAPI fontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
3226 IDWriteFontFileStream **stream)
3228 return 0x8faecafe;
3231 static const struct IDWriteFontFileLoaderVtbl dwritefontfileloadervtbl = {
3232 fontfileloader_QueryInterface,
3233 fontfileloader_AddRef,
3234 fontfileloader_Release,
3235 fontfileloader_CreateStreamFromKey
3238 static void test_CreateCustomFontFileReference(void)
3240 IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl };
3241 IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl };
3242 IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl };
3243 IDWriteFactory *factory, *factory2;
3244 IDWriteFontFileLoader *loader;
3245 IDWriteFontFile *file, *file2;
3246 BOOL support;
3247 DWRITE_FONT_FILE_TYPE file_type;
3248 DWRITE_FONT_FACE_TYPE face_type;
3249 UINT32 count;
3250 IDWriteFontFace *face, *face2;
3251 HRESULT hr;
3252 HRSRC fontrsrc;
3253 UINT32 codePoints[1] = {0xa8};
3254 UINT16 indices[2];
3255 const void *key;
3256 UINT32 key_size;
3257 WCHAR *path;
3258 ULONG ref;
3260 path = create_testfontfile(test_fontfile);
3262 factory = create_factory();
3263 factory2 = create_factory();
3265 if (0) { /* crashes on win10 */
3266 hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
3267 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3269 /* local loader is accepted too */
3270 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3271 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3273 hr = IDWriteFontFile_GetLoader(file, &loader);
3274 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3276 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3277 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3279 hr = IDWriteFactory_CreateCustomFontFileReference(factory, key, key_size, loader, &file2);
3280 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3282 IDWriteFontFile_Release(file2);
3283 IDWriteFontFile_Release(file);
3284 IDWriteFontFileLoader_Release(loader);
3286 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3287 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3288 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader2);
3289 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3290 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3291 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
3292 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3293 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3295 file = NULL;
3296 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3297 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3298 IDWriteFontFile_Release(file);
3300 file = (void*)0xdeadbeef;
3301 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader3, &file);
3302 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3303 ok(file == NULL, "got %p\n", file);
3305 file = (void*)0xdeadbeef;
3306 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, NULL, &file);
3307 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3308 ok(file == NULL, "got %p\n", file);
3310 file = NULL;
3311 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3312 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3314 file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
3315 face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
3316 support = TRUE;
3317 count = 1;
3318 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3319 ok(hr == 0x8faecafe, "Unexpected hr %#lx.\n", hr);
3320 ok(support == FALSE, "got %i\n", support);
3321 ok(file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN, "got %i\n", file_type);
3322 ok(face_type == DWRITE_FONT_FACE_TYPE_UNKNOWN, "got %i\n", face_type);
3323 ok(count == 0, "got %i\n", count);
3325 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0, &face);
3326 ok(hr == 0x8faecafe, "Unexpected hr %#lx.\n", hr);
3327 IDWriteFontFile_Release(file);
3329 fontrsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3330 ok(fontrsrc != NULL, "Failed to find font resource\n");
3332 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file);
3333 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3335 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3336 face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3337 support = FALSE;
3338 count = 0;
3339 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3340 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3341 ok(support == TRUE, "got %i\n", support);
3342 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
3343 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
3344 ok(count == 1, "got %i\n", count);
3346 /* invalid index */
3347 face = (void*)0xdeadbeef;
3348 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 1, DWRITE_FONT_SIMULATIONS_NONE, &face);
3349 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3350 ok(face == NULL, "got %p\n", face);
3352 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
3353 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3355 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3356 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3357 /* fontface instances are reused starting with win7 */
3358 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3359 IDWriteFontFace_Release(face2);
3361 /* file was created with different factory */
3362 face2 = NULL;
3363 hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3364 todo_wine
3365 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3366 if (face2) {
3367 IDWriteFontFace_Release(face2);
3369 file2 = NULL;
3370 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2);
3371 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3372 ok(file != file2, "got %p, %p\n", file, file2);
3374 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3375 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3376 /* fontface instances are reused starting with win7 */
3377 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3378 IDWriteFontFace_Release(face2);
3379 IDWriteFontFile_Release(file2);
3381 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, NULL);
3382 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
3384 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, NULL);
3385 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
3387 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, indices);
3388 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3390 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, indices);
3391 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
3393 indices[0] = indices[1] = 11;
3394 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, indices);
3395 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3396 ok(indices[0] == 0, "got index %i\n", indices[0]);
3397 ok(indices[1] == 11, "got index %i\n", indices[1]);
3399 if (0) /* crashes on native */
3400 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, NULL);
3402 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 1, indices);
3403 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3404 ok(indices[0] == 7, "Unexpected glyph index, %u.\n", indices[0]);
3405 IDWriteFontFace_Release(face);
3406 IDWriteFontFile_Release(file);
3408 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3409 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3410 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3411 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3412 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader2);
3413 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3414 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3415 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3417 ref = IDWriteFactory_Release(factory2);
3418 ok(ref == 0, "factory not released, %lu\n", ref);
3419 ref = IDWriteFactory_Release(factory);
3420 ok(ref == 0, "factory not released, %lu\n", ref);
3421 DELETE_FONTFILE(path);
3424 static void test_CreateFontFileReference(void)
3426 HRESULT hr;
3427 IDWriteFontFile *ffile = NULL;
3428 BOOL support;
3429 DWRITE_FONT_FILE_TYPE type;
3430 DWRITE_FONT_FACE_TYPE face;
3431 UINT32 count;
3432 IDWriteFontFace *fface = NULL;
3433 IDWriteFactory *factory;
3434 WCHAR *path;
3435 ULONG ref;
3437 path = create_testfontfile(test_fontfile);
3438 factory = create_factory();
3440 ffile = (void*)0xdeadbeef;
3441 hr = IDWriteFactory_CreateFontFileReference(factory, NULL, NULL, &ffile);
3442 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n",hr);
3443 ok(ffile == NULL, "got %p\n", ffile);
3445 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &ffile);
3446 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
3448 support = FALSE;
3449 type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3450 face = DWRITE_FONT_FACE_TYPE_CFF;
3451 count = 0;
3452 hr = IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count);
3453 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3454 ok(support == TRUE, "got %i\n", support);
3455 ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type);
3456 ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face);
3457 ok(count == 1, "got %i\n", count);
3459 hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface);
3460 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3462 IDWriteFontFace_Release(fface);
3463 IDWriteFontFile_Release(ffile);
3464 ref = IDWriteFactory_Release(factory);
3465 ok(ref == 0, "factory not released, %lu\n", ref);
3467 DELETE_FONTFILE(path);
3470 static void test_shared_isolated(void)
3472 IDWriteFactory *isolated, *isolated2;
3473 IDWriteFactory *shared, *shared2;
3474 HRESULT hr;
3475 ULONG ref;
3477 /* invalid type */
3478 shared = NULL;
3479 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&shared);
3480 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3481 ok(shared != NULL, "got %p\n", shared);
3482 IDWriteFactory_Release(shared);
3484 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared);
3485 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3487 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3488 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3489 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3490 IDWriteFactory_Release(shared2);
3492 IDWriteFactory_Release(shared);
3494 /* we got 2 references, released 2 - still same pointer is returned */
3495 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3496 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3497 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3498 IDWriteFactory_Release(shared2);
3500 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated);
3501 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3503 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3504 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3505 ok(isolated != isolated2, "got %p, and %p\n", isolated, isolated2);
3506 IDWriteFactory_Release(isolated2);
3508 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IUnknown, (IUnknown**)&isolated2);
3509 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3510 IDWriteFactory_Release(isolated2);
3512 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3513 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3514 ok(shared != isolated2, "got %p, and %p\n", shared, isolated2);
3516 ref = IDWriteFactory_Release(isolated);
3517 ok(ref == 0, "factory not released, %lu\n", ref);
3518 ref = IDWriteFactory_Release(isolated2);
3519 ok(ref == 0, "factory not released, %lu\n", ref);
3522 struct dwrite_fonttable
3524 BYTE *data;
3525 void *context;
3526 UINT32 size;
3529 static WORD table_read_be_word(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
3531 if (!ptr)
3532 ptr = table->data;
3534 if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
3535 return 0;
3537 if (offset > table->size - sizeof(WORD))
3538 return 0;
3540 return GET_BE_WORD(*(WORD *)((BYTE *)ptr + offset));
3543 static DWORD table_read_be_dword(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
3545 if (!ptr)
3546 ptr = table->data;
3548 if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
3549 return 0;
3551 if (offset > table->size - sizeof(WORD))
3552 return 0;
3554 return GET_BE_DWORD(*(DWORD *)((BYTE *)ptr + offset));
3557 static void array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
3559 size_t new_capacity, max_capacity;
3560 void *new_elements;
3562 if (count <= *capacity)
3563 return;
3565 max_capacity = ~(SIZE_T)0 / size;
3566 if (count > max_capacity)
3567 return;
3569 new_capacity = max(4, *capacity);
3570 while (new_capacity < count && new_capacity <= max_capacity / 2)
3571 new_capacity *= 2;
3572 if (new_capacity < count)
3573 new_capacity = max_capacity;
3575 if (!(new_elements = realloc(*elements, new_capacity * size)))
3576 return;
3578 *elements = new_elements;
3579 *capacity = new_capacity;
3582 static void opentype_cmap_read_table(const struct dwrite_fonttable *table, UINT16 cmap_index, UINT32 *count,
3583 size_t *capacity, DWRITE_UNICODE_RANGE **ranges)
3585 const BYTE *tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
3586 struct cmap_encoding_record *record;
3587 DWORD table_offset;
3588 WORD format;
3589 int j;
3591 record = (struct cmap_encoding_record *)(tables + cmap_index * sizeof(*record));
3593 if (!(table_offset = table_read_be_dword(table, record, FIELD_OFFSET(struct cmap_encoding_record, offset))))
3594 return;
3596 format = table_read_be_word(table, NULL, table_offset);
3597 switch (format)
3599 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
3601 UINT16 segment_count = table_read_be_word(table, NULL, table_offset +
3602 FIELD_OFFSET(struct cmap_segmented_mapping_0, segCountX2)) / 2;
3603 DWORD start_code_offset = table_offset + sizeof(struct cmap_segmented_mapping_0) +
3604 sizeof(WORD) * segment_count;
3606 for (j = 0; j < segment_count; ++j) {
3607 WORD endcode = table_read_be_word(table, NULL, table_offset +
3608 FIELD_OFFSET(struct cmap_segmented_mapping_0, endCode) + j * sizeof(WORD));
3609 WORD first;
3611 if (endcode == 0xffff)
3612 break;
3614 first = table_read_be_word(table, NULL, start_code_offset + j * sizeof(WORD));
3616 array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
3617 (*ranges)[*count].first = first;
3618 (*ranges)[*count].last = endcode;
3619 (*count)++;
3621 break;
3623 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
3625 DWORD num_groups = table_read_be_dword(table, NULL, table_offset +
3626 FIELD_OFFSET(struct cmap_segmented_coverage, nGroups));
3628 for (j = 0; j < num_groups; ++j) {
3629 DWORD group_offset = table_offset + FIELD_OFFSET(struct cmap_segmented_coverage, groups) +
3630 j * sizeof(struct cmap_segmented_coverage_group);
3631 DWORD first = table_read_be_dword(table, NULL, group_offset +
3632 FIELD_OFFSET(struct cmap_segmented_coverage_group, startCharCode));
3633 DWORD last = table_read_be_dword(table, NULL, group_offset +
3634 FIELD_OFFSET(struct cmap_segmented_coverage_group, endCharCode));
3636 array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
3637 (*ranges)[*count].first = first;
3638 (*ranges)[*count].last = last;
3639 (*count)++;
3641 break;
3643 default:
3644 ok(0, "%u table format %#x unhandled.\n", cmap_index, format);
3648 static UINT32 opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *table, DWRITE_UNICODE_RANGE **ranges)
3650 int index_full = -1, index_bmp = -1;
3651 unsigned int i, count = 0;
3652 size_t capacity = 0;
3653 const BYTE *tables;
3654 WORD num_tables;
3656 *ranges = NULL;
3658 num_tables = table_read_be_word(table, 0, FIELD_OFFSET(struct cmap_header, num_tables));
3659 tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
3661 for (i = 0; i < num_tables; ++i)
3663 struct cmap_encoding_record *record = (struct cmap_encoding_record *)(tables + i * sizeof(*record));
3664 WORD platform, encoding;
3666 platform = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, platformID));
3667 encoding = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, encodingID));
3669 if (platform == OPENTYPE_CMAP_TABLE_PLATFORM_WIN)
3671 if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL)
3673 index_full = i;
3674 break;
3676 else if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP)
3677 index_bmp = i;
3681 if (index_full != -1)
3682 opentype_cmap_read_table(table, index_full, &count, &capacity, ranges);
3683 else if (index_bmp != -1)
3684 opentype_cmap_read_table(table, index_bmp, &count, &capacity, ranges);
3686 return count;
3689 static UINT32 fontface_get_expected_unicode_ranges(IDWriteFontFace1 *fontface, DWRITE_UNICODE_RANGE **out)
3691 struct dwrite_fonttable cmap;
3692 DWRITE_UNICODE_RANGE *ranges;
3693 UINT32 i, j, count;
3694 BOOL exists;
3695 HRESULT hr;
3697 *out = NULL;
3699 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_CMAP_TAG, (const void **)&cmap.data,
3700 &cmap.size, &cmap.context, &exists);
3701 if (FAILED(hr) || !exists)
3702 return 0;
3704 count = opentype_cmap_get_unicode_ranges(&cmap, &ranges);
3705 IDWriteFontFace1_ReleaseFontTable(fontface, cmap.context);
3707 *out = malloc(count * sizeof(**out));
3709 /* Eliminate duplicates and merge ranges together. */
3710 for (i = 0, j = 0; i < count; ++i) {
3711 if (j) {
3712 DWRITE_UNICODE_RANGE *prev = &(*out)[j-1];
3713 /* Merge adjacent ranges. */
3714 if (ranges[i].first == prev->last + 1) {
3715 prev->last = ranges[i].last;
3716 continue;
3719 (*out)[j++] = ranges[i];
3722 free(ranges);
3724 return j;
3727 static void test_GetUnicodeRanges(void)
3729 IDWriteFontCollection *syscollection;
3730 DWRITE_UNICODE_RANGE *ranges, r;
3731 IDWriteFontFile *ffile = NULL;
3732 IDWriteFontFace1 *fontface1;
3733 IDWriteFontFace *fontface;
3734 IDWriteFactory *factory;
3735 UINT32 count, i;
3736 HRESULT hr;
3737 HRSRC font;
3738 ULONG ref;
3740 factory = create_factory();
3742 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3743 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3745 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3746 ok(font != NULL, "Failed to find font resource\n");
3748 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile);
3749 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3751 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3752 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3753 IDWriteFontFile_Release(ffile);
3755 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3756 IDWriteFontFace_Release(fontface);
3757 if (hr != S_OK) {
3758 win_skip("GetUnicodeRanges() is not supported.\n");
3759 IDWriteFactory_Release(factory);
3760 return;
3763 count = 0;
3764 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
3765 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3766 ok(count > 0, "got %u\n", count);
3768 count = 1;
3769 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count);
3770 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3771 ok(count == 0, "got %u\n", count);
3773 count = 0;
3774 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count);
3775 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3776 ok(count > 1, "got %u\n", count);
3778 ranges = malloc(count*sizeof(DWRITE_UNICODE_RANGE));
3779 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
3780 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3782 ranges[0].first = ranges[0].last = 0;
3783 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count);
3784 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3785 ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last);
3787 free(ranges);
3789 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3790 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3792 IDWriteFontFace1_Release(fontface1);
3794 if (strcmp(winetest_platform, "wine")) {
3796 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
3797 ok(hr == S_OK, "Failed to get system collection, hr %#lx.\n", hr);
3799 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
3801 for (i = 0; i < count; i++) {
3802 WCHAR familynameW[256], facenameW[128];
3803 IDWriteLocalizedStrings *names;
3804 IDWriteFontFamily *family;
3805 UINT32 j, k, fontcount;
3806 IDWriteFont *font;
3808 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
3809 ok(hr == S_OK, "Failed to get font family, hr %#lx.\n", hr);
3811 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
3812 ok(hr == S_OK, "Failed to get family names, hr %#lx.\n", hr);
3814 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
3815 IDWriteLocalizedStrings_Release(names);
3817 fontcount = IDWriteFontFamily_GetFontCount(family);
3818 for (j = 0; j < fontcount; j++) {
3819 DWRITE_UNICODE_RANGE *expected_ranges = NULL;
3820 UINT32 range_count, expected_count;
3822 hr = IDWriteFontFamily_GetFont(family, j, &font);
3823 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
3825 hr = IDWriteFont_CreateFontFace(font, &fontface);
3826 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
3828 hr = IDWriteFont_GetFaceNames(font, &names);
3829 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
3830 IDWriteFont_Release(font);
3832 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
3834 IDWriteLocalizedStrings_Release(names);
3836 if (IDWriteFontFace_IsSymbolFont(fontface))
3838 static int once;
3839 if (!once++)
3840 skip("GetUnicodeRanges() test does not support symbol fonts.\n");
3841 IDWriteFontFace_Release(fontface);
3842 continue;
3845 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
3847 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &range_count);
3848 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
3850 ranges = malloc(range_count * sizeof(*ranges));
3852 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, range_count, ranges, &range_count);
3853 ok(hr == S_OK, "Failed to get ranges, hr %#lx.\n", hr);
3855 expected_count = fontface_get_expected_unicode_ranges(fontface1, &expected_ranges);
3856 ok(expected_count == range_count, "%s - %s: unexpected range count %u, expected %u.\n",
3857 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), range_count, expected_count);
3859 if (expected_count == range_count) {
3860 if (memcmp(expected_ranges, ranges, expected_count * sizeof(*ranges))) {
3861 for (k = 0; k < expected_count; ++k) {
3862 BOOL failed = memcmp(&expected_ranges[k], &ranges[k], sizeof(*ranges));
3863 ok(!failed, "%u: %s - %s mismatching range [%#x, %#x] vs [%#x, %#x].\n", k,
3864 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), ranges[k].first, ranges[k].last,
3865 expected_ranges[k].first, expected_ranges[k].last);
3866 if (failed)
3867 break;
3872 free(expected_ranges);
3873 free(ranges);
3875 IDWriteFontFace1_Release(fontface1);
3876 IDWriteFontFace_Release(fontface);
3879 IDWriteFontFamily_Release(family);
3882 IDWriteFontCollection_Release(syscollection);
3884 ref = IDWriteFactory_Release(factory);
3885 ok(ref == 0, "factory not released, %lu\n", ref);
3888 static void test_GetFontFromFontFace(void)
3890 IDWriteFontFace *fontface, *fontface2;
3891 IDWriteFontCollection *collection;
3892 IDWriteFont *font, *font2, *font3;
3893 IDWriteFontFamily *family;
3894 IDWriteFactory *factory;
3895 IDWriteFontFile *file;
3896 WCHAR *path;
3897 HRESULT hr;
3898 ULONG ref;
3900 factory = create_factory();
3902 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3903 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3905 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3906 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3908 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3909 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3910 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3912 hr = IDWriteFont_CreateFontFace(font, &fontface);
3913 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3915 font2 = NULL;
3916 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
3917 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3918 ok(font2 != font, "got %p, %p\n", font2, font);
3920 font3 = NULL;
3921 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3922 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3923 ok(font3 != font && font3 != font2, "got %p, %p, %p\n", font3, font2, font);
3925 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
3926 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3927 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3928 IDWriteFontFace_Release(fontface2);
3930 hr = IDWriteFont_CreateFontFace(font3, &fontface2);
3931 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3932 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3933 IDWriteFontFace_Release(fontface2);
3934 IDWriteFontFace_Release(fontface);
3935 IDWriteFont_Release(font3);
3936 IDWriteFactory_Release(factory);
3938 /* fontface that wasn't created from this collection */
3939 factory = create_factory();
3940 path = create_testfontfile(test_fontfile);
3942 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3943 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
3945 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3946 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3947 IDWriteFontFile_Release(file);
3949 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3950 ok(hr == DWRITE_E_NOFONT, "Unexpected hr %#lx.\n", hr);
3951 ok(font3 == NULL, "got %p\n", font3);
3952 IDWriteFontFace_Release(fontface);
3954 IDWriteFont_Release(font);
3955 IDWriteFont_Release(font2);
3956 IDWriteFontFamily_Release(family);
3957 IDWriteFontCollection_Release(collection);
3958 ref = IDWriteFactory_Release(factory);
3959 ok(ref == 0, "factory not released, %lu\n", ref);
3960 DELETE_FONTFILE(path);
3963 static void test_GetFirstMatchingFont(void)
3965 DWRITE_FONT_SIMULATIONS simulations;
3966 IDWriteFontCollection *collection;
3967 IDWriteFontFamily *family;
3968 IDWriteFont *font, *font2;
3969 IDWriteFactory *factory;
3970 HRESULT hr;
3971 ULONG ref;
3973 factory = create_factory();
3975 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3976 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3978 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3979 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3981 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3982 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3983 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3985 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3986 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
3987 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3988 ok(font != font2, "got %p, %p\n", font, font2);
3989 IDWriteFont_Release(font);
3990 IDWriteFont_Release(font2);
3992 /* out-of-range font props are allowed */
3993 hr = IDWriteFontFamily_GetFirstMatchingFont(family, 1000, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3994 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3995 IDWriteFont_Release(font);
3997 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, 10, DWRITE_FONT_STYLE_NORMAL, &font);
3998 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3999 IDWriteFont_Release(font);
4001 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
4002 10, &font);
4003 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4004 IDWriteFont_Release(font);
4006 IDWriteFontFamily_Release(family);
4008 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
4009 simulations = IDWriteFont_GetSimulations(font);
4010 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "%d\n", simulations);
4011 IDWriteFont_Release(font);
4013 IDWriteFontCollection_Release(collection);
4014 ref = IDWriteFactory_Release(factory);
4015 ok(ref == 0, "factory not released, %lu\n", ref);
4018 static void test_GetMatchingFonts(void)
4020 IDWriteFontCollection *collection;
4021 IDWriteFontFamily *family;
4022 IDWriteFactory *factory;
4023 IDWriteFontList *fontlist, *fontlist2;
4024 IDWriteFontList1 *fontlist1;
4025 IDWriteFontList2 *fontlist3;
4026 HRESULT hr;
4027 ULONG ref;
4029 factory = create_factory();
4031 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4032 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4034 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4035 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4037 /* out-of-range font props are allowed */
4038 hr = IDWriteFontFamily_GetMatchingFonts(family, 1000, DWRITE_FONT_STRETCH_NORMAL,
4039 DWRITE_FONT_STYLE_NORMAL, &fontlist);
4040 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4041 IDWriteFontList_Release(fontlist);
4043 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, 10,
4044 DWRITE_FONT_STYLE_NORMAL, &fontlist);
4045 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4046 IDWriteFontList_Release(fontlist);
4048 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
4049 10, &fontlist);
4050 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4051 IDWriteFontList_Release(fontlist);
4053 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
4054 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
4055 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4057 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
4058 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
4059 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4060 ok(fontlist != fontlist2, "got %p, %p\n", fontlist, fontlist2);
4061 IDWriteFontList_Release(fontlist2);
4063 hr = IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList1, (void**)&fontlist1);
4064 if (hr == S_OK) {
4065 IDWriteFontFaceReference *ref, *ref1;
4066 IDWriteFont3 *font;
4067 UINT32 count;
4069 count = IDWriteFontList1_GetFontCount(fontlist1);
4070 ok(count > 0, "got %u\n", count);
4072 font = (void*)0xdeadbeef;
4073 hr = IDWriteFontList1_GetFont(fontlist1, ~0u, &font);
4074 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4075 ok(font == NULL, "got %p\n", font);
4077 font = (void*)0xdeadbeef;
4078 hr = IDWriteFontList1_GetFont(fontlist1, count, &font);
4079 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4080 ok(font == NULL, "got %p\n", font);
4082 hr = IDWriteFontList1_GetFont(fontlist1, 0, &font);
4083 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4084 IDWriteFont3_Release(font);
4086 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref);
4087 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4089 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref1);
4090 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4091 ok(ref != ref1, "got %p, %p\n", ref, ref1);
4093 IDWriteFontFaceReference_Release(ref1);
4094 IDWriteFontFaceReference_Release(ref);
4095 IDWriteFontList1_Release(fontlist1);
4097 else
4098 win_skip("IDWriteFontList1 is not supported.\n");
4100 if (SUCCEEDED(IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList2, (void **)&fontlist3)))
4102 IDWriteFontSet1 *fontset, *fontset2;
4104 hr = IDWriteFontList2_GetFontSet(fontlist3, &fontset);
4105 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4107 hr = IDWriteFontList2_GetFontSet(fontlist3, &fontset2);
4108 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4109 ok(fontset != fontset2, "Unexpected instance.\n");
4111 IDWriteFontSet1_Release(fontset2);
4112 IDWriteFontSet1_Release(fontset);
4114 IDWriteFontList2_Release(fontlist3);
4116 else
4117 win_skip("IDWriteFontList2 is not supported.\n");
4119 IDWriteFontList_Release(fontlist);
4120 IDWriteFontFamily_Release(family);
4122 IDWriteFontCollection_Release(collection);
4123 ref = IDWriteFactory_Release(factory);
4124 ok(ref == 0, "factory not released, %lu\n", ref);
4127 static void test_GetInformationalStrings(void)
4129 IDWriteLocalizedStrings *strings, *strings2;
4130 IDWriteFontCollection *collection;
4131 IDWriteFontFace3 *fontface3;
4132 IDWriteFontFace *fontface;
4133 IDWriteFontFamily *family;
4134 IDWriteFactory *factory;
4135 IDWriteFont *font;
4136 BOOL exists;
4137 HRESULT hr;
4138 ULONG ref;
4140 factory = create_factory();
4142 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4143 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4145 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4146 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4148 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4149 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4150 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4152 exists = TRUE;
4153 strings = (void *)0xdeadbeef;
4154 hr = IDWriteFont_GetInformationalStrings(font, 0xdead, &strings, &exists);
4155 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4156 ok(exists == FALSE, "got %d\n", exists);
4157 ok(strings == NULL, "got %p\n", strings);
4159 exists = TRUE;
4160 strings = NULL;
4161 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists);
4162 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4163 ok(exists == FALSE, "got %d\n", exists);
4165 exists = FALSE;
4166 strings = NULL;
4167 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
4168 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4169 ok(exists == TRUE, "got %d\n", exists);
4171 /* strings instance is not reused */
4172 strings2 = NULL;
4173 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings2, &exists);
4174 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4175 ok(strings2 != strings, "got %p, %p\n", strings2, strings);
4177 IDWriteLocalizedStrings_Release(strings);
4178 IDWriteLocalizedStrings_Release(strings2);
4180 hr = IDWriteFont_CreateFontFace(font, &fontface);
4181 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
4183 if (SUCCEEDED(hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
4185 hr = IDWriteFontFace3_GetInformationalStrings(fontface3, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES,
4186 &strings, &exists);
4187 ok(hr == S_OK, "Failed to get info strings, hr %#lx.\n", hr);
4188 IDWriteLocalizedStrings_Release(strings);
4190 IDWriteFontFace3_Release(fontface3);
4192 else
4193 win_skip("IDWriteFontFace3::GetInformationalStrings() is not supported.\n");
4195 IDWriteFontFace_Release(fontface);
4197 IDWriteFont_Release(font);
4198 IDWriteFontFamily_Release(family);
4199 IDWriteFontCollection_Release(collection);
4200 ref = IDWriteFactory_Release(factory);
4201 ok(ref == 0, "factory not released, %lu\n", ref);
4204 static void test_GetGdiInterop(void)
4206 IDWriteGdiInterop *interop, *interop2;
4207 IDWriteFactory *factory, *factory2;
4208 IDWriteFont *font;
4209 LOGFONTW logfont;
4210 HRESULT hr;
4211 ULONG ref;
4213 factory = create_factory();
4215 interop = NULL;
4216 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4217 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4219 interop2 = NULL;
4220 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
4221 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4222 ok(interop == interop2, "got %p, %p\n", interop, interop2);
4223 IDWriteGdiInterop_Release(interop2);
4225 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory2);
4226 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4228 /* each factory gets its own interop */
4229 interop2 = NULL;
4230 hr = IDWriteFactory_GetGdiInterop(factory2, &interop2);
4231 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4232 ok(interop != interop2, "got %p, %p\n", interop, interop2);
4234 /* release factory - interop still works */
4235 IDWriteFactory_Release(factory2);
4237 memset(&logfont, 0, sizeof(logfont));
4238 logfont.lfHeight = 12;
4239 logfont.lfWidth = 12;
4240 logfont.lfWeight = FW_NORMAL;
4241 logfont.lfItalic = 1;
4242 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4244 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop2, &logfont, &font);
4245 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4246 IDWriteFont_Release(font);
4248 IDWriteGdiInterop_Release(interop2);
4249 IDWriteGdiInterop_Release(interop);
4250 ref = IDWriteFactory_Release(factory);
4251 ok(ref == 0, "factory not released, %lu\n", ref);
4254 static void *map_font_file(const WCHAR *filename, DWORD *file_size)
4256 HANDLE file, mapping;
4257 void *ptr;
4259 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4260 if (file == INVALID_HANDLE_VALUE) return NULL;
4262 *file_size = GetFileSize(file, NULL);
4264 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4265 if (!mapping)
4267 CloseHandle(file);
4268 return NULL;
4271 ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4273 CloseHandle(file);
4274 CloseHandle(mapping);
4275 return ptr;
4278 struct font_realization_info
4280 DWORD size;
4281 DWORD flags;
4282 DWORD cache_num;
4283 DWORD instance_id;
4284 DWORD file_count;
4285 WORD face_index;
4286 WORD simulations;
4289 static void test_CreateFontFaceFromHdc(void)
4291 IDWriteFontFileStream *stream, *stream2;
4292 void *font_data, *fragment_context;
4293 struct font_realization_info info;
4294 const void *refkey, *fragment;
4295 IDWriteFontFileLoader *loader;
4296 DWORD data_size, num_fonts;
4297 IDWriteGdiInterop *interop;
4298 IDWriteFontFace *fontface;
4299 IDWriteFactory *factory;
4300 UINT64 size, writetime;
4301 IDWriteFontFile *file;
4302 HFONT hfont, oldhfont;
4303 UINT32 count, dummy;
4304 LOGFONTW logfont;
4305 HANDLE resource;
4306 IUnknown *unk;
4307 LOGFONTA lf;
4308 WCHAR *path;
4309 HRESULT hr;
4310 ULONG ref;
4311 BOOL ret;
4312 HDC hdc;
4314 factory = create_factory();
4316 pGetFontRealizationInfo = (void *)GetProcAddress(GetModuleHandleA("gdi32"), "GetFontRealizationInfo");
4318 interop = NULL;
4319 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4320 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4322 /* Invalid HDC. */
4323 fontface = (void*)0xdeadbeef;
4324 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, NULL, &fontface);
4325 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
4326 ok(fontface == NULL, "got %p\n", fontface);
4328 fontface = (void *)0xdeadbeef;
4329 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, (HDC)0xdeadbeef, &fontface);
4330 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4331 ok(fontface == NULL, "got %p\n", fontface);
4333 memset(&logfont, 0, sizeof(logfont));
4334 logfont.lfHeight = 12;
4335 logfont.lfWidth = 12;
4336 logfont.lfWeight = FW_NORMAL;
4337 logfont.lfItalic = 1;
4338 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4340 hfont = CreateFontIndirectW(&logfont);
4341 hdc = CreateCompatibleDC(0);
4342 oldhfont = SelectObject(hdc, hfont);
4344 fontface = NULL;
4345 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4346 ok(hr == S_OK, "Failed to create font face, hr %#lx.\n", hr);
4348 count = 1;
4349 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
4350 ok(hr == S_OK, "Failed to get font files, hr %#lx.\n", hr);
4352 hr = IDWriteFontFile_GetLoader(file, &loader);
4353 ok(hr == S_OK, "Failed to get file loader, hr %#lx.\n", hr);
4355 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void **)&unk);
4356 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Vista */, "Expected local loader, hr %#lx.\n", hr);
4357 if (unk)
4358 IUnknown_Release(unk);
4360 IDWriteFontFileLoader_Release(loader);
4361 IDWriteFontFile_Release(file);
4363 IDWriteFontFace_Release(fontface);
4364 DeleteObject(SelectObject(hdc, oldhfont));
4366 /* Select bitmap font MS Sans Serif, format that's not supported by DirectWrite. */
4367 memset(&lf, 0, sizeof(lf));
4368 lf.lfHeight = -12;
4369 strcpy(lf.lfFaceName, "MS Sans Serif");
4371 hfont = CreateFontIndirectA(&lf);
4372 oldhfont = SelectObject(hdc, hfont);
4374 fontface = (void *)0xdeadbeef;
4375 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4376 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* Vista */, "Unexpected hr %#lx.\n", hr);
4377 ok(fontface == NULL, "got %p\n", fontface);
4379 DeleteObject(SelectObject(hdc, oldhfont));
4381 /* Memory resource font */
4382 path = create_testfontfile(test_fontfile);
4384 data_size = 0;
4385 font_data = map_font_file(path, &data_size);
4387 num_fonts = 0;
4388 resource = AddFontMemResourceEx(font_data, data_size, NULL, &num_fonts);
4389 ok(resource != NULL, "Failed to add memory resource font, %ld.\n", GetLastError());
4390 ok(num_fonts == 1, "Unexpected number of fonts.\n");
4392 memset(&lf, 0, sizeof(lf));
4393 lf.lfHeight = -12;
4394 strcpy(lf.lfFaceName, "wine_test");
4396 hfont = CreateFontIndirectA(&lf);
4397 ok(hfont != NULL, "Failed to create a font.\n");
4398 oldhfont = SelectObject(hdc, hfont);
4400 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4401 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
4403 count = 1;
4404 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
4405 ok(hr == S_OK, "Failed to get font files, hr %#lx.\n", hr);
4407 hr = IDWriteFontFile_GetLoader(file, &loader);
4408 ok(hr == S_OK, "Failed to get file loader, hr %#lx.\n", hr);
4410 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
4411 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#lx.\n", hr);
4413 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&unk);
4414 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
4416 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void **)&unk);
4417 ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
4419 count = 0;
4420 hr = IDWriteFontFile_GetReferenceKey(file, &refkey, &count);
4421 ok(hr == S_OK, "Failed to get ref key, hr %#lx.\n", hr);
4422 ok(count > 0, "Unexpected key length %u.\n", count);
4424 if (pGetFontRealizationInfo)
4426 info.size = sizeof(info);
4427 ret = pGetFontRealizationInfo(hdc, &info);
4428 ok(ret, "Failed to get realization info.\n");
4429 ok(count == sizeof(info.instance_id), "Unexpected key size.\n");
4430 ok(*(DWORD *)refkey == info.instance_id, "Unexpected stream key.\n");
4432 else
4433 win_skip("GetFontRealizationInfo() is not available.\n");
4435 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refkey, count, &stream);
4436 ok(hr == S_OK, "Failed to create file stream, hr %#lx.\n", hr);
4438 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refkey, count, &stream2);
4439 ok(hr == S_OK, "Failed to create file stream, hr %#lx.\n", hr);
4440 ok(stream2 != stream, "Unexpected stream instance.\n");
4441 IDWriteFontFileStream_Release(stream2);
4443 dummy = 1;
4444 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, &dummy, count, &stream2);
4445 ok(hr == S_OK, "Failed to create file stream, hr %#lx.\n", hr);
4447 writetime = 1;
4448 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
4449 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
4450 ok(writetime == 1, "Unexpected write time.\n");
4452 IDWriteFontFileStream_Release(stream2);
4454 hr = IDWriteFontFileStream_GetFileSize(stream, &size);
4455 ok(hr == S_OK, "Failed to get stream size, hr %#lx.\n", hr);
4456 ok(size == data_size, "Unexpected stream size.\n");
4458 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4459 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
4461 fragment_context = NULL;
4462 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, size, &fragment_context);
4463 ok(hr == S_OK, "Failed to read fragment, hr %#lx.\n", hr);
4464 ok(fragment_context != NULL, "Unexpected context %p.\n", fragment_context);
4465 ok(fragment == fragment_context, "Unexpected data pointer %p, context %p.\n", fragment, fragment_context);
4466 IDWriteFontFileStream_ReleaseFileFragment(stream, fragment_context);
4468 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, size + 1, &fragment_context);
4469 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
4471 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, size - 1, size / 2, &fragment_context);
4472 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
4474 IDWriteFontFileStream_Release(stream);
4476 IDWriteFontFileLoader_Release(loader);
4477 IDWriteFontFile_Release(file);
4479 IDWriteFontFace_Release(fontface);
4481 ret = RemoveFontMemResourceEx(resource);
4482 ok(ret, "Failed to remove memory resource font, %ld.\n", GetLastError());
4484 UnmapViewOfFile(font_data);
4486 DELETE_FONTFILE(path);
4488 DeleteObject(SelectObject(hdc, oldhfont));
4489 DeleteDC(hdc);
4490 IDWriteGdiInterop_Release(interop);
4491 ref = IDWriteFactory_Release(factory);
4492 ok(ref == 0, "factory not released, %lu\n", ref);
4495 static void test_GetSimulations(void)
4497 DWRITE_FONT_SIMULATIONS simulations;
4498 IDWriteGdiInterop *interop;
4499 IDWriteFontFace *fontface;
4500 IDWriteFactory *factory;
4501 IDWriteFont *font;
4502 LOGFONTW logfont;
4503 HRESULT hr;
4504 ULONG ref;
4506 factory = create_factory();
4508 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4509 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4511 memset(&logfont, 0, sizeof(logfont));
4512 logfont.lfHeight = 12;
4513 logfont.lfWidth = 12;
4514 logfont.lfWeight = FW_NORMAL;
4515 logfont.lfItalic = 1;
4516 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4518 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4519 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4521 simulations = IDWriteFont_GetSimulations(font);
4522 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
4523 hr = IDWriteFont_CreateFontFace(font, &fontface);
4524 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4525 simulations = IDWriteFontFace_GetSimulations(fontface);
4526 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
4527 IDWriteFontFace_Release(fontface);
4528 IDWriteFont_Release(font);
4530 memset(&logfont, 0, sizeof(logfont));
4531 logfont.lfHeight = 12;
4532 logfont.lfWidth = 12;
4533 logfont.lfWeight = FW_NORMAL;
4534 logfont.lfItalic = 0;
4535 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4537 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4538 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4540 simulations = IDWriteFont_GetSimulations(font);
4541 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
4542 hr = IDWriteFont_CreateFontFace(font, &fontface);
4543 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4544 simulations = IDWriteFontFace_GetSimulations(fontface);
4545 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
4546 IDWriteFontFace_Release(fontface);
4547 IDWriteFont_Release(font);
4549 IDWriteGdiInterop_Release(interop);
4550 ref = IDWriteFactory_Release(factory);
4551 ok(ref == 0, "factory not released, %lu\n", ref);
4554 static void test_GetFaceNames(void)
4556 IDWriteLocalizedStrings *strings, *strings2, *strings3;
4557 IDWriteFontFace3 *fontface3;
4558 IDWriteGdiInterop *interop;
4559 IDWriteFontFace *fontface;
4560 IDWriteFactory *factory;
4561 UINT32 count, index;
4562 IDWriteFont *font;
4563 LOGFONTW logfont;
4564 WCHAR buffW[255];
4565 BOOL exists;
4566 HRESULT hr;
4567 ULONG ref;
4569 factory = create_factory();
4571 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4572 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4574 memset(&logfont, 0, sizeof(logfont));
4575 logfont.lfHeight = 12;
4576 logfont.lfWidth = 12;
4577 logfont.lfWeight = FW_NORMAL;
4578 logfont.lfItalic = 1;
4579 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4581 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4582 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4584 hr = IDWriteFont_GetFaceNames(font, &strings);
4585 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4587 hr = IDWriteFont_GetFaceNames(font, &strings2);
4588 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4589 ok(strings != strings2, "got %p, %p\n", strings2, strings);
4590 IDWriteLocalizedStrings_Release(strings2);
4592 count = IDWriteLocalizedStrings_GetCount(strings);
4593 ok(count == 1, "got %d\n", count);
4595 index = 1;
4596 exists = FALSE;
4597 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-Us", &index, &exists);
4598 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4599 ok(index == 0 && exists, "got %d, %d\n", index, exists);
4601 count = 0;
4602 hr = IDWriteLocalizedStrings_GetLocaleNameLength(strings, 1, &count);
4603 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4604 ok(count == ~0, "got %d\n", count);
4606 /* for simulated faces names are also simulated */
4607 buffW[0] = 0;
4608 hr = IDWriteLocalizedStrings_GetLocaleName(strings, 0, buffW, ARRAY_SIZE(buffW));
4609 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4610 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
4612 buffW[0] = 0;
4613 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
4614 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4615 ok(!lstrcmpW(buffW, L"Oblique"), "got %s\n", wine_dbgstr_w(buffW));
4616 IDWriteLocalizedStrings_Release(strings);
4618 hr = IDWriteFont_CreateFontFace(font, &fontface);
4619 ok(hr == S_OK, "Failed to create a font face, hr %#lx.\n", hr);
4621 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
4623 hr = IDWriteFontFace3_GetFaceNames(fontface3, &strings2);
4624 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
4626 hr = IDWriteFontFace3_GetFaceNames(fontface3, &strings3);
4627 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
4628 ok(strings2 != strings3, "Unexpected instance.\n");
4629 IDWriteLocalizedStrings_Release(strings3);
4631 buffW[0] = 0;
4632 hr = IDWriteLocalizedStrings_GetString(strings2, 0, buffW, ARRAY_SIZE(buffW));
4633 ok(hr == S_OK, "Failed to get a string, hr %#lx.\n", hr);
4634 ok(!lstrcmpW(buffW, L"Oblique"), "Unexpected name %s.\n", wine_dbgstr_w(buffW));
4635 IDWriteLocalizedStrings_Release(strings2);
4637 IDWriteFontFace3_Release(fontface3);
4639 else
4640 win_skip("GetFaceNames() is not supported.\n");
4642 IDWriteFontFace_Release(fontface);
4644 IDWriteFont_Release(font);
4645 IDWriteGdiInterop_Release(interop);
4646 ref = IDWriteFactory_Release(factory);
4647 ok(ref == 0, "factory not released, %lu\n", ref);
4650 struct local_refkey
4652 FILETIME writetime;
4653 WCHAR name[1];
4656 static void test_TryGetFontTable(void)
4658 IDWriteLocalFontFileLoader *localloader;
4659 WIN32_FILE_ATTRIBUTE_DATA info;
4660 const struct local_refkey *key;
4661 IDWriteFontFileLoader *loader;
4662 const void *table, *table2;
4663 IDWriteFontFace *fontface;
4664 void *context, *context2;
4665 IDWriteFactory *factory;
4666 IDWriteFontFile *file;
4667 WCHAR buffW[MAX_PATH];
4668 BOOL exists, ret;
4669 UINT32 size, len;
4670 WCHAR *path;
4671 HRESULT hr;
4672 ULONG ref;
4674 path = create_testfontfile(test_fontfile);
4676 factory = create_factory();
4678 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4679 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4681 key = NULL;
4682 size = 0;
4683 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4684 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4685 ok(size != 0, "got %u\n", size);
4687 ret = GetFileAttributesExW(path, GetFileExInfoStandard, &info);
4688 ok(ret, "got %d\n", ret);
4689 ok(!memcmp(&info.ftLastWriteTime, &key->writetime, sizeof(key->writetime)), "got wrong write time\n");
4691 hr = IDWriteFontFile_GetLoader(file, &loader);
4692 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4693 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4694 IDWriteFontFileLoader_Release(loader);
4696 hr = IDWriteLocalFontFileLoader_GetFilePathLengthFromKey(localloader, key, size, &len);
4697 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4698 ok(lstrlenW(key->name) == len, "path length %d\n", len);
4700 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, size, buffW, ARRAY_SIZE(buffW));
4701 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4702 ok(!lstrcmpW(buffW, key->name), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(key->name));
4703 IDWriteLocalFontFileLoader_Release(localloader);
4705 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, 0, &fontface);
4706 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4708 exists = FALSE;
4709 context = (void*)0xdeadbeef;
4710 table = NULL;
4711 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table, &size, &context, &exists);
4712 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4713 ok(exists == TRUE, "got %d\n", exists);
4714 ok(context == NULL && table != NULL, "cmap: context %p, table %p\n", context, table);
4716 exists = FALSE;
4717 context2 = (void*)0xdeadbeef;
4718 table2 = NULL;
4719 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table2, &size, &context2, &exists);
4720 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4721 ok(exists == TRUE, "got %d\n", exists);
4722 ok(context2 == context && table2 == table, "cmap: context2 %p, table2 %p\n", context2, table2);
4724 IDWriteFontFace_ReleaseFontTable(fontface, context2);
4725 IDWriteFontFace_ReleaseFontTable(fontface, context);
4727 /* table does not exist */
4728 exists = TRUE;
4729 context = (void*)0xdeadbeef;
4730 table = (void*)0xdeadbeef;
4731 hr = IDWriteFontFace_TryGetFontTable(fontface, 0xabababab, &table, &size, &context, &exists);
4732 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4733 ok(exists == FALSE, "got %d\n", exists);
4734 ok(context == NULL && table == NULL, "got context %p, table pointer %p\n", context, table);
4736 IDWriteFontFace_Release(fontface);
4737 IDWriteFontFile_Release(file);
4738 ref = IDWriteFactory_Release(factory);
4739 ok(ref == 0, "factory not released, %lu\n", ref);
4740 DELETE_FONTFILE(path);
4743 static void test_ConvertFontToLOGFONT(void)
4745 IDWriteFactory *factory, *factory2;
4746 IDWriteFontCollection *collection;
4747 IDWriteGdiInterop *interop;
4748 IDWriteFontFamily *family;
4749 IDWriteFont *font;
4750 LOGFONTW logfont;
4751 UINT32 i, count;
4752 BOOL system;
4753 HRESULT hr;
4754 ULONG ref;
4756 factory = create_factory();
4757 factory2 = create_factory();
4759 interop = NULL;
4760 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4761 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4763 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection, FALSE);
4764 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4766 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4767 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4769 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4770 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4771 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4773 if (0) { /* crashes on native */
4774 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, NULL, NULL);
4775 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, NULL);
4776 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, NULL, &system);
4779 memset(&logfont, 0xcc, sizeof(logfont));
4780 system = TRUE;
4781 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, &system);
4782 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
4783 ok(!system, "got %d\n", system);
4784 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
4786 count = IDWriteFontCollection_GetFontFamilyCount(collection);
4787 for (i = 0; i < count; i++) {
4788 WCHAR nameW[128], familynameW[64], facenameW[64];
4789 IDWriteLocalizedStrings *names;
4790 DWRITE_FONT_SIMULATIONS sim;
4791 IDWriteFontFamily *family;
4792 UINT32 font_count, j;
4793 IDWriteFont *font;
4794 LOGFONTW lf;
4796 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
4797 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4799 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
4800 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4802 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
4803 IDWriteLocalizedStrings_Release(names);
4805 font_count = IDWriteFontFamily_GetFontCount(family);
4807 for (j = 0; j < font_count; ++j)
4809 IDWriteFontFace *fontface;
4810 BOOL has_variations;
4812 hr = IDWriteFontFamily_GetFont(family, j, &font);
4813 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4815 hr = IDWriteFont_GetFaceNames(font, &names);
4816 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4818 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
4819 IDWriteLocalizedStrings_Release(names);
4821 lstrcpyW(nameW, familynameW);
4822 lstrcatW(nameW, L" ");
4823 lstrcatW(nameW, facenameW);
4825 hr = IDWriteFont_CreateFontFace(font, &fontface);
4826 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4828 has_variations = has_face_variations(fontface);
4829 IDWriteFontFace_Release(fontface);
4831 if (has_variations)
4833 static int once;
4834 if (!once++)
4835 skip("ConvertFontToLOGFONT() test does not support variable fonts.\n");
4836 IDWriteFont_Release(font);
4837 continue;
4840 system = FALSE;
4841 memset(&logfont, 0xcc, sizeof(logfont));
4842 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, &logfont, &system);
4843 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4844 ok(system, "got %d\n", system);
4846 sim = IDWriteFont_GetSimulations(font);
4848 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
4850 get_logfont_from_font(font, &lf);
4851 ok(logfont.lfWeight == lf.lfWeight, "Unexpected lfWeight %ld, expected lfWeight %ld, font weight %d, "
4852 "bold simulation %s.\n", logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
4853 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
4854 ok(logfont.lfItalic == lf.lfItalic, "Unexpected italic flag %d, oblique simulation %s.\n",
4855 logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
4856 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "Unexpected facename %s, expected %s.\n",
4857 wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
4859 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "Unexpected output precision %d.\n", logfont.lfOutPrecision);
4860 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "Unexpected clipping precision %d.\n", logfont.lfClipPrecision);
4861 ok(logfont.lfQuality == DEFAULT_QUALITY, "Unexpected quality %d.\n", logfont.lfQuality);
4862 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "Unexpected pitch %d.\n", logfont.lfPitchAndFamily);
4864 winetest_pop_context();
4866 IDWriteFont_Release(font);
4869 IDWriteFontFamily_Release(family);
4872 IDWriteFactory_Release(factory2);
4874 IDWriteFontCollection_Release(collection);
4875 IDWriteFontFamily_Release(family);
4876 IDWriteFont_Release(font);
4877 IDWriteGdiInterop_Release(interop);
4878 ref = IDWriteFactory_Release(factory);
4879 ok(ref == 0, "factory not released, %lu\n", ref);
4882 static void test_CreateStreamFromKey(void)
4884 IDWriteLocalFontFileLoader *localloader;
4885 IDWriteFontFileStream *stream, *stream2;
4886 IDWriteFontFileLoader *loader;
4887 IDWriteFactory *factory;
4888 IDWriteFontFile *file;
4889 UINT64 writetime;
4890 WCHAR *path;
4891 void *key;
4892 UINT32 size;
4893 HRESULT hr;
4894 ULONG ref;
4896 factory = create_factory();
4898 path = create_testfontfile(test_fontfile);
4900 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4901 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4903 key = NULL;
4904 size = 0;
4905 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4906 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4907 ok(size != 0, "got %u\n", size);
4909 hr = IDWriteFontFile_GetLoader(file, &loader);
4910 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4911 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4912 IDWriteFontFileLoader_Release(loader);
4914 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4915 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4916 EXPECT_REF(stream, 1);
4918 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2);
4919 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4920 ok(stream == stream2 || broken(stream != stream2) /* Win7 SP0 */, "got %p, %p\n", stream, stream2);
4921 if (stream == stream2)
4922 EXPECT_REF(stream, 2);
4923 IDWriteFontFileStream_Release(stream);
4924 IDWriteFontFileStream_Release(stream2);
4926 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4927 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4928 EXPECT_REF(stream, 1);
4930 writetime = 0;
4931 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4932 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4933 ok(writetime != 0, "got %s\n", wine_dbgstr_longlong(writetime));
4935 IDWriteFontFileStream_Release(stream);
4936 IDWriteFontFile_Release(file);
4938 IDWriteLocalFontFileLoader_Release(localloader);
4939 ref = IDWriteFactory_Release(factory);
4940 ok(ref == 0, "factory not released, %lu\n", ref);
4941 DELETE_FONTFILE(path);
4944 static void test_ReadFileFragment(void)
4946 IDWriteLocalFontFileLoader *localloader;
4947 IDWriteFontFileStream *stream;
4948 IDWriteFontFileLoader *loader;
4949 IDWriteFactory *factory;
4950 IDWriteFontFile *file;
4951 const void *fragment, *fragment2;
4952 void *key, *context, *context2;
4953 UINT64 filesize;
4954 UINT32 size;
4955 WCHAR *path;
4956 HRESULT hr;
4957 ULONG ref;
4959 factory = create_factory();
4961 path = create_testfontfile(test_fontfile);
4963 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4964 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
4966 key = NULL;
4967 size = 0;
4968 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4969 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4970 ok(size != 0, "got %u\n", size);
4972 hr = IDWriteFontFile_GetLoader(file, &loader);
4973 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4974 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4975 IDWriteFontFileLoader_Release(loader);
4977 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4978 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4980 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
4981 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4983 /* reading past the end of the stream */
4984 fragment = (void*)0xdeadbeef;
4985 context = (void*)0xdeadbeef;
4986 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize+1, &context);
4987 ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
4988 ok(context == NULL, "got %p\n", context);
4989 ok(fragment == NULL, "got %p\n", fragment);
4991 fragment = (void*)0xdeadbeef;
4992 context = (void*)0xdeadbeef;
4993 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
4994 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4995 ok(context == NULL, "got %p\n", context);
4996 ok(fragment != NULL, "got %p\n", fragment);
4998 fragment2 = (void*)0xdeadbeef;
4999 context2 = (void*)0xdeadbeef;
5000 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment2, 0, filesize, &context2);
5001 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5002 ok(context2 == NULL, "got %p\n", context2);
5003 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
5005 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
5006 IDWriteFontFileStream_ReleaseFileFragment(stream, context2);
5008 /* fragment is released, try again */
5009 fragment = (void*)0xdeadbeef;
5010 context = (void*)0xdeadbeef;
5011 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
5012 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5013 ok(context == NULL, "got %p\n", context);
5014 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
5015 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
5017 IDWriteFontFile_Release(file);
5018 IDWriteFontFileStream_Release(stream);
5019 IDWriteLocalFontFileLoader_Release(localloader);
5020 ref = IDWriteFactory_Release(factory);
5021 ok(ref == 0, "factory not released, %lu\n", ref);
5022 DELETE_FONTFILE(path);
5025 static void test_GetDesignGlyphMetrics(void)
5027 DWRITE_GLYPH_METRICS metrics[2];
5028 IDWriteFontFace *fontface;
5029 IDWriteFactory *factory;
5030 IDWriteFontFile *file;
5031 UINT16 indices[2];
5032 UINT32 codepoint;
5033 WCHAR *path;
5034 HRESULT hr;
5035 ULONG ref;
5037 factory = create_factory();
5039 path = create_testfontfile(test_fontfile);
5041 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5042 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5044 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
5045 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5046 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5047 IDWriteFontFile_Release(file);
5049 codepoint = 'A';
5050 indices[0] = 0;
5051 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &indices[0]);
5052 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5053 ok(indices[0] > 0, "got %u\n", indices[0]);
5055 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 0, metrics, FALSE);
5056 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n",hr);
5058 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 1, metrics, FALSE);
5059 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n",hr);
5061 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 0, metrics, FALSE);
5062 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5064 /* missing glyphs are ignored */
5065 indices[1] = 1;
5066 memset(metrics, 0xcc, sizeof(metrics));
5067 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 2, metrics, FALSE);
5068 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5069 ok(metrics[0].advanceWidth == 1000, "got %d\n", metrics[0].advanceWidth);
5070 ok(metrics[1].advanceWidth == 0, "got %d\n", metrics[1].advanceWidth);
5072 IDWriteFontFace_Release(fontface);
5073 ref = IDWriteFactory_Release(factory);
5074 ok(ref == 0, "factory not released, %lu\n", ref);
5075 DELETE_FONTFILE(path);
5078 static BOOL get_expected_is_monospaced(IDWriteFontFace1 *fontface, const DWRITE_PANOSE *panose)
5080 BOOL exists, is_monospaced = FALSE;
5081 const TT_POST *tt_post;
5082 void *post_context;
5083 UINT32 size;
5084 HRESULT hr;
5086 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_POST_TAG, (const void **)&tt_post, &size,
5087 &post_context, &exists);
5088 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5090 if (tt_post)
5092 is_monospaced = !!tt_post->fixed_pitch;
5093 IDWriteFontFace1_ReleaseFontTable(fontface, post_context);
5096 if (!is_monospaced)
5097 is_monospaced |= panose->text.proportion == DWRITE_PANOSE_PROPORTION_MONOSPACED;
5099 return is_monospaced;
5102 static void test_IsMonospacedFont(void)
5104 IDWriteFontCollection *collection;
5105 IDWriteFactory1 *factory;
5106 UINT32 count, i;
5107 HRESULT hr;
5108 ULONG ref;
5110 factory = create_factory_iid(&IID_IDWriteFactory1);
5112 if (!factory)
5114 win_skip("IsMonospacedFont() is not supported.\n");
5115 return;
5118 hr = IDWriteFactory1_GetSystemFontCollection(factory, &collection, FALSE);
5119 ok(hr == S_OK, "Failed to get font collection, hr %#lx.\n", hr);
5121 count = IDWriteFontCollection_GetFontFamilyCount(collection);
5122 for (i = 0; i < count; ++i)
5124 IDWriteLocalizedStrings *names;
5125 IDWriteFontFamily *family;
5126 UINT32 font_count, j;
5127 WCHAR nameW[256];
5129 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
5130 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
5132 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
5133 ok(hr == S_OK, "Failed to get names, hr %#lx.\n", hr);
5134 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
5135 IDWriteLocalizedStrings_Release(names);
5137 font_count = IDWriteFontFamily_GetFontCount(family);
5139 for (j = 0; j < font_count; ++j)
5141 BOOL is_monospaced_font, is_monospaced_face, is_monospaced_expected;
5142 IDWriteFontFace1 *fontface1;
5143 IDWriteFontFace *fontface;
5144 DWRITE_PANOSE panose;
5145 IDWriteFont1 *font1;
5146 IDWriteFont *font;
5148 hr = IDWriteFontFamily_GetFont(family, j, &font);
5149 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
5151 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
5152 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
5153 IDWriteFont_Release(font);
5155 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
5156 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
5158 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
5159 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
5160 IDWriteFontFace_Release(fontface);
5162 is_monospaced_font = IDWriteFont1_IsMonospacedFont(font1);
5163 is_monospaced_face = IDWriteFontFace1_IsMonospacedFont(fontface1);
5164 ok(is_monospaced_font == is_monospaced_face, "Unexpected monospaced flag.\n");
5166 IDWriteFont1_GetPanose(font1, &panose);
5168 is_monospaced_expected = get_expected_is_monospaced(fontface1, &panose);
5169 ok(is_monospaced_expected == is_monospaced_face, "Unexpected is_monospaced flag %d for %s, font %d.\n",
5170 is_monospaced_face, wine_dbgstr_w(nameW), j);
5172 IDWriteFontFace1_Release(fontface1);
5173 IDWriteFont1_Release(font1);
5176 IDWriteFontFamily_Release(family);
5179 IDWriteFontCollection_Release(collection);
5180 ref = IDWriteFactory1_Release(factory);
5181 ok(ref == 0, "factory not released, %lu\n", ref);
5184 static void test_GetDesignGlyphAdvances(void)
5186 IDWriteFontFace1 *fontface1;
5187 IDWriteFontFace *fontface;
5188 IDWriteFactory *factory;
5189 IDWriteFontFile *file;
5190 WCHAR *path;
5191 HRESULT hr;
5192 ULONG ref;
5194 factory = create_factory();
5196 path = create_testfontfile(test_fontfile);
5198 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5199 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5201 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
5202 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5203 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5204 IDWriteFontFile_Release(file);
5206 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5207 if (hr == S_OK) {
5208 UINT32 codepoint;
5209 UINT16 index;
5210 INT32 advance;
5212 codepoint = 'A';
5213 index = 0;
5214 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &index);
5215 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5216 ok(index > 0, "got %u\n", index);
5218 advance = 0;
5219 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, FALSE);
5220 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5221 ok(advance == 1000, "got %i\n", advance);
5223 advance = 0;
5224 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, TRUE);
5225 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5226 todo_wine
5227 ok(advance == 2048, "got %i\n", advance);
5229 IDWriteFontFace1_Release(fontface1);
5231 else
5232 win_skip("GetDesignGlyphAdvances() is not supported.\n");
5234 IDWriteFontFace_Release(fontface);
5235 ref = IDWriteFactory_Release(factory);
5236 ok(ref == 0, "factory not released, %lu\n", ref);
5237 DELETE_FONTFILE(path);
5240 static void test_GetGlyphRunOutline(void)
5242 DWRITE_GLYPH_OFFSET offsets[2];
5243 IDWriteFactory *factory;
5244 IDWriteFontFile *file;
5245 IDWriteFontFace *face;
5246 UINT32 codepoint;
5247 FLOAT advances[2];
5248 UINT16 glyphs[2];
5249 WCHAR *path;
5250 HRESULT hr;
5251 ULONG ref;
5253 path = create_testfontfile(test_fontfile);
5254 factory = create_factory();
5256 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5257 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
5259 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
5260 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5261 IDWriteFontFile_Release(file);
5263 codepoint = 'A';
5264 glyphs[0] = 0;
5265 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5266 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5267 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5268 glyphs[1] = glyphs[0];
5270 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, glyphs, advances, offsets, 1, FALSE, FALSE, NULL);
5271 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5273 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, NULL, NULL, offsets, 1, FALSE, FALSE, &test_geomsink);
5274 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5276 advances[0] = 1.0;
5277 advances[1] = 0.0;
5279 offsets[0].advanceOffset = 1.0;
5280 offsets[0].ascenderOffset = 1.0;
5281 offsets[1].advanceOffset = 0.0;
5282 offsets[1].ascenderOffset = 0.0;
5284 /* default advances, no offsets */
5285 memset(g_startpoints, 0, sizeof(g_startpoints));
5286 g_startpoint_count = 0;
5287 SET_EXPECT(setfillmode);
5288 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, FALSE, &test_geomsink);
5289 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5290 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5291 if (g_startpoint_count == 2) {
5292 /* glyph advance of 500 is applied */
5293 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);
5294 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);
5296 CHECK_CALLED(setfillmode);
5298 /* default advances, no offsets, RTL */
5299 memset(g_startpoints, 0, sizeof(g_startpoints));
5300 g_startpoint_count = 0;
5301 SET_EXPECT(setfillmode);
5302 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, TRUE, &test_geomsink);
5303 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5304 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5305 if (g_startpoint_count == 2) {
5306 /* advance is -500 now */
5307 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);
5308 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);
5310 CHECK_CALLED(setfillmode);
5312 /* default advances, additional offsets */
5313 memset(g_startpoints, 0, sizeof(g_startpoints));
5314 g_startpoint_count = 0;
5315 SET_EXPECT(setfillmode);
5316 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, FALSE, &test_geomsink);
5317 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5318 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5319 if (g_startpoint_count == 2) {
5320 /* offsets applied to first contour */
5321 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);
5322 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);
5324 CHECK_CALLED(setfillmode);
5326 /* default advances, additional offsets, RTL */
5327 memset(g_startpoints, 0, sizeof(g_startpoints));
5328 g_startpoint_count = 0;
5329 SET_EXPECT(setfillmode);
5330 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, TRUE, &test_geomsink);
5331 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5332 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5333 if (g_startpoint_count == 2) {
5334 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);
5335 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);
5337 CHECK_CALLED(setfillmode);
5339 /* custom advances and offsets, offset turns total advance value to zero */
5340 memset(g_startpoints, 0, sizeof(g_startpoints));
5341 g_startpoint_count = 0;
5342 SET_EXPECT(setfillmode);
5343 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, advances, offsets, 2, FALSE, FALSE, &test_geomsink);
5344 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5345 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5346 if (g_startpoint_count == 2) {
5347 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);
5348 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);
5350 CHECK_CALLED(setfillmode);
5352 /* 0 glyph count */
5353 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 0, FALSE, FALSE, &test_geomsink2);
5354 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5356 /* Glyph with open figure, single contour point. */
5357 codepoint = 'B';
5358 glyphs[0] = 0;
5359 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5360 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5361 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5363 SET_EXPECT(setfillmode);
5364 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
5365 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5366 CHECK_CALLED(setfillmode);
5368 IDWriteFactory_Release(factory);
5369 IDWriteFontFace_Release(face);
5370 DELETE_FONTFILE(path);
5372 /* space glyph */
5373 factory = create_factory();
5374 face = create_fontface(factory);
5376 codepoint = ' ';
5377 glyphs[0] = 0;
5378 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5379 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5380 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5382 SET_EXPECT(setfillmode);
5383 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
5384 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5385 CHECK_CALLED(setfillmode);
5387 IDWriteFontFace_Release(face);
5388 ref = IDWriteFactory_Release(factory);
5389 ok(ref == 0, "factory not released, %lu\n", ref);
5392 static void test_GetEudcFontCollection(void)
5394 IDWriteFontCollection *coll, *coll2;
5395 IDWriteFactory1 *factory;
5396 HRESULT hr;
5397 ULONG ref;
5399 factory = create_factory_iid(&IID_IDWriteFactory1);
5400 if (!factory) {
5401 win_skip("GetEudcFontCollection() is not supported.\n");
5402 return;
5405 EXPECT_REF(factory, 1);
5406 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll, FALSE);
5407 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5408 EXPECT_REF(factory, 2);
5409 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll2, FALSE);
5410 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5411 EXPECT_REF(factory, 2);
5412 ok(coll == coll2, "got %p, %p\n", coll, coll2);
5413 IDWriteFontCollection_Release(coll);
5414 IDWriteFontCollection_Release(coll2);
5416 ref = IDWriteFactory1_Release(factory);
5417 ok(ref == 0, "factory not released, %lu\n", ref);
5420 static void test_GetCaretMetrics(void)
5422 DWRITE_FONT_METRICS1 metrics;
5423 IDWriteFontFace1 *fontface1;
5424 DWRITE_CARET_METRICS caret;
5425 IDWriteFontFace *fontface;
5426 IDWriteFactory *factory;
5427 IDWriteFontFile *file;
5428 IDWriteFont *font;
5429 WCHAR *path;
5430 HRESULT hr;
5431 ULONG ref;
5433 path = create_testfontfile(test_fontfile);
5434 factory = create_factory();
5436 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5437 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5439 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5440 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5441 IDWriteFontFile_Release(file);
5443 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5444 IDWriteFontFace_Release(fontface);
5445 if (hr != S_OK) {
5446 win_skip("GetCaretMetrics() is not supported.\n");
5447 ref = IDWriteFactory_Release(factory);
5448 ok(ref == 0, "factory not released, %lu\n", ref);
5449 DELETE_FONTFILE(path);
5450 return;
5453 memset(&caret, 0xcc, sizeof(caret));
5454 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5455 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
5456 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
5457 ok(caret.offset == 0, "got %d\n", caret.offset);
5458 IDWriteFontFace1_Release(fontface1);
5459 IDWriteFactory_Release(factory);
5461 /* now with Tahoma Normal */
5462 factory = create_factory();
5463 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5464 hr = IDWriteFont_CreateFontFace(font, &fontface);
5465 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5466 IDWriteFont_Release(font);
5467 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5468 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5469 IDWriteFontFace_Release(fontface);
5471 memset(&caret, 0xcc, sizeof(caret));
5472 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5473 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
5474 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
5475 ok(caret.offset == 0, "got %d\n", caret.offset);
5476 IDWriteFontFace1_Release(fontface1);
5478 /* simulated italic */
5479 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
5480 hr = IDWriteFont_CreateFontFace(font, &fontface);
5481 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5482 IDWriteFont_Release(font);
5483 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5484 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5485 IDWriteFontFace_Release(fontface);
5487 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
5489 memset(&caret, 0xcc, sizeof(caret));
5490 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5491 ok(caret.slopeRise == metrics.designUnitsPerEm, "got %d\n", caret.slopeRise);
5492 ok(caret.slopeRun > 0, "got %d\n", caret.slopeRun);
5493 ok(caret.offset == 0, "got %d\n", caret.offset);
5494 IDWriteFontFace1_Release(fontface1);
5496 ref = IDWriteFactory_Release(factory);
5497 ok(ref == 0, "factory not released, %lu\n", ref);
5498 DELETE_FONTFILE(path);
5501 static void test_GetGlyphCount(void)
5503 IDWriteFontFace *fontface;
5504 IDWriteFactory *factory;
5505 IDWriteFontFile *file;
5506 UINT16 count;
5507 WCHAR *path;
5508 HRESULT hr;
5509 ULONG ref;
5511 path = create_testfontfile(test_fontfile);
5512 factory = create_factory();
5514 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5515 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5517 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5518 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5519 IDWriteFontFile_Release(file);
5521 count = IDWriteFontFace_GetGlyphCount(fontface);
5522 ok(count == 8, "got %u\n", count);
5524 IDWriteFontFace_Release(fontface);
5525 ref = IDWriteFactory_Release(factory);
5526 ok(ref == 0, "factory not released, %lu\n", ref);
5527 DELETE_FONTFILE(path);
5530 static void test_GetKerningPairAdjustments(void)
5532 IDWriteFontFace1 *fontface1;
5533 IDWriteFontFace *fontface;
5534 IDWriteFactory *factory;
5535 IDWriteFontFile *file;
5536 WCHAR *path;
5537 HRESULT hr;
5538 ULONG ref;
5540 path = create_testfontfile(test_fontfile);
5541 factory = create_factory();
5543 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5544 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5546 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5547 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5548 IDWriteFontFile_Release(file);
5550 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5551 if (hr == S_OK) {
5552 INT32 adjustments[1];
5554 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 0, NULL, NULL);
5555 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "Unexpected hr %#lx.\n", hr);
5557 if (0) /* crashes on native */
5558 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, NULL);
5560 adjustments[0] = 1;
5561 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, adjustments);
5562 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5563 ok(adjustments[0] == 0, "got %d\n", adjustments[0]);
5565 IDWriteFontFace1_Release(fontface1);
5567 else
5568 win_skip("GetKerningPairAdjustments() is not supported.\n");
5570 IDWriteFontFace_Release(fontface);
5571 ref = IDWriteFactory_Release(factory);
5572 ok(ref == 0, "factory not released, %lu\n", ref);
5573 DELETE_FONTFILE(path);
5576 static void test_CreateRenderingParams(void)
5578 IDWriteRenderingParams2 *params2;
5579 IDWriteRenderingParams1 *params1;
5580 IDWriteRenderingParams *params;
5581 DWRITE_RENDERING_MODE mode;
5582 IDWriteFactory3 *factory3;
5583 IDWriteFactory *factory;
5584 HRESULT hr;
5585 ULONG ref;
5587 factory = create_factory();
5589 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
5590 DWRITE_RENDERING_MODE_DEFAULT, &params);
5591 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5593 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams1, (void**)&params1);
5594 if (hr == S_OK) {
5595 FLOAT enhcontrast;
5597 /* test what enhanced contrast setting set by default to */
5598 enhcontrast = IDWriteRenderingParams1_GetGrayscaleEnhancedContrast(params1);
5599 ok(enhcontrast == 1.0, "got %.2f\n", enhcontrast);
5600 IDWriteRenderingParams1_Release(params1);
5602 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
5603 if (hr == S_OK) {
5604 DWRITE_GRID_FIT_MODE gridfit;
5606 /* default gridfit mode */
5607 gridfit = IDWriteRenderingParams2_GetGridFitMode(params2);
5608 ok(gridfit == DWRITE_GRID_FIT_MODE_DEFAULT, "got %d\n", gridfit);
5610 IDWriteRenderingParams2_Release(params2);
5612 else
5613 win_skip("IDWriteRenderingParams2 not supported.\n");
5615 else
5616 win_skip("IDWriteRenderingParams1 not supported.\n");
5618 IDWriteRenderingParams_Release(params);
5620 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
5621 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5623 mode = IDWriteRenderingParams_GetRenderingMode(params);
5624 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
5625 IDWriteRenderingParams_Release(params);
5627 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
5628 if (hr == S_OK) {
5629 IDWriteRenderingParams3 *params3;
5631 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
5632 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_DEFAULT, &params3);
5633 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5635 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
5636 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5638 mode = IDWriteRenderingParams_GetRenderingMode(params);
5639 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
5641 IDWriteRenderingParams_Release(params);
5642 IDWriteRenderingParams3_Release(params3);
5643 IDWriteFactory3_Release(factory3);
5645 else
5646 win_skip("IDWriteRenderingParams3 not supported.\n");
5648 ref = IDWriteFactory_Release(factory);
5649 ok(ref == 0, "factory not released, %lu\n", ref);
5652 static void test_CreateGlyphRunAnalysis(void)
5654 static const DWRITE_RENDERING_MODE rendermodes[] = {
5655 DWRITE_RENDERING_MODE_ALIASED,
5656 DWRITE_RENDERING_MODE_GDI_CLASSIC,
5657 DWRITE_RENDERING_MODE_GDI_NATURAL,
5658 DWRITE_RENDERING_MODE_NATURAL,
5659 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
5662 IDWriteGlyphRunAnalysis *analysis, *analysis2;
5663 IDWriteRenderingParams *params;
5664 IDWriteFactory3 *factory3;
5665 IDWriteFactory2 *factory2;
5666 IDWriteFactory *factory;
5667 DWRITE_GLYPH_RUN run;
5668 IDWriteFontFace *face;
5669 UINT16 glyph, glyphs[10];
5670 FLOAT advances[2];
5671 HRESULT hr;
5672 UINT32 ch;
5673 RECT rect, rect2;
5674 DWRITE_GLYPH_OFFSET offsets[2];
5675 DWRITE_GLYPH_METRICS metrics;
5676 DWRITE_FONT_METRICS fm;
5677 DWRITE_MATRIX m;
5678 ULONG size;
5679 BYTE *bits;
5680 ULONG ref;
5681 int i;
5683 factory = create_factory();
5684 face = create_fontface(factory);
5686 ch = 'A';
5687 glyph = 0;
5688 hr = IDWriteFontFace_GetGlyphIndices(face, &ch, 1, &glyph);
5689 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5690 ok(glyph > 0, "got %u\n", glyph);
5692 hr = IDWriteFontFace_GetDesignGlyphMetrics(face, &glyph, 1, &metrics, FALSE);
5693 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5694 advances[0] = metrics.advanceWidth;
5696 offsets[0].advanceOffset = 0.0;
5697 offsets[0].ascenderOffset = 0.0;
5699 run.fontFace = face;
5700 run.fontEmSize = 24.0;
5701 run.glyphCount = 1;
5702 run.glyphIndices = &glyph;
5703 run.glyphAdvances = advances;
5704 run.glyphOffsets = offsets;
5705 run.isSideways = FALSE;
5706 run.bidiLevel = 0;
5708 /* zero ppdip */
5709 analysis = (void*)0xdeadbeef;
5710 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 0.0, NULL,
5711 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5712 0.0, 0.0, &analysis);
5713 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5714 ok(analysis == NULL, "got %p\n", analysis);
5716 /* negative ppdip */
5717 analysis = (void*)0xdeadbeef;
5718 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, -1.0, NULL,
5719 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5720 0.0, 0.0, &analysis);
5721 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5722 ok(analysis == NULL, "got %p\n", analysis);
5724 /* default mode is not allowed */
5725 analysis = (void*)0xdeadbeef;
5726 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5727 DWRITE_RENDERING_MODE_DEFAULT, DWRITE_MEASURING_MODE_NATURAL,
5728 0.0, 0.0, &analysis);
5729 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5730 ok(analysis == NULL, "got %p\n", analysis);
5732 /* outline too */
5733 analysis = (void*)0xdeadbeef;
5734 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5735 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_MEASURING_MODE_NATURAL,
5736 0.0, 0.0, &analysis);
5737 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5738 ok(analysis == NULL, "got %p\n", analysis);
5740 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5741 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5742 0.0, 0.0, &analysis);
5743 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5745 /* invalid texture type */
5746 memset(&rect, 0xcc, sizeof(rect));
5747 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &rect);
5748 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5749 ok(rect.left == 0 && rect.right == 0 &&
5750 rect.top == 0 && rect.bottom == 0, "unexpected rect\n");
5752 /* check how origin affects bounds */
5753 SetRectEmpty(&rect);
5754 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5755 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5756 ok(!IsRectEmpty(&rect), "got empty rect\n");
5757 IDWriteGlyphRunAnalysis_Release(analysis);
5759 /* doubled ppdip */
5760 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5761 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5762 0.0, 0.0, &analysis);
5763 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5764 SetRectEmpty(&rect2);
5765 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5766 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5767 ok(rect.right - rect.left < rect2.right - rect2.left, "expected wider rect\n");
5768 ok(rect.bottom - rect.top < rect2.bottom - rect2.top, "expected taller rect\n");
5769 IDWriteGlyphRunAnalysis_Release(analysis);
5771 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5772 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5773 10.0, -5.0, &analysis);
5774 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5776 SetRectEmpty(&rect2);
5777 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5778 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5779 ok(!IsRectEmpty(&rect2), "got empty rect\n");
5780 IDWriteGlyphRunAnalysis_Release(analysis);
5782 ok(!EqualRect(&rect, &rect2), "got equal bounds\n");
5783 OffsetRect(&rect, 10, -5);
5784 ok(EqualRect(&rect, &rect2), "got different bounds\n");
5786 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
5787 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5788 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
5789 0.0, 0.0, &analysis);
5790 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5792 if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
5793 SetRectEmpty(&rect);
5794 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5795 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5796 ok(!IsRectEmpty(&rect), "got empty rect\n");
5798 SetRect(&rect, 0, 0, 1, 1);
5799 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5800 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5801 ok(IsRectEmpty(&rect), "unexpected empty rect\n");
5803 else {
5804 SetRect(&rect, 0, 0, 1, 1);
5805 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5806 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5807 ok(IsRectEmpty(&rect), "got empty rect\n");
5809 SetRectEmpty(&rect);
5810 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5811 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5812 ok(!IsRectEmpty(&rect), "got empty rect\n");
5815 IDWriteGlyphRunAnalysis_Release(analysis);
5818 IDWriteFontFace_GetMetrics(run.fontFace, &fm);
5820 /* check bbox for a single glyph run */
5821 for (run.fontEmSize = 1.0; run.fontEmSize <= 100.0; run.fontEmSize += 1.0) {
5822 DWRITE_GLYPH_METRICS gm;
5823 LONG bboxX, bboxY;
5825 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5826 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5827 0.0, 0.0, &analysis);
5828 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5830 SetRectEmpty(&rect);
5831 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5832 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5834 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
5835 DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
5836 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5838 /* metrics are in design units */
5839 bboxX = (int)floorf((gm.advanceWidth - gm.leftSideBearing - gm.rightSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
5840 bboxY = (int)floorf((gm.advanceHeight - gm.topSideBearing - gm.bottomSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
5842 rect.right -= rect.left;
5843 rect.bottom -= rect.top;
5844 ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %ld, from metrics %ld\n", run.fontEmSize, rect.right, bboxX);
5845 ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %ld, from metrics %ld\n", run.fontEmSize, rect.bottom, bboxY);
5847 IDWriteGlyphRunAnalysis_Release(analysis);
5850 /* without offsets */
5851 run.fontFace = face;
5852 run.fontEmSize = 24.0;
5853 run.glyphCount = 1;
5854 run.glyphIndices = &glyph;
5855 run.glyphAdvances = advances;
5856 run.glyphOffsets = NULL;
5857 run.isSideways = FALSE;
5858 run.bidiLevel = 0;
5860 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5861 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5862 0.0, 0.0, &analysis);
5863 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5865 SetRectEmpty(&rect);
5866 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5867 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5868 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5870 IDWriteGlyphRunAnalysis_Release(analysis);
5872 /* without explicit advances */
5873 run.fontFace = face;
5874 run.fontEmSize = 24.0;
5875 run.glyphCount = 1;
5876 run.glyphIndices = &glyph;
5877 run.glyphAdvances = NULL;
5878 run.glyphOffsets = NULL;
5879 run.isSideways = FALSE;
5880 run.bidiLevel = 0;
5882 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5883 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5884 0.0, 0.0, &analysis);
5885 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5887 SetRectEmpty(&rect);
5888 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5889 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5890 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5892 IDWriteGlyphRunAnalysis_Release(analysis);
5894 /* test that advances are scaled according to ppdip too */
5895 glyphs[0] = glyphs[1] = glyph;
5896 advances[0] = advances[1] = 100.0f;
5897 run.fontFace = face;
5898 run.fontEmSize = 24.0;
5899 run.glyphCount = 2;
5900 run.glyphIndices = glyphs;
5901 run.glyphAdvances = advances;
5902 run.glyphOffsets = NULL;
5903 run.isSideways = FALSE;
5904 run.bidiLevel = 0;
5906 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5907 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5908 0.0, 0.0, &analysis);
5909 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5911 SetRectEmpty(&rect2);
5912 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5913 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5914 ok(!IsRectEmpty(&rect2), "got empty bounds\n");
5915 ok(!EqualRect(&rect, &rect2), "got wrong rect2\n");
5916 ok((rect2.right - rect.left) > advances[0], "got rect width %ld for advance %f\n", rect.right - rect.left, advances[0]);
5917 IDWriteGlyphRunAnalysis_Release(analysis);
5919 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5920 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5921 0.0, 0.0, &analysis);
5922 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5924 SetRectEmpty(&rect);
5925 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5926 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5927 ok((rect.right - rect.left) > 2 * advances[0], "got rect width %ld for advance %f\n", rect.right - rect.left, advances[0]);
5928 IDWriteGlyphRunAnalysis_Release(analysis);
5930 /* with scaling transform */
5931 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5932 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5933 0.0, 0.0, &analysis);
5934 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5936 SetRectEmpty(&rect);
5937 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5938 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5939 ok(!IsRectEmpty(&rect), "got rect width %ld\n", rect.right - rect.left);
5940 IDWriteGlyphRunAnalysis_Release(analysis);
5942 memset(&m, 0, sizeof(m));
5943 m.m11 = 2.0;
5944 m.m22 = 1.0;
5945 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5946 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5947 0.0, 0.0, &analysis);
5948 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5950 SetRectEmpty(&rect2);
5951 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5952 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5953 ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %ld\n", rect2.right - rect2.left);
5955 /* instances are not reused for same runs */
5956 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5957 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5958 0.0, 0.0, &analysis2);
5959 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
5960 ok(analysis2 != analysis, "got %p, previous instance %p\n", analysis2, analysis);
5961 IDWriteGlyphRunAnalysis_Release(analysis2);
5963 IDWriteGlyphRunAnalysis_Release(analysis);
5965 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void **)&factory2) == S_OK) {
5966 FLOAT gamma, contrast, cleartype_level;
5968 /* Invalid antialias mode. */
5969 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5970 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
5971 0.0f, 0.0f, &analysis);
5972 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5974 /* Invalid grid fit mode. */
5975 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5976 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5977 0.0f, 0.0f, &analysis);
5978 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5980 /* Invalid rendering mode. */
5981 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_OUTLINE,
5982 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5983 0.0f, 0.0f, &analysis);
5984 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
5986 /* Invalid measuring mode. */
5987 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5988 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, 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 /* Win8 does not accept default grid fitting mode. */
5993 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
5994 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5995 0.0f, 0.0f, &analysis);
5996 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Win8 */, "Failed to create analysis, hr %#lx.\n", hr);
5997 if (hr == S_OK)
5998 IDWriteGlyphRunAnalysis_Release(analysis);
6000 /* Natural mode, grayscale antialiased. */
6001 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
6002 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6003 0.0f, 0.0f, &analysis);
6004 ok(hr == S_OK, "Failed to create analysis, hr %#lx.\n", hr);
6006 SetRect(&rect, 0, 1, 0, 1);
6007 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
6008 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6009 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
6011 SetRectEmpty(&rect);
6012 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
6013 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6014 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
6016 size = (rect.right - rect.left) * (rect.bottom - rect.top);
6017 bits = malloc(size);
6019 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
6020 ok(hr == S_OK, "Failed to get alpha texture, hr %#lx.\n", hr);
6022 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
6023 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
6025 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
6026 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6028 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
6029 todo_wine
6030 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6032 free(bits);
6034 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.1f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
6035 DWRITE_RENDERING_MODE_NATURAL, &params);
6036 ok(hr == S_OK, "Failed to create custom parameters, hr %#lx.\n", hr);
6038 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &cleartype_level);
6039 ok(hr == S_OK, "Failed to get alpha blend params, hr %#lx.\n", hr);
6040 todo_wine
6041 ok(cleartype_level == 0.0f, "Unexpected cleartype level %f.\n", cleartype_level);
6043 IDWriteRenderingParams_Release(params);
6044 IDWriteGlyphRunAnalysis_Release(analysis);
6046 IDWriteFactory2_Release(factory2);
6049 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3) == S_OK) {
6051 /* Invalid antialias mode. */
6052 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6053 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
6054 0.0f, 0.0f, &analysis);
6055 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6057 /* Invalid grid fit mode. */
6058 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6059 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6060 0.0f, 0.0f, &analysis);
6061 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6063 /* Invalid rendering mode. */
6064 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_OUTLINE,
6065 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6066 0.0f, 0.0f, &analysis);
6067 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6069 /* Invalid measuring mode. */
6070 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6071 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED,
6072 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, 0.0f, 0.0f, &analysis);
6073 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6075 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
6076 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6077 0.0f, 0.0f, &analysis);
6078 ok(hr == S_OK, "Failed to create analysis, hr %#lx.\n", hr);
6079 IDWriteGlyphRunAnalysis_Release(analysis);
6081 /* Natural mode, grayscale antialiased. */
6082 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
6083 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6084 0.0f, 0.0f, &analysis);
6085 ok(hr == S_OK, "Failed to create analysis, hr %#lx.\n", hr);
6087 SetRect(&rect, 0, 1, 0, 1);
6088 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
6089 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6090 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
6092 SetRectEmpty(&rect);
6093 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
6094 ok(hr == S_OK, "Failed to get texture bounds, hr %#lx.\n", hr);
6095 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
6097 size = (rect.right - rect.left) * (rect.bottom - rect.top);
6098 bits = malloc(size);
6100 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
6101 ok(hr == S_OK, "Failed to get alpha texture, hr %#lx.\n", hr);
6103 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
6104 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
6106 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
6107 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6109 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
6110 todo_wine
6111 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr);
6113 free(bits);
6115 IDWriteGlyphRunAnalysis_Release(analysis);
6117 IDWriteFactory3_Release(factory3);
6120 IDWriteFontFace_Release(face);
6121 ref = IDWriteFactory_Release(factory);
6122 ok(ref == 0, "factory not released, %lu\n", ref);
6125 #define round(x) ((int)floor((x) + 0.5))
6127 struct VDMX_Header
6129 WORD version;
6130 WORD numRecs;
6131 WORD numRatios;
6134 struct VDMX_Ratio
6136 BYTE bCharSet;
6137 BYTE xRatio;
6138 BYTE yStartRatio;
6139 BYTE yEndRatio;
6142 struct VDMX_group
6144 WORD recs;
6145 BYTE startsz;
6146 BYTE endsz;
6149 struct VDMX_vTable
6151 WORD yPelHeight;
6152 SHORT yMax;
6153 SHORT yMin;
6156 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
6158 WORD num_ratios, i, group_offset = 0;
6159 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
6160 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
6162 num_ratios = GET_BE_WORD(hdr->numRatios);
6164 for (i = 0; i < num_ratios; i++)
6166 if (!ratios[i].bCharSet) continue;
6168 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
6169 ratios[i].yEndRatio == 0) ||
6170 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
6171 ratios[i].yEndRatio >= dev_y_ratio))
6173 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
6174 break;
6177 if (group_offset)
6178 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
6179 return NULL;
6182 static BOOL get_vdmx_size(const struct VDMX_group *group, int emsize, int *a, int *d)
6184 WORD recs, i;
6185 const struct VDMX_vTable *tables;
6187 if (!group) return FALSE;
6189 recs = GET_BE_WORD(group->recs);
6190 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
6192 tables = (const struct VDMX_vTable *)(group + 1);
6193 for (i = 0; i < recs; i++)
6195 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
6196 if (ppem > emsize)
6198 /* FIXME: Supposed to interpolate */
6199 trace("FIXME interpolate %d\n", emsize);
6200 return FALSE;
6203 if (ppem == emsize)
6205 *a = (SHORT)GET_BE_WORD(tables[i].yMax);
6206 *d = -(SHORT)GET_BE_WORD(tables[i].yMin);
6207 return TRUE;
6210 return FALSE;
6213 static void test_metrics_cmp(FLOAT emsize, const DWRITE_FONT_METRICS *metrics, const DWRITE_FONT_METRICS1 *expected)
6215 winetest_push_context("Size %.2f", emsize);
6217 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "got %u expect %u.\n",
6218 metrics->designUnitsPerEm, expected->designUnitsPerEm);
6219 ok(metrics->ascent == expected->ascent, "a: got %u expect %u.\n", metrics->ascent, expected->ascent);
6220 ok(metrics->descent == expected->descent, "d: got %u expect %u.\n", metrics->descent, expected->descent);
6221 ok(metrics->lineGap == expected->lineGap, "lg: got %d expect %d.\n", metrics->lineGap, expected->lineGap);
6222 ok(metrics->capHeight == expected->capHeight, "capH: got %u expect %u.\n", metrics->capHeight, expected->capHeight);
6223 ok(metrics->xHeight == expected->xHeight, "xH: got %u expect %u.\n", metrics->xHeight, expected->xHeight);
6224 ok(metrics->underlinePosition == expected->underlinePosition, "ulP: got %d expect %d.\n",
6225 metrics->underlinePosition, expected->underlinePosition);
6226 ok(metrics->underlineThickness == expected->underlineThickness, "ulTh: got %u expect %u.\n",
6227 metrics->underlineThickness, expected->underlineThickness);
6228 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "stP: got %d expect %d.\n",
6229 metrics->strikethroughPosition, expected->strikethroughPosition);
6230 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "stTh: got %u expect %u.\n",
6231 metrics->strikethroughThickness, expected->strikethroughThickness);
6233 winetest_pop_context();
6236 static void test_metrics1_cmp(FLOAT emsize, const DWRITE_FONT_METRICS1 *metrics, const DWRITE_FONT_METRICS1 *expected)
6238 winetest_push_context("Size %.2f", emsize);
6240 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "got %u expect %u.\n",
6241 metrics->designUnitsPerEm, expected->designUnitsPerEm);
6242 ok(metrics->ascent == expected->ascent, "a: got %u expect %u.\n", metrics->ascent, expected->ascent);
6243 ok(metrics->descent == expected->descent, "d: got %u expect %u.\n", metrics->descent, expected->descent);
6244 ok(metrics->lineGap == expected->lineGap, "lg: got %d expect %d.\n", metrics->lineGap, expected->lineGap);
6245 ok(metrics->capHeight == expected->capHeight, "capH: got %u expect %u.\n", metrics->capHeight, expected->capHeight);
6246 ok(metrics->xHeight == expected->xHeight, "xH: got %u expect %u.\n", metrics->xHeight, expected->xHeight);
6247 ok(metrics->underlinePosition == expected->underlinePosition, "ulP: got %d expect %d.\n",
6248 metrics->underlinePosition, expected->underlinePosition);
6249 ok(metrics->underlineThickness == expected->underlineThickness, "ulTh: got %u expect %u.\n",
6250 metrics->underlineThickness, expected->underlineThickness);
6251 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "stP: got %d expect %d.\n",
6252 metrics->strikethroughPosition, expected->strikethroughPosition);
6253 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "stTh: got %u expect %u.\n",
6254 metrics->strikethroughThickness, expected->strikethroughThickness);
6255 ok(metrics->glyphBoxLeft == expected->glyphBoxLeft, "box left: got %d expect %d.\n",
6256 metrics->glyphBoxLeft, expected->glyphBoxLeft);
6257 if (0) { /* this is not consistent */
6258 ok(metrics->glyphBoxTop == expected->glyphBoxTop, "box top: got %d expect %d.\n",
6259 metrics->glyphBoxTop, expected->glyphBoxTop);
6260 ok(metrics->glyphBoxRight == expected->glyphBoxRight, "box right: got %d expect %d.\n",
6261 metrics->glyphBoxRight, expected->glyphBoxRight);
6263 ok(metrics->glyphBoxBottom == expected->glyphBoxBottom, "box bottom: got %d expect %d.\n",
6264 metrics->glyphBoxBottom, expected->glyphBoxBottom);
6265 ok(metrics->subscriptPositionX == expected->subscriptPositionX, "subX: got %d expect %d.\n",
6266 metrics->subscriptPositionX, expected->subscriptPositionX);
6267 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "subY: got %d expect %d.\n",
6268 metrics->subscriptPositionY, expected->subscriptPositionY);
6269 ok(metrics->subscriptSizeX == expected->subscriptSizeX, "subsizeX: got %d expect %d.\n",
6270 metrics->subscriptSizeX, expected->subscriptSizeX);
6271 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "subsizeY: got %d expect %d.\n",
6272 metrics->subscriptSizeY, expected->subscriptSizeY);
6273 ok(metrics->superscriptPositionX == expected->superscriptPositionX, "supX: got %d expect %d.\n",
6274 metrics->superscriptPositionX, expected->superscriptPositionX);
6275 if (0)
6276 ok(metrics->superscriptPositionY == expected->superscriptPositionY, "supY: got %d expect %d.\n",
6277 metrics->superscriptPositionY, expected->superscriptPositionY);
6278 ok(metrics->superscriptSizeX == expected->superscriptSizeX, "supsizeX: got %d expect %d.\n",
6279 metrics->superscriptSizeX, expected->superscriptSizeX);
6280 ok(metrics->superscriptSizeY == expected->superscriptSizeY, "supsizeY: got %d expect %d.\n",
6281 metrics->superscriptSizeY, expected->superscriptSizeY);
6282 ok(metrics->hasTypographicMetrics == expected->hasTypographicMetrics, "hastypo: got %d expect %d.\n",
6283 metrics->hasTypographicMetrics, expected->hasTypographicMetrics);
6285 winetest_pop_context();
6288 struct compatmetrics_test {
6289 DWRITE_MATRIX m;
6290 FLOAT ppdip;
6291 FLOAT emsize;
6294 static struct compatmetrics_test compatmetrics_tests[] = {
6295 { { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0, 5.0 },
6296 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 1.0, 5.0 },
6297 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 2.0, 5.0 },
6298 { { 0.0, 0.0, 0.0, 3.0, 0.0, 0.0 }, 2.0, 5.0 },
6299 { { 0.0, 0.0, 0.0, -3.0, 0.0, 0.0 }, 2.0, 5.0 },
6300 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 2.0, 5.0 },
6301 { { 1.0, 0.0, 0.0, 1.0, 5.0, 0.0 }, 2.0, 5.0 },
6302 { { 1.0, 0.0, 0.0, 1.0, 0.0, 5.0 }, 2.0, 5.0 },
6305 static void get_expected_metrics(IDWriteFontFace *fontface, struct compatmetrics_test *ptr,
6306 DWRITE_FONT_METRICS *expected)
6308 HRESULT hr;
6310 memset(expected, 0, sizeof(*expected));
6311 hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, ptr->ppdip * fabsf(ptr->m.m22) * ptr->emsize, 1.0, NULL, expected);
6312 ok(hr == S_OK, "got %08lx\n", hr);
6315 static void test_gdicompat_metrics(IDWriteFontFace *face)
6317 IDWriteFontFace1 *fontface1 = NULL;
6318 HRESULT hr;
6319 DWRITE_FONT_METRICS design_metrics, comp_metrics;
6320 DWRITE_FONT_METRICS1 design_metrics1, expected;
6321 FLOAT emsize, scale;
6322 int ascent, descent;
6323 const struct VDMX_Header *vdmx;
6324 UINT32 vdmx_len;
6325 void *vdmx_ctx;
6326 BOOL exists;
6327 const struct VDMX_group *vdmx_group = NULL;
6328 int i;
6330 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace1, (void**)&fontface1);
6331 if (hr != S_OK)
6332 win_skip("gdi compatible DWRITE_FONT_METRICS1 are not supported.\n");
6334 if (fontface1) {
6335 IDWriteFontFace1_GetMetrics(fontface1, &design_metrics1);
6336 memcpy(&design_metrics, &design_metrics1, sizeof(design_metrics));
6338 else
6339 IDWriteFontFace_GetMetrics(face, &design_metrics);
6341 hr = IDWriteFontFace_TryGetFontTable(face, MS_VDMX_TAG, (const void **)&vdmx,
6342 &vdmx_len, &vdmx_ctx, &exists);
6343 if (hr != S_OK || !exists)
6344 vdmx = NULL;
6345 else
6346 vdmx_group = find_vdmx_group(vdmx);
6348 /* negative emsize */
6349 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6350 memset(&expected, 0, sizeof(expected));
6351 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, -10.0, 1.0, NULL, &comp_metrics);
6352 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6353 test_metrics_cmp(0.0, &comp_metrics, &expected);
6355 /* zero emsize */
6356 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6357 memset(&expected, 0, sizeof(expected));
6358 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 0.0, 1.0, NULL, &comp_metrics);
6359 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6360 test_metrics_cmp(0.0, &comp_metrics, &expected);
6362 /* zero pixels per dip */
6363 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6364 memset(&expected, 0, sizeof(expected));
6365 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, 0.0, NULL, &comp_metrics);
6366 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6367 test_metrics_cmp(5.0, &comp_metrics, &expected);
6369 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6370 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, -1.0, NULL, &comp_metrics);
6371 ok(hr == E_INVALIDARG, "got %08lx\n", hr);
6372 test_metrics_cmp(5.0, &comp_metrics, &expected);
6374 for (i = 0; i < ARRAY_SIZE(compatmetrics_tests); i++) {
6375 struct compatmetrics_test *ptr = &compatmetrics_tests[i];
6377 get_expected_metrics(face, ptr, (DWRITE_FONT_METRICS*)&expected);
6378 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, ptr->emsize, ptr->ppdip, &ptr->m, &comp_metrics);
6379 ok(hr == S_OK, "got %08lx\n", hr);
6380 test_metrics_cmp(ptr->emsize, &comp_metrics, &expected);
6383 for (emsize = 5; emsize <= design_metrics.designUnitsPerEm; emsize++)
6385 DWRITE_FONT_METRICS1 comp_metrics1, expected;
6387 if (fontface1) {
6388 hr = IDWriteFontFace1_GetGdiCompatibleMetrics(fontface1, emsize, 1.0, NULL, &comp_metrics1);
6389 ok(hr == S_OK, "got %08lx\n", hr);
6391 else {
6392 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, emsize, 1.0, NULL, &comp_metrics);
6393 ok(hr == S_OK, "got %08lx\n", hr);
6396 scale = emsize / design_metrics.designUnitsPerEm;
6397 if (!get_vdmx_size(vdmx_group, emsize, &ascent, &descent))
6399 ascent = round(design_metrics.ascent * scale);
6400 descent = round(design_metrics.descent * scale);
6403 expected.designUnitsPerEm = design_metrics.designUnitsPerEm;
6404 expected.ascent = round(ascent / scale );
6405 expected.descent = round(descent / scale );
6406 expected.lineGap = round(round(design_metrics.lineGap * scale) / scale);
6407 expected.capHeight = round(round(design_metrics.capHeight * scale) / scale);
6408 expected.xHeight = round(round(design_metrics.xHeight * scale) / scale);
6409 expected.underlinePosition = round(round(design_metrics.underlinePosition * scale) / scale);
6410 expected.underlineThickness = round(round(design_metrics.underlineThickness * scale) / scale);
6411 expected.strikethroughPosition = round(round(design_metrics.strikethroughPosition * scale) / scale);
6412 expected.strikethroughThickness = round(round(design_metrics.strikethroughThickness * scale) / scale);
6414 if (fontface1) {
6415 expected.glyphBoxLeft = round(round(design_metrics1.glyphBoxLeft * scale) / scale);
6417 if (0) { /* those two fail on Tahoma and Win7 */
6418 expected.glyphBoxTop = round(round(design_metrics1.glyphBoxTop * scale) / scale);
6419 expected.glyphBoxRight = round(round(design_metrics1.glyphBoxRight * scale) / scale);
6421 expected.glyphBoxBottom = round(round(design_metrics1.glyphBoxBottom * scale) / scale);
6422 expected.subscriptPositionX = round(round(design_metrics1.subscriptPositionX * scale) / scale);
6423 expected.subscriptPositionY = round(round(design_metrics1.subscriptPositionY * scale) / scale);
6424 expected.subscriptSizeX = round(round(design_metrics1.subscriptSizeX * scale) / scale);
6425 expected.subscriptSizeY = round(round(design_metrics1.subscriptSizeY * scale) / scale);
6426 expected.superscriptPositionX = round(round(design_metrics1.superscriptPositionX * scale) / scale);
6427 if (0) /* this fails for 3 emsizes, Tahoma from [5, 2048] range */ {
6428 expected.superscriptPositionY = round(round(design_metrics1.superscriptPositionY * scale) / scale);
6430 expected.superscriptSizeX = round(round(design_metrics1.superscriptSizeX * scale) / scale);
6431 expected.superscriptSizeY = round(round(design_metrics1.superscriptSizeY * scale) / scale);
6432 expected.hasTypographicMetrics = design_metrics1.hasTypographicMetrics;
6434 test_metrics1_cmp(emsize, &comp_metrics1, &expected);
6436 else
6437 test_metrics_cmp(emsize, &comp_metrics, &expected);
6441 if (fontface1)
6442 IDWriteFontFace1_Release(fontface1);
6443 if (vdmx) IDWriteFontFace_ReleaseFontTable(face, vdmx_ctx);
6446 static void test_GetGdiCompatibleMetrics(void)
6448 IDWriteFactory *factory;
6449 IDWriteFont *font;
6450 IDWriteFontFace *fontface;
6451 HRESULT hr;
6452 ULONG ref;
6454 factory = create_factory();
6456 font = get_font(factory, L"Tahoma", DWRITE_FONT_STYLE_NORMAL);
6457 hr = IDWriteFont_CreateFontFace(font, &fontface);
6458 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6459 IDWriteFont_Release(font);
6460 test_gdicompat_metrics(fontface);
6461 IDWriteFontFace_Release(fontface);
6463 font = get_font(factory, L"Arial", DWRITE_FONT_STYLE_NORMAL);
6464 if (!font)
6465 skip("Skipping tests with Arial\n");
6466 else
6468 hr = IDWriteFont_CreateFontFace(font, &fontface);
6469 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6470 IDWriteFont_Release(font);
6472 test_gdicompat_metrics(fontface);
6473 IDWriteFontFace_Release(fontface);
6476 ref = IDWriteFactory_Release(factory);
6477 ok(ref == 0, "factory not released, %lu\n", ref);
6480 static void get_expected_panose(IDWriteFont1 *font, DWRITE_PANOSE *panose)
6482 IDWriteFontFace *fontface;
6483 const TT_OS2_V2 *tt_os2;
6484 void *os2_context;
6485 UINT32 size;
6486 BOOL exists;
6487 HRESULT hr;
6489 memset(panose, 0, sizeof(*panose));
6491 hr = IDWriteFont1_CreateFontFace(font, &fontface);
6492 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6494 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
6495 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6497 if (tt_os2) {
6498 memcpy(panose, &tt_os2->panose, sizeof(*panose));
6499 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
6502 IDWriteFontFace_Release(fontface);
6505 static void test_GetPanose(void)
6507 IDWriteFontCollection *syscollection;
6508 IDWriteFactory *factory;
6509 IDWriteFont1 *font1;
6510 IDWriteFont *font;
6511 UINT count, i;
6512 HRESULT hr;
6513 ULONG ref;
6515 factory = create_factory();
6516 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6518 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
6519 IDWriteFont_Release(font);
6521 if (FAILED(hr)) {
6522 ref = IDWriteFactory_Release(factory);
6523 ok(ref == 0, "factory not released, %lu\n", ref);
6524 win_skip("GetPanose() is not supported.\n");
6525 return;
6527 IDWriteFont1_Release(font1);
6529 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
6530 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6531 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
6533 for (i = 0; i < count; i++) {
6534 DWRITE_PANOSE panose, expected_panose;
6535 IDWriteLocalizedStrings *names;
6536 IDWriteFontFace3 *fontface3;
6537 IDWriteFontFace *fontface;
6538 IDWriteFontFamily *family;
6539 IDWriteFont1 *font1;
6540 IDWriteFont *font;
6541 WCHAR nameW[256];
6543 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
6544 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6546 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
6547 DWRITE_FONT_STYLE_NORMAL, &font);
6548 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6550 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
6551 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6552 IDWriteFont_Release(font);
6554 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
6555 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6557 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
6559 IDWriteLocalizedStrings_Release(names);
6561 IDWriteFont1_GetPanose(font1, &panose);
6562 get_expected_panose(font1, &expected_panose);
6564 winetest_push_context("Font %s", wine_dbgstr_w(nameW));
6566 ok(panose.values[0] == expected_panose.values[0], "values[0] %#x, expected %#x.\n",
6567 panose.values[0], expected_panose.values[0]);
6568 ok(panose.values[1] == expected_panose.values[1], "values[1] %#x, expected %#x.\n",
6569 panose.values[1], expected_panose.values[1]);
6570 ok(panose.values[2] == expected_panose.values[2], "values[2] %#x, expected %#x.\n",
6571 panose.values[2], expected_panose.values[2]);
6572 ok(panose.values[3] == expected_panose.values[3], "values[3] %#x, expected %#x.\n",
6573 panose.values[3], expected_panose.values[3]);
6574 ok(panose.values[4] == expected_panose.values[4], "values[4] %#x, expected %#x.\n",
6575 panose.values[4], expected_panose.values[4]);
6576 ok(panose.values[5] == expected_panose.values[5], "values[5] %#x, expected %#x.\n",
6577 panose.values[5], expected_panose.values[5]);
6578 ok(panose.values[6] == expected_panose.values[6], "values[6] %#x, expected %#x.\n",
6579 panose.values[6], expected_panose.values[6]);
6580 ok(panose.values[7] == expected_panose.values[7], "values[7] %#x, expected %#x.\n",
6581 panose.values[7], expected_panose.values[7]);
6582 ok(panose.values[8] == expected_panose.values[8], "values[8] %#x, expected %#x.\n",
6583 panose.values[8], expected_panose.values[8]);
6584 ok(panose.values[9] == expected_panose.values[9], "values[9] %#x, expected %#x.\n",
6585 panose.values[9], expected_panose.values[9]);
6587 winetest_pop_context();
6589 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
6590 ok(hr == S_OK, "Failed to create a font face, %#lx.\n", hr);
6591 if (IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3) == S_OK) {
6592 ok(!memcmp(&panose, &expected_panose, sizeof(panose)), "%s: Unexpected panose from font face.\n",
6593 wine_dbgstr_w(nameW));
6594 IDWriteFontFace3_Release(fontface3);
6596 IDWriteFontFace_Release(fontface);
6598 IDWriteFont1_Release(font1);
6599 IDWriteFontFamily_Release(family);
6602 IDWriteFontCollection_Release(syscollection);
6603 ref = IDWriteFactory_Release(factory);
6604 ok(ref == 0, "factory not released, %lu\n", ref);
6607 static INT32 get_gdi_font_advance(HDC hdc, FLOAT emsize)
6609 LOGFONTW logfont;
6610 HFONT hfont;
6611 BOOL ret;
6612 ABC abc;
6614 memset(&logfont, 0, sizeof(logfont));
6615 logfont.lfHeight = (LONG)-emsize;
6616 logfont.lfWeight = FW_NORMAL;
6617 logfont.lfQuality = CLEARTYPE_QUALITY;
6618 lstrcpyW(logfont.lfFaceName, L"Tahoma");
6620 hfont = CreateFontIndirectW(&logfont);
6621 SelectObject(hdc, hfont);
6623 ret = GetCharABCWidthsW(hdc, 'A', 'A', &abc);
6624 ok(ret, "got %d\n", ret);
6626 DeleteObject(hfont);
6628 return abc.abcA + abc.abcB + abc.abcC;
6631 static void test_GetGdiCompatibleGlyphAdvances(void)
6633 IDWriteFontFace1 *fontface1;
6634 IDWriteFontFace *fontface;
6635 IDWriteFactory *factory;
6636 IDWriteFont *font;
6637 HRESULT hr;
6638 HDC hdc;
6639 UINT32 codepoint;
6640 UINT16 glyph;
6641 FLOAT emsize;
6642 DWRITE_FONT_METRICS1 fm;
6643 INT32 advance;
6644 ULONG ref;
6646 factory = create_factory();
6647 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6649 hr = IDWriteFont_CreateFontFace(font, &fontface);
6650 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6651 IDWriteFont_Release(font);
6653 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
6654 IDWriteFontFace_Release(fontface);
6656 if (hr != S_OK) {
6657 ref = IDWriteFactory_Release(factory);
6658 ok(ref == 0, "factory not released, %lu\n", ref);
6659 win_skip("GetGdiCompatibleGlyphAdvances() is not supported\n");
6660 return;
6663 codepoint = 'A';
6664 glyph = 0;
6665 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &glyph);
6666 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6667 ok(glyph > 0, "got %u\n", glyph);
6669 /* zero emsize */
6670 advance = 1;
6671 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 0.0,
6672 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6673 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6674 ok(advance == 0, "got %d\n", advance);
6676 /* negative emsize */
6677 advance = 1;
6678 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, -1.0,
6679 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6680 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6681 ok(advance == 0, "got %d\n", advance);
6683 /* zero ppdip */
6684 advance = 1;
6685 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
6686 0.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6687 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6688 ok(advance == 0, "got %d\n", advance);
6690 /* negative ppdip */
6691 advance = 1;
6692 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
6693 -1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6694 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6695 ok(advance == 0, "got %d\n", advance);
6697 IDWriteFontFace1_GetMetrics(fontface1, &fm);
6699 hdc = CreateCompatibleDC(0);
6701 for (emsize = 1.0; emsize <= fm.designUnitsPerEm; emsize += 1.0) {
6702 INT32 gdi_advance;
6704 gdi_advance = get_gdi_font_advance(hdc, emsize);
6705 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emsize,
6706 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6707 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6709 /* advance is in design units */
6710 advance = (int)floorf(emsize * advance / fm.designUnitsPerEm + 0.5f);
6711 ok((advance - gdi_advance) <= 2, "%.0f: got advance %d, expected %d\n", emsize, advance, gdi_advance);
6714 DeleteObject(hdc);
6716 IDWriteFontFace1_Release(fontface1);
6717 ref = IDWriteFactory_Release(factory);
6718 ok(ref == 0, "factory not released, %lu\n", ref);
6721 static WORD get_gasp_flags(IDWriteFontFace *fontface, FLOAT emsize, FLOAT ppdip)
6723 WORD num_recs, version;
6724 const WORD *ptr;
6725 WORD flags = 0;
6726 UINT32 size;
6727 BOOL exists;
6728 void *ctxt;
6729 HRESULT hr;
6731 emsize *= ppdip;
6733 exists = FALSE;
6734 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GASP_TAG,
6735 (const void**)&ptr, &size, &ctxt, &exists);
6736 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6738 if (!exists)
6739 goto done;
6741 version = GET_BE_WORD( *ptr++ );
6742 num_recs = GET_BE_WORD( *ptr++ );
6743 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
6744 ok(0, "unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
6745 goto done;
6748 while (num_recs--)
6750 flags = GET_BE_WORD( *(ptr + 1) );
6751 if (emsize <= GET_BE_WORD( *ptr )) break;
6752 ptr += 2;
6755 done:
6756 IDWriteFontFace_ReleaseFontTable(fontface, ctxt);
6757 return flags;
6760 #define GASP_GRIDFIT 0x0001
6761 #define GASP_DOGRAY 0x0002
6762 #define GASP_SYMMETRIC_GRIDFIT 0x0004
6763 #define GASP_SYMMETRIC_SMOOTHING 0x0008
6765 static BOOL g_is_vista;
6766 static DWRITE_RENDERING_MODE get_expected_rendering_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
6767 DWRITE_OUTLINE_THRESHOLD threshold)
6769 static const FLOAT aa_threshold = 100.0f;
6770 static const FLOAT a_threshold = 350.0f;
6771 static const FLOAT naturalemsize = 20.0f;
6772 FLOAT v;
6774 /* outline threshold */
6775 if (g_is_vista)
6776 v = mode == DWRITE_MEASURING_MODE_NATURAL ? aa_threshold : a_threshold;
6777 else
6778 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
6780 if (emsize >= v)
6781 return DWRITE_RENDERING_MODE_OUTLINE;
6783 switch (mode)
6785 case DWRITE_MEASURING_MODE_NATURAL:
6786 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (emsize <= naturalemsize))
6787 return DWRITE_RENDERING_MODE_NATURAL;
6788 else
6789 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
6790 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6791 return DWRITE_RENDERING_MODE_GDI_CLASSIC;
6792 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6793 return DWRITE_RENDERING_MODE_GDI_NATURAL;
6794 default:
6798 /* should be unreachable */
6799 return DWRITE_RENDERING_MODE_DEFAULT;
6802 static DWRITE_GRID_FIT_MODE get_expected_gridfit_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
6803 DWRITE_OUTLINE_THRESHOLD threshold)
6805 static const FLOAT aa_threshold = 100.0f;
6806 static const FLOAT a_threshold = 350.0f;
6807 FLOAT v;
6809 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
6810 if (emsize >= v)
6811 return DWRITE_GRID_FIT_MODE_DISABLED;
6813 if (mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
6814 return DWRITE_GRID_FIT_MODE_ENABLED;
6816 return (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
6819 struct recommendedmode_test
6821 DWRITE_MEASURING_MODE measuring;
6822 DWRITE_OUTLINE_THRESHOLD threshold;
6825 static const struct recommendedmode_test recmode_tests[] = {
6826 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6827 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6828 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6831 static const struct recommendedmode_test recmode_tests1[] = {
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 },
6835 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6836 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6837 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6840 static void test_GetRecommendedRenderingMode(void)
6842 IDWriteRenderingParams *params;
6843 IDWriteFontFace3 *fontface3;
6844 IDWriteFontFace2 *fontface2;
6845 IDWriteFontFace1 *fontface1;
6846 IDWriteFontFace *fontface;
6847 DWRITE_RENDERING_MODE mode;
6848 IDWriteFactory *factory;
6849 FLOAT emsize;
6850 HRESULT hr;
6851 ULONG ref;
6853 factory = create_factory();
6854 fontface = create_fontface(factory);
6856 fontface1 = NULL;
6857 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
6858 if (hr != S_OK)
6859 win_skip("IDWriteFontFace1::GetRecommendedRenderingMode() is not supported.\n");
6861 fontface2 = NULL;
6862 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6863 if (hr != S_OK)
6864 win_skip("IDWriteFontFace2::GetRecommendedRenderingMode() is not supported.\n");
6866 fontface3 = NULL;
6867 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
6868 if (hr != S_OK)
6869 win_skip("IDWriteFontFace3::GetRecommendedRenderingMode() is not supported.\n");
6871 if (0) /* crashes on native */
6872 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6873 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, NULL);
6875 mode = 10;
6876 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6877 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode);
6878 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
6879 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
6881 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
6882 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6884 /* detect old dwrite version, that is using higher threshold value */
6885 g_is_vista = fontface1 == NULL;
6887 for (emsize = 1.0; emsize < 500.0; emsize += 1.0)
6889 DWRITE_RENDERING_MODE expected;
6890 unsigned int i;
6891 FLOAT ppdip;
6892 WORD gasp;
6894 winetest_push_context("Size %.2f", emsize);
6896 for (i = 0; i < ARRAY_SIZE(recmode_tests); ++i)
6898 winetest_push_context("%u", i);
6900 ppdip = 1.0f;
6901 mode = 10;
6902 gasp = get_gasp_flags(fontface, emsize, ppdip);
6903 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6904 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6905 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6906 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6908 /* some ppdip variants */
6909 ppdip = 0.5f;
6910 mode = 10;
6911 gasp = get_gasp_flags(fontface, emsize, ppdip);
6912 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6913 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6914 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6915 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6917 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6918 Win8 and Win10 handle this as expected. */
6919 if (emsize > 20.0f)
6921 ppdip = 1.5f;
6922 mode = 10;
6923 gasp = get_gasp_flags(fontface, emsize, ppdip);
6924 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6925 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6926 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6927 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6929 ppdip = 2.0f;
6930 mode = 10;
6931 gasp = get_gasp_flags(fontface, emsize, ppdip);
6932 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6933 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6934 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6935 ok(mode == expected, "got %d, ppdip %f, flags 0x%04x, expected %d.\n", mode, ppdip, gasp, expected);
6938 winetest_pop_context();
6941 /* IDWriteFontFace1 offers another variant of this method */
6942 if (fontface1)
6944 for (i = 0; i < ARRAY_SIZE(recmode_tests1); ++i)
6946 FLOAT dpi;
6948 winetest_push_context("%u", i);
6950 ppdip = 1.0f;
6951 dpi = 96.0f * ppdip;
6952 mode = 10;
6953 gasp = get_gasp_flags(fontface, emsize, ppdip);
6954 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6955 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6956 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6957 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6958 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
6960 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6961 Win8 and Win10 handle this as expected. */
6962 if (emsize > 20.0f)
6964 ppdip = 2.0f;
6965 dpi = 96.0f * ppdip;
6966 mode = 10;
6967 gasp = get_gasp_flags(fontface, emsize, ppdip);
6968 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6969 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6970 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6971 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6972 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
6974 ppdip = 0.5f;
6975 dpi = 96.0f * ppdip;
6976 mode = 10;
6977 gasp = get_gasp_flags(fontface, emsize, ppdip);
6978 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6979 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6980 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6981 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6982 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
6984 /* try different dpis for X and Y direction */
6985 ppdip = 1.0f;
6986 dpi = 96.0f * ppdip;
6987 mode = 10;
6988 gasp = get_gasp_flags(fontface, emsize, ppdip);
6989 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6990 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6991 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6992 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
6993 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
6995 ppdip = 1.0f;
6996 dpi = 96.0f * ppdip;
6997 mode = 10;
6998 gasp = get_gasp_flags(fontface, emsize, ppdip);
6999 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7000 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
7001 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
7002 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7003 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
7005 ppdip = 2.0f;
7006 dpi = 96.0f * ppdip;
7007 mode = 10;
7008 gasp = get_gasp_flags(fontface, emsize, ppdip);
7009 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7010 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
7011 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
7012 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7013 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
7015 ppdip = 2.0f;
7016 dpi = 96.0f * ppdip;
7017 mode = 10;
7018 gasp = get_gasp_flags(fontface, emsize, ppdip);
7019 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7020 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
7021 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
7022 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7023 ok(mode == expected, "got %d, dpi %f, flags 0x%04x, expected %d.\n", mode, dpi, gasp, expected);
7026 winetest_pop_context();
7030 /* IDWriteFontFace2 - another one */
7031 if (fontface2) {
7032 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
7034 gasp = get_gasp_flags(fontface, emsize, 1.0f);
7035 for (i = 0; i < ARRAY_SIZE(recmode_tests1); ++i)
7037 winetest_push_context("%u", i);
7039 mode = 10;
7040 expected = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7041 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7042 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, emsize, 96.0f, 96.0f,
7043 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode, &gridfit);
7044 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7045 ok(mode == expected, "got %d, flags 0x%04x, expected %d.\n", mode, gasp, expected);
7046 ok(gridfit == expected_gridfit, "gridfit: got %d, flags 0x%04x, expected %d.\n", gridfit, gasp, expected_gridfit);
7048 winetest_pop_context();
7052 /* IDWriteFontFace3 - and another one */
7053 if (fontface3) {
7054 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
7055 DWRITE_RENDERING_MODE1 mode1, expected1;
7057 gasp = get_gasp_flags(fontface, emsize, 1.0f);
7058 for (i = 0; i < ARRAY_SIZE(recmode_tests1); ++i)
7060 winetest_push_context("%u", i);
7062 mode1 = 10;
7063 expected1 = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7064 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7065 hr = IDWriteFontFace3_GetRecommendedRenderingMode(fontface3, emsize, 96.0f, 96.0f,
7066 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode1, &gridfit);
7067 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7068 ok(mode1 == expected1, "got %d, flags 0x%04x, expected %d.\n", mode1, gasp, expected1);
7069 ok(gridfit == expected_gridfit, "gridfit: got %d, flags 0x%04x, expected %d.\n", gridfit, gasp, expected_gridfit);
7071 winetest_pop_context();
7075 winetest_pop_context();
7078 IDWriteRenderingParams_Release(params);
7080 /* test how parameters override returned modes */
7081 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
7082 DWRITE_RENDERING_MODE_GDI_CLASSIC, &params);
7083 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7085 mode = 10;
7086 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode);
7087 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7088 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7090 IDWriteRenderingParams_Release(params);
7092 if (fontface2) {
7093 IDWriteRenderingParams2 *params2;
7094 IDWriteFactory2 *factory2;
7095 DWRITE_GRID_FIT_MODE gridfit;
7097 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
7098 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7100 hr = IDWriteFactory2_CreateCustomRenderingParams(factory2, 1.0, 0.0, 0.0, 0.5, DWRITE_PIXEL_GEOMETRY_FLAT,
7101 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_GRID_FIT_MODE_ENABLED, &params2);
7102 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7104 mode = 10;
7105 gridfit = 10;
7106 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
7107 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7108 NULL, &mode, &gridfit);
7109 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7110 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7111 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7113 mode = 10;
7114 gridfit = 10;
7115 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
7116 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7117 (IDWriteRenderingParams*)params2, &mode, &gridfit);
7118 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7119 ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode);
7120 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7122 IDWriteRenderingParams2_Release(params2);
7123 IDWriteFactory2_Release(factory2);
7126 if (fontface3) {
7127 IDWriteRenderingParams3 *params3;
7128 IDWriteRenderingParams2 *params2;
7129 IDWriteRenderingParams *params;
7130 IDWriteFactory3 *factory3;
7131 DWRITE_GRID_FIT_MODE gridfit;
7132 DWRITE_RENDERING_MODE1 mode1;
7134 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
7135 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7137 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 0.5f, DWRITE_PIXEL_GEOMETRY_FLAT,
7138 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_ENABLED, &params3);
7139 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7141 mode1 = IDWriteRenderingParams3_GetRenderingMode1(params3);
7142 ok(mode1 == DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, "got %d\n", mode1);
7144 mode = IDWriteRenderingParams3_GetRenderingMode(params3);
7145 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7147 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
7148 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7149 ok(params == (IDWriteRenderingParams*)params3, "got %p, %p\n", params3, params);
7150 mode = IDWriteRenderingParams_GetRenderingMode(params);
7151 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7152 IDWriteRenderingParams_Release(params);
7154 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams2, (void**)&params2);
7155 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7156 ok(params2 == (IDWriteRenderingParams2*)params3, "got %p, %p\n", params3, params2);
7157 mode = IDWriteRenderingParams2_GetRenderingMode(params2);
7158 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7159 IDWriteRenderingParams2_Release(params2);
7161 mode = 10;
7162 gridfit = 10;
7163 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
7164 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7165 NULL, &mode, &gridfit);
7166 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7167 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7168 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7170 mode = 10;
7171 gridfit = 10;
7172 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
7173 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7174 (IDWriteRenderingParams*)params3, &mode, &gridfit);
7175 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7176 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7177 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7179 IDWriteRenderingParams3_Release(params3);
7180 IDWriteFactory3_Release(factory3);
7183 if (fontface3)
7184 IDWriteFontFace3_Release(fontface3);
7185 if (fontface2)
7186 IDWriteFontFace2_Release(fontface2);
7187 if (fontface1)
7188 IDWriteFontFace1_Release(fontface1);
7189 IDWriteFontFace_Release(fontface);
7190 ref = IDWriteFactory_Release(factory);
7191 ok(ref == 0, "factory not released, %lu\n", ref);
7194 static inline BOOL float_eq(FLOAT left, FLOAT right)
7196 int x = *(int *)&left;
7197 int y = *(int *)&right;
7199 if (x < 0)
7200 x = INT_MIN - x;
7201 if (y < 0)
7202 y = INT_MIN - y;
7204 return abs(x - y) <= 8;
7207 static void test_GetAlphaBlendParams(void)
7209 static const DWRITE_RENDERING_MODE rendermodes[] = {
7210 DWRITE_RENDERING_MODE_ALIASED,
7211 DWRITE_RENDERING_MODE_GDI_CLASSIC,
7212 DWRITE_RENDERING_MODE_GDI_NATURAL,
7213 DWRITE_RENDERING_MODE_NATURAL,
7214 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
7217 IDWriteGlyphRunAnalysis *analysis;
7218 FLOAT gamma, contrast, ctlevel;
7219 IDWriteRenderingParams *params;
7220 DWRITE_GLYPH_METRICS metrics;
7221 DWRITE_GLYPH_OFFSET offset;
7222 IDWriteFontFace *fontface;
7223 IDWriteFactory *factory;
7224 DWRITE_GLYPH_RUN run;
7225 FLOAT advance, expected_gdi_gamma;
7226 UINT value = 0;
7227 UINT16 glyph;
7228 UINT32 ch, i;
7229 HRESULT hr;
7230 ULONG ref;
7231 BOOL ret;
7233 factory = create_factory();
7234 fontface = create_fontface(factory);
7236 ch = 'A';
7237 glyph = 0;
7238 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
7239 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7240 ok(glyph > 0, "got %u\n", glyph);
7242 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
7243 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7244 advance = metrics.advanceWidth;
7246 offset.advanceOffset = 0.0;
7247 offset.ascenderOffset = 0.0;
7249 run.fontFace = fontface;
7250 run.fontEmSize = 24.0;
7251 run.glyphCount = 1;
7252 run.glyphIndices = &glyph;
7253 run.glyphAdvances = &advance;
7254 run.glyphOffsets = &offset;
7255 run.isSideways = FALSE;
7256 run.bidiLevel = 0;
7258 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.9, 0.3, 0.1, DWRITE_PIXEL_GEOMETRY_RGB,
7259 DWRITE_RENDERING_MODE_DEFAULT, &params);
7260 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7262 value = 0;
7263 ret = SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
7264 ok(ret, "got %d\n", ret);
7265 expected_gdi_gamma = (FLOAT)(value / 1000.0);
7267 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
7268 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7269 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
7270 0.0, 0.0, &analysis);
7271 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7273 gamma = contrast = ctlevel = -1.0;
7274 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, NULL, &gamma, &contrast, &ctlevel);
7275 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7276 ok(gamma == -1.0, "got %.2f\n", gamma);
7277 ok(contrast == -1.0, "got %.2f\n", contrast);
7278 ok(ctlevel == -1.0, "got %.2f\n", ctlevel);
7280 gamma = contrast = ctlevel = -1.0;
7281 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &ctlevel);
7282 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7284 if (rendermodes[i] == DWRITE_RENDERING_MODE_GDI_CLASSIC || rendermodes[i] == DWRITE_RENDERING_MODE_GDI_NATURAL) {
7285 ok(float_eq(gamma, expected_gdi_gamma), "got %.2f, expected %.2f\n", gamma, expected_gdi_gamma);
7286 ok(contrast == 0.0f, "got %.2f\n", contrast);
7287 ok(ctlevel == 1.0f, "got %.2f\n", ctlevel);
7289 else {
7290 ok(gamma == 0.9f, "got %.2f\n", gamma);
7291 ok(contrast == 0.3f, "got %.2f\n", contrast);
7292 ok(ctlevel == 0.1f, "got %.2f\n", ctlevel);
7295 IDWriteGlyphRunAnalysis_Release(analysis);
7298 IDWriteRenderingParams_Release(params);
7299 IDWriteFontFace_Release(fontface);
7300 ref = IDWriteFactory_Release(factory);
7301 ok(ref == 0, "factory not released, %lu\n", ref);
7304 static void test_CreateAlphaTexture(void)
7306 IDWriteGlyphRunAnalysis *analysis;
7307 DWRITE_GLYPH_METRICS metrics;
7308 DWRITE_GLYPH_OFFSET offset;
7309 IDWriteFontFace *fontface;
7310 IDWriteFactory *factory;
7311 DWRITE_GLYPH_RUN run;
7312 UINT32 ch, size;
7313 BYTE buff[1024];
7314 RECT bounds, r;
7315 FLOAT advance;
7316 UINT16 glyph;
7317 HRESULT hr;
7318 ULONG ref;
7320 factory = create_factory();
7321 fontface = create_fontface(factory);
7323 ch = 'A';
7324 glyph = 0;
7325 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
7326 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7327 ok(glyph > 0, "got %u\n", glyph);
7329 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
7330 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7331 advance = metrics.advanceWidth;
7333 offset.advanceOffset = 0.0;
7334 offset.ascenderOffset = 0.0;
7336 run.fontFace = fontface;
7337 run.fontEmSize = 24.0;
7338 run.glyphCount = 1;
7339 run.glyphIndices = &glyph;
7340 run.glyphAdvances = &advance;
7341 run.glyphOffsets = &offset;
7342 run.isSideways = FALSE;
7343 run.bidiLevel = 0;
7345 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7346 DWRITE_RENDERING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
7347 0.0, 0.0, &analysis);
7348 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7350 SetRectEmpty(&bounds);
7351 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
7352 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7353 ok(!IsRectEmpty(&bounds), "got empty rect\n");
7354 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top)*3;
7355 ok(sizeof(buff) >= size, "required %u\n", size);
7357 /* invalid type value */
7358 memset(buff, 0xcf, sizeof(buff));
7359 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &bounds, buff, sizeof(buff));
7360 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7361 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7363 memset(buff, 0xcf, sizeof(buff));
7364 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, 2);
7365 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7366 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7368 /* vista version allows texture type mismatch, mark it broken for now */
7369 memset(buff, 0xcf, sizeof(buff));
7370 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, sizeof(buff));
7371 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr);
7372 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
7374 memset(buff, 0xcf, sizeof(buff));
7375 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, size-1);
7376 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7377 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7379 IDWriteGlyphRunAnalysis_Release(analysis);
7381 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7382 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7383 0.0, 0.0, &analysis);
7384 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7386 SetRectEmpty(&bounds);
7387 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
7388 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7389 ok(!IsRectEmpty(&bounds), "got empty rect\n");
7390 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
7391 ok(sizeof(buff) >= size, "required %u\n", size);
7393 memset(buff, 0xcf, sizeof(buff));
7394 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, sizeof(buff));
7395 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7396 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7398 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, NULL, sizeof(buff));
7399 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7401 memset(buff, 0xcf, sizeof(buff));
7402 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, 0);
7403 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
7404 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7406 /* buffer size is not enough */
7407 memset(buff, 0xcf, sizeof(buff));
7408 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, size-1);
7409 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7410 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7412 /* request texture for rectangle that doesn't intersect */
7413 memset(buff, 0xcf, sizeof(buff));
7414 r = bounds;
7415 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7416 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
7417 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7418 ok(buff[0] == 0, "got %1x\n", buff[0]);
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 /* request texture for rectangle that doesn't intersect, small buffer */
7428 memset(buff, 0xcf, sizeof(buff));
7429 r = bounds;
7430 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7431 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, size-1);
7432 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
7433 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7435 /* vista version allows texture type mismatch, mark it broken for now */
7436 memset(buff, 0xcf, sizeof(buff));
7437 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, sizeof(buff));
7438 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr);
7439 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
7441 IDWriteGlyphRunAnalysis_Release(analysis);
7442 IDWriteFontFace_Release(fontface);
7443 ref = IDWriteFactory_Release(factory);
7444 ok(ref == 0, "factory not released, %lu\n", ref);
7447 static BOOL get_expected_is_symbol(IDWriteFontFace *fontface)
7449 BOOL exists, is_symbol = FALSE;
7450 struct dwrite_fonttable cmap;
7451 const TT_OS2_V2 *tt_os2;
7452 const BYTE *tables;
7453 void *os2_context;
7454 WORD num_tables;
7455 unsigned int i;
7456 UINT32 size;
7457 HRESULT hr;
7459 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
7460 ok(hr == S_OK, "Failed to get OS/2 table, hr %#lx.\n", hr);
7462 if (tt_os2)
7464 is_symbol = tt_os2->panose.bFamilyType == PAN_FAMILY_PICTORIAL;
7465 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
7468 if (is_symbol)
7469 return is_symbol;
7471 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, (const void **)&cmap.data,
7472 &cmap.size, &cmap.context, &exists);
7473 if (FAILED(hr) || !exists)
7474 return is_symbol;
7476 num_tables = table_read_be_word(&cmap, 0, FIELD_OFFSET(struct cmap_header, num_tables));
7477 tables = cmap.data + FIELD_OFFSET(struct cmap_header, tables);
7479 for (i = 0; i < num_tables; ++i)
7481 struct cmap_encoding_record *record = (struct cmap_encoding_record *)(tables + i * sizeof(*record));
7482 WORD platform, encoding;
7484 platform = table_read_be_word(&cmap, record, FIELD_OFFSET(struct cmap_encoding_record, platformID));
7485 encoding = table_read_be_word(&cmap, record, FIELD_OFFSET(struct cmap_encoding_record, encodingID));
7487 if (platform == OPENTYPE_CMAP_TABLE_PLATFORM_WIN && encoding == OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL)
7489 is_symbol = TRUE;
7490 break;
7494 IDWriteFontFace_ReleaseFontTable(fontface, cmap.context);
7496 return is_symbol;
7499 static void test_IsSymbolFont(void)
7501 IDWriteFontCollection *collection;
7502 IDWriteFontFace *fontface;
7503 IDWriteFactory *factory;
7504 IDWriteFont *font;
7505 UINT32 count, i;
7506 HRESULT hr;
7507 ULONG ref;
7509 factory = create_factory();
7511 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
7512 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7514 count = IDWriteFontCollection_GetFontFamilyCount(collection);
7515 for (i = 0; i < count; ++i)
7517 IDWriteLocalizedStrings *names;
7518 IDWriteFontFamily *family;
7519 UINT32 font_count, j;
7520 WCHAR nameW[256];
7522 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
7523 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
7525 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7526 ok(hr == S_OK, "Failed to get names, hr %#lx.\n", hr);
7527 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
7528 IDWriteLocalizedStrings_Release(names);
7530 font_count = IDWriteFontFamily_GetFontCount(family);
7532 for (j = 0; j < font_count; ++j)
7534 BOOL is_symbol_font, is_symbol_face, is_symbol_expected;
7536 hr = IDWriteFontFamily_GetFont(family, j, &font);
7537 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
7539 hr = IDWriteFont_CreateFontFace(font, &fontface);
7540 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
7542 is_symbol_font = IDWriteFont_IsSymbolFont(font);
7543 is_symbol_face = IDWriteFontFace_IsSymbolFont(fontface);
7544 ok(is_symbol_font == is_symbol_face, "Unexpected symbol flag.\n");
7546 is_symbol_expected = get_expected_is_symbol(fontface);
7547 ok(is_symbol_expected == is_symbol_face, "Unexpected is_symbol flag %d for %s, font %d.\n",
7548 is_symbol_face, wine_dbgstr_w(nameW), j);
7550 IDWriteFontFace_Release(fontface);
7551 IDWriteFont_Release(font);
7554 IDWriteFontFamily_Release(family);
7557 IDWriteFontCollection_Release(collection);
7559 ref = IDWriteFactory_Release(factory);
7560 ok(ref == 0, "factory not released, %lu\n", ref);
7563 struct CPAL_Header_0
7565 USHORT version;
7566 USHORT numPaletteEntries;
7567 USHORT numPalette;
7568 USHORT numColorRecords;
7569 ULONG offsetFirstColorRecord;
7570 USHORT colorRecordIndices[1];
7573 static void test_GetPaletteEntries(void)
7575 IDWriteFontFace2 *fontface2;
7576 IDWriteFontFace *fontface;
7577 IDWriteFactory *factory;
7578 IDWriteFont *font;
7579 DWRITE_COLOR_F color;
7580 UINT32 palettecount, entrycount, size, colorrecords;
7581 void *ctxt;
7582 const struct CPAL_Header_0 *cpal_header;
7583 HRESULT hr;
7584 BOOL exists;
7585 ULONG ref;
7587 factory = create_factory();
7589 /* Tahoma, no color support */
7590 fontface = create_fontface(factory);
7591 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7592 IDWriteFontFace_Release(fontface);
7593 if (hr != S_OK) {
7594 ref = IDWriteFactory_Release(factory);
7595 ok(ref == 0, "factory not released, %lu\n", ref);
7596 win_skip("GetPaletteEntries() is not supported.\n");
7597 return;
7600 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 1, &color);
7601 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7602 IDWriteFontFace2_Release(fontface2);
7604 /* Segoe UI Emoji, with color support */
7605 font = get_font(factory, L"Segoe UI Emoji", DWRITE_FONT_STYLE_NORMAL);
7606 if (!font) {
7607 ref = IDWriteFactory_Release(factory);
7608 ok(ref == 0, "factory not released, %lu\n", ref);
7609 skip("Segoe UI Emoji font not found.\n");
7610 return;
7613 hr = IDWriteFont_CreateFontFace(font, &fontface);
7614 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7615 IDWriteFont_Release(font);
7617 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7618 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7619 IDWriteFontFace_Release(fontface);
7621 palettecount = IDWriteFontFace2_GetColorPaletteCount(fontface2);
7622 ok(palettecount >= 1, "got %u\n", palettecount);
7624 entrycount = IDWriteFontFace2_GetPaletteEntryCount(fontface2);
7625 ok(entrycount >= 1, "got %u\n", entrycount);
7627 exists = FALSE;
7628 hr = IDWriteFontFace2_TryGetFontTable(fontface2, MS_CPAL_TAG, (const void**)&cpal_header, &size, &ctxt, &exists);
7629 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7630 ok(exists, "got %d\n", exists);
7631 colorrecords = GET_BE_WORD(cpal_header->numColorRecords);
7632 ok(colorrecords >= 1, "got %u\n", colorrecords);
7634 /* invalid palette index */
7635 color.r = color.g = color.b = color.a = 123.0;
7636 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, palettecount, 0, 1, &color);
7637 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7638 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
7639 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7641 /* invalid entry index */
7642 color.r = color.g = color.b = color.a = 123.0;
7643 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount, 1, &color);
7644 ok(hr == E_INVALIDARG, "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 color.r = color.g = color.b = color.a = 123.0;
7649 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount - 1, 1, &color);
7650 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7651 ok(color.r != 123.0 && color.g != 123.0 && color.b != 123.0 && color.a != 123.0,
7652 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7654 /* zero return length */
7655 color.r = color.g = color.b = color.a = 123.0;
7656 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 0, &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 IDWriteFontFace2_Release(fontface2);
7662 ref = IDWriteFactory_Release(factory);
7663 ok(ref == 0, "factory not released, %lu\n", ref);
7666 static void test_TranslateColorGlyphRun(void)
7668 IDWriteColorGlyphRunEnumerator1 *layers1;
7669 IDWriteColorGlyphRunEnumerator *layers;
7670 const DWRITE_COLOR_GLYPH_RUN1 *colorrun1;
7671 const DWRITE_COLOR_GLYPH_RUN *colorrun;
7672 IDWriteFontFace2 *fontface2;
7673 IDWriteFontFace *fontface;
7674 IDWriteFactory4 *factory4;
7675 IDWriteFactory2 *factory;
7676 DWRITE_GLYPH_RUN run;
7677 UINT32 codepoints[2];
7678 IDWriteFont *font;
7679 UINT16 glyphs[2];
7680 BOOL hasrun;
7681 HRESULT hr;
7682 ULONG ref;
7684 factory = create_factory_iid(&IID_IDWriteFactory2);
7685 if (!factory) {
7686 win_skip("TranslateColorGlyphRun() is not supported.\n");
7687 return;
7690 /* Tahoma, no color support */
7691 fontface = create_fontface((IDWriteFactory *)factory);
7693 codepoints[0] = 'A';
7694 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7695 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7697 run.fontFace = fontface;
7698 run.fontEmSize = 20.0f;
7699 run.glyphCount = 1;
7700 run.glyphIndices = glyphs;
7701 run.glyphAdvances = NULL;
7702 run.glyphOffsets = NULL;
7703 run.isSideways = FALSE;
7704 run.bidiLevel = 0;
7706 layers = (void*)0xdeadbeef;
7707 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7708 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7709 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7710 ok(layers == NULL, "got %p\n", layers);
7711 IDWriteFontFace_Release(fontface);
7713 /* Segoe UI Emoji, with color support */
7714 font = get_font((IDWriteFactory *)factory, L"Segoe UI Emoji", DWRITE_FONT_STYLE_NORMAL);
7715 if (!font) {
7716 IDWriteFactory2_Release(factory);
7717 skip("Segoe UI Emoji font not found.\n");
7718 return;
7721 hr = IDWriteFont_CreateFontFace(font, &fontface);
7722 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7723 IDWriteFont_Release(font);
7725 codepoints[0] = 0x26c4;
7726 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7727 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7729 run.fontFace = fontface;
7731 layers = NULL;
7732 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7733 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7734 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7735 ok(layers != NULL, "got %p\n", layers);
7737 hr = IDWriteColorGlyphRunEnumerator_QueryInterface(layers, &IID_IDWriteColorGlyphRunEnumerator1, (void **)&layers1);
7738 if (FAILED(hr))
7740 layers1 = NULL;
7741 win_skip("IDWriteColorGlyphRunEnumerator1 is not supported.\n");
7744 for (;;)
7746 hasrun = FALSE;
7747 hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &hasrun);
7748 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7750 if (!hasrun)
7751 break;
7753 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
7754 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7755 ok(colorrun->glyphRun.fontFace == fontface, "Unexpected fontface %p.\n", colorrun->glyphRun.fontFace);
7756 ok(colorrun->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun->glyphRun.fontEmSize);
7757 ok(colorrun->glyphRun.glyphCount == 1, "Unexpected glyph count %u.\n", colorrun->glyphRun.glyphCount);
7758 ok(colorrun->glyphRun.glyphIndices != NULL, "got null glyph indices %p\n", colorrun->glyphRun.glyphIndices);
7759 ok(colorrun->glyphRun.glyphAdvances != NULL, "got null glyph advances %p\n", colorrun->glyphRun.glyphAdvances);
7760 ok(!colorrun->glyphRunDescription, "Unexpected description pointer.\n");
7762 if (layers1)
7764 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7765 ok(hr == S_OK, "Failed to get color runt, hr %#lx.\n", hr);
7766 ok((const DWRITE_COLOR_GLYPH_RUN *)colorrun1 == colorrun, "Unexpected pointer.\n");
7767 ok(colorrun1->glyphImageFormat == (DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE | DWRITE_GLYPH_IMAGE_FORMATS_COLR) ||
7768 colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_NONE,
7769 "Unexpected glyph image format %#x.\n", colorrun1->glyphImageFormat);
7770 ok(colorrun1->measuringMode == DWRITE_MEASURING_MODE_NATURAL, "Unexpected measuring mode %d.\n",
7771 colorrun1->measuringMode);
7775 /* iterated all way through */
7776 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
7777 ok(hr == E_NOT_VALID_STATE, "Unexpected hr %#lx.\n", hr);
7779 if (layers1)
7781 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7782 ok(hr == E_NOT_VALID_STATE, "Unexpected hr %#lx.\n", hr);
7785 IDWriteColorGlyphRunEnumerator_Release(layers);
7786 if (layers1)
7787 IDWriteColorGlyphRunEnumerator1_Release(layers1);
7789 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7790 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7792 /* invalid palette index */
7793 layers = (void*)0xdeadbeef;
7794 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7795 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2),
7796 &layers);
7797 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7798 ok(layers == NULL, "got %p\n", layers);
7800 layers = NULL;
7801 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7802 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2) - 1,
7803 &layers);
7804 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7805 IDWriteColorGlyphRunEnumerator_Release(layers);
7807 /* color font, glyph without color info */
7808 codepoints[0] = 'A';
7809 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7810 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7811 ok(!!*glyphs, "Unexpected glyph.\n");
7813 layers = (void*)0xdeadbeef;
7814 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7815 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7816 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7817 ok(layers == NULL, "got %p\n", layers);
7819 /* one glyph with, one without */
7820 codepoints[0] = 'A';
7821 codepoints[1] = 0x26c4;
7823 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 2, glyphs);
7824 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7826 run.glyphCount = 2;
7828 layers = NULL;
7829 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7830 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7831 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7832 ok(layers != NULL, "got %p\n", layers);
7834 hr = IDWriteColorGlyphRunEnumerator_QueryInterface(layers, &IID_IDWriteColorGlyphRunEnumerator1, (void **)&layers1);
7835 if (SUCCEEDED(hr))
7837 for (;;)
7839 hasrun = FALSE;
7840 hr = IDWriteColorGlyphRunEnumerator1_MoveNext(layers1, &hasrun);
7841 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7843 if (!hasrun)
7844 break;
7846 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7847 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7848 ok(!!colorrun1->glyphRun.fontFace, "Unexpected fontface %p.\n", colorrun1->glyphRun.fontFace);
7849 ok(colorrun1->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun1->glyphRun.fontEmSize);
7850 ok(colorrun1->glyphRun.glyphCount > 0, "Unexpected glyph count %u.\n", colorrun1->glyphRun.glyphCount);
7851 ok(!!colorrun1->glyphRun.glyphIndices, "Unexpected indices %p.\n", colorrun1->glyphRun.glyphIndices);
7852 ok(!!colorrun1->glyphRun.glyphAdvances, "Unexpected advances %p.\n", colorrun1->glyphRun.glyphAdvances);
7853 ok(!colorrun1->glyphRunDescription, "Unexpected description pointer.\n");
7854 todo_wine
7855 ok(colorrun1->glyphImageFormat == (DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE | DWRITE_GLYPH_IMAGE_FORMATS_COLR) ||
7856 colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE, "Unexpected glyph image format %#x.\n",
7857 colorrun1->glyphImageFormat);
7858 ok(colorrun1->measuringMode == DWRITE_MEASURING_MODE_NATURAL, "Unexpected measuring mode %d.\n",
7859 colorrun1->measuringMode);
7862 IDWriteColorGlyphRunEnumerator1_Release(layers1);
7864 IDWriteColorGlyphRunEnumerator_Release(layers);
7866 if (SUCCEEDED(IDWriteFactory2_QueryInterface(factory, &IID_IDWriteFactory4, (void **)&factory4)))
7868 D2D1_POINT_2F origin;
7870 origin.x = origin.y = 0.0f;
7871 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7872 DWRITE_GLYPH_IMAGE_FORMATS_NONE, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7873 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7875 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7876 DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7877 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7879 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7880 DWRITE_GLYPH_IMAGE_FORMATS_CFF, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7881 ok(hr == DWRITE_E_NOCOLOR, "Unexpected hr %#lx.\n", hr);
7883 hr = IDWriteFactory4_TranslateColorGlyphRun(factory4, origin, &run, NULL,
7884 DWRITE_GLYPH_IMAGE_FORMATS_COLR, DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers1);
7885 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7887 for (;;)
7889 hasrun = FALSE;
7890 hr = IDWriteColorGlyphRunEnumerator1_MoveNext(layers1, &hasrun);
7891 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7893 if (!hasrun)
7894 break;
7896 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7897 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7898 ok(!!colorrun1->glyphRun.fontFace, "Unexpected fontface %p.\n", colorrun1->glyphRun.fontFace);
7899 ok(colorrun1->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun1->glyphRun.fontEmSize);
7900 ok(colorrun1->glyphRun.glyphCount > 0, "Unexpected glyph count %u.\n", colorrun1->glyphRun.glyphCount);
7901 ok(!!colorrun1->glyphRun.glyphIndices, "Unexpected indices %p.\n", colorrun1->glyphRun.glyphIndices);
7902 ok(!!colorrun1->glyphRun.glyphAdvances, "Unexpected advances %p.\n", colorrun1->glyphRun.glyphAdvances);
7903 ok(!colorrun1->glyphRunDescription, "Unexpected description pointer.\n");
7904 ok(colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_COLR ||
7905 colorrun1->glyphImageFormat == DWRITE_GLYPH_IMAGE_FORMATS_NONE, "Unexpected glyph image format %#x.\n",
7906 colorrun1->glyphImageFormat);
7907 ok(colorrun1->measuringMode == DWRITE_MEASURING_MODE_NATURAL, "Unexpected measuring mode %d.\n",
7908 colorrun1->measuringMode);
7911 IDWriteColorGlyphRunEnumerator1_Release(layers1);
7913 IDWriteFactory4_Release(factory4);
7915 else
7916 win_skip("IDWriteFactory4::TranslateColorGlyphRun() is not supported.\n");
7918 IDWriteFontFace2_Release(fontface2);
7919 IDWriteFontFace_Release(fontface);
7920 ref = IDWriteFactory2_Release(factory);
7921 ok(ref == 0, "factory not released, %lu\n", ref);
7924 static void test_HasCharacter(void)
7926 IDWriteFactory3 *factory3;
7927 IDWriteFactory *factory;
7928 IDWriteFont3 *font3;
7929 IDWriteFont *font;
7930 HRESULT hr;
7931 ULONG ref;
7932 BOOL ret;
7934 factory = create_factory();
7936 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
7937 ok(font != NULL, "failed to create font\n");
7939 /* Win8 is broken, QI claims to support IDWriteFont3, but in fact it does not */
7940 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
7941 if (hr == S_OK) {
7942 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
7943 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
7945 ret = IDWriteFont3_HasCharacter(font3, 'A');
7946 ok(ret, "got %d\n", ret);
7948 IDWriteFont3_Release(font3);
7949 IDWriteFactory3_Release(factory3);
7951 else
7952 win_skip("IDWriteFont3 is not supported.\n");
7954 IDWriteFont_Release(font);
7955 ref = IDWriteFactory_Release(factory);
7956 ok(ref == 0, "factory not released, %lu\n", ref);
7959 static BOOL has_main_axis_values(const DWRITE_FONT_AXIS_VALUE *values, unsigned int count)
7961 BOOL has_wght = FALSE, has_wdth = FALSE, has_ital = FALSE, has_slnt = FALSE;
7962 unsigned int i;
7964 for (i = 0; i < count; ++i)
7966 if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT)
7967 has_wght = TRUE;
7968 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_WIDTH)
7969 has_wdth = TRUE;
7970 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_ITALIC)
7971 has_ital = TRUE;
7972 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_SLANT)
7973 has_slnt = TRUE;
7976 return has_wght && has_wdth && has_ital && has_slnt;
7979 static void test_CreateFontFaceReference(void)
7981 IDWriteFontFaceReference *ref, *ref1, *ref3;
7982 IDWriteFontFace3 *fontface, *fontface1;
7983 DWRITE_FONT_AXIS_VALUE axis_values[16];
7984 IDWriteFontCollection1 *collection;
7985 IDWriteFontFile *file, *file1;
7986 IDWriteFactory3 *factory;
7987 UINT32 index, count, i;
7988 IDWriteFont3 *font3;
7989 ULONG refcount;
7990 WCHAR *path;
7991 HRESULT hr;
7992 BOOL ret;
7994 factory = create_factory_iid(&IID_IDWriteFactory3);
7995 if (!factory) {
7996 win_skip("CreateFontFaceReference() is not supported.\n");
7997 return;
8000 path = create_testfontfile(test_fontfile);
8002 hr = IDWriteFactory3_CreateFontFaceReference(factory, NULL, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8003 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
8005 /* out of range simulation flags */
8006 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, ~0u, &ref);
8007 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
8009 /* test file is not a collection, but reference could still be created with non-zero face index */
8010 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8011 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8013 index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
8014 ok(index == 1, "got %u\n", index);
8016 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
8017 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8018 IDWriteFontFile_Release(file);
8020 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
8021 todo_wine
8022 ok(hr == DWRITE_E_FILEFORMAT, "Unexpected hr %#lx.\n", hr);
8024 IDWriteFontFaceReference_Release(ref);
8026 /* path however has to be valid */
8027 hr = IDWriteFactory3_CreateFontFaceReference(factory, L"dummy", NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8028 todo_wine
8029 ok(hr == DWRITE_E_FILENOTFOUND, "Unexpected hr %#lx.\n", hr);
8030 if (hr == S_OK)
8031 IDWriteFontFaceReference_Release(ref);
8033 EXPECT_REF(factory, 1);
8034 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8035 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8036 EXPECT_REF(factory, 2);
8038 /* new file is returned */
8039 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
8040 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8042 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
8043 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8044 ok(file != file1, "got %p, previous file %p\n", file1, file);
8046 IDWriteFontFile_Release(file);
8047 IDWriteFontFile_Release(file1);
8049 /* references are not reused */
8050 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
8051 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8052 ok(ref1 != ref, "got %p, previous ref %p\n", ref1, ref);
8054 /* created fontfaces are cached */
8055 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
8056 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8058 hr = IDWriteFontFaceReference_CreateFontFace(ref1, &fontface1);
8059 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8060 ok(fontface == fontface1, "got %p, expected %p\n", fontface1, fontface);
8061 IDWriteFontFace3_Release(fontface);
8062 IDWriteFontFace3_Release(fontface1);
8064 /* reference equality */
8065 ret = IDWriteFontFaceReference_Equals(ref, ref1);
8066 ok(ret, "got %d\n", ret);
8067 IDWriteFontFaceReference_Release(ref1);
8069 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
8070 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8071 ret = IDWriteFontFaceReference_Equals(ref, ref1);
8072 ok(!ret, "got %d\n", ret);
8073 IDWriteFontFaceReference_Release(ref1);
8075 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_BOLD, &ref1);
8076 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8077 ret = IDWriteFontFaceReference_Equals(ref, ref1);
8078 ok(!ret, "got %d\n", ret);
8079 IDWriteFontFaceReference_Release(ref1);
8081 IDWriteFontFaceReference_Release(ref);
8083 /* create reference from a file */
8084 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
8085 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8087 hr = IDWriteFactory3_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
8088 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8090 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
8091 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8092 ok(file != file1, "got %p, previous file %p\n", file1, file);
8094 IDWriteFontFaceReference_Release(ref);
8095 IDWriteFontFile_Release(file);
8096 IDWriteFontFile_Release(file1);
8098 /* References returned from IDWriteFont3/IDWriteFontFace3. */
8099 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
8100 ok(hr == S_OK, "Failed to get system collection, hr %#lx.\n", hr);
8102 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
8103 for (i = 0; i < count; i++)
8105 IDWriteFontFamily1 *family;
8106 UINT32 font_count, j;
8108 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
8109 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
8111 font_count = IDWriteFontFamily1_GetFontCount(family);
8113 for (j = 0; j < font_count; j++)
8115 IDWriteFontFaceReference1 *ref2;
8117 hr = IDWriteFontFamily1_GetFont(family, j, &font3);
8118 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
8120 hr = IDWriteFont3_GetFontFaceReference(font3, &ref);
8121 ok(hr == S_OK, "Failed to get reference object, hr %#lx.\n", hr);
8123 hr = IDWriteFont3_GetFontFaceReference(font3, &ref1);
8124 ok(hr == S_OK, "Failed to get reference object, hr %#lx.\n", hr);
8125 ok(ref != ref1, "Unexpected reference object %p, %p.\n", ref1, ref);
8127 hr = IDWriteFont3_CreateFontFace(font3, &fontface);
8128 ok(hr == S_OK, "Failed to create a fontface, hr %#lx.\n", hr);
8130 /* Fonts present regular properties as axis values, for non-variable fonts too.
8131 Normally it would include weight/width/slant/italic, but could also contain optical size axis. */
8132 if (SUCCEEDED(hr = IDWriteFontFaceReference_QueryInterface(ref, &IID_IDWriteFontFaceReference1,
8133 (void **)&ref2)))
8135 UINT32 axis_count = IDWriteFontFaceReference1_GetFontAxisValueCount(ref2);
8136 todo_wine
8137 ok(axis_count >= 4, "Unexpected axis value count.\n");
8139 hr = IDWriteFontFaceReference1_GetFontAxisValues(ref2, axis_values, ARRAY_SIZE(axis_values));
8140 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8142 todo_wine
8143 ok(has_main_axis_values(axis_values, axis_count), "Unexpected axis returned.\n");
8145 IDWriteFontFaceReference1_Release(ref2);
8148 IDWriteFontFaceReference_Release(ref);
8149 IDWriteFontFaceReference_Release(ref1);
8151 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref);
8152 ok(hr == S_OK, "Failed to get a reference, hr %#lx.\n", hr);
8153 EXPECT_REF(fontface, 2);
8155 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref1);
8156 ok(hr == S_OK, "Failed to get a reference, hr %#lx.\n", hr);
8157 ok(ref == ref1, "Unexpected reference %p, %p.\n", ref1, ref);
8158 EXPECT_REF(fontface, 3);
8160 hr = IDWriteFontFace3_QueryInterface(fontface, &IID_IDWriteFontFaceReference, (void **)&ref3);
8161 ok(hr == S_OK || broken(FAILED(hr)), "Failed to get interface, hr %#lx.\n", hr);
8162 if (SUCCEEDED(hr))
8164 ok(ref == ref3, "Unexpected reference %p.\n", ref3);
8165 IDWriteFontFaceReference_Release(ref3);
8168 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface1);
8169 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
8170 ok(fontface1 == fontface, "Unexpected fontface %p, %p.\n", fontface1, fontface);
8171 IDWriteFontFace3_Release(fontface1);
8173 IDWriteFontFaceReference_Release(ref);
8174 IDWriteFontFaceReference_Release(ref1);
8176 IDWriteFontFace3_Release(fontface);
8177 IDWriteFont3_Release(font3);
8180 IDWriteFontFamily1_Release(family);
8182 IDWriteFontCollection1_Release(collection);
8184 refcount = IDWriteFactory3_Release(factory);
8185 ok(refcount == 0, "factory not released, %lu\n", refcount);
8186 DELETE_FONTFILE(path);
8189 static void get_expected_fontsig(IDWriteFont *font, FONTSIGNATURE *fontsig)
8191 void *os2_context;
8192 IDWriteFontFace *fontface;
8193 const TT_OS2_V2 *tt_os2;
8194 UINT32 size;
8195 BOOL exists;
8196 HRESULT hr;
8198 memset(fontsig, 0, sizeof(*fontsig));
8200 hr = IDWriteFont_CreateFontFace(font, &fontface);
8201 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8203 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
8204 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8206 if (tt_os2) {
8207 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
8208 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
8209 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
8210 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
8212 if (GET_BE_WORD(tt_os2->version) == 0) {
8213 fontsig->fsCsb[0] = 0;
8214 fontsig->fsCsb[1] = 0;
8216 else {
8217 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
8218 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
8221 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
8224 IDWriteFontFace_Release(fontface);
8227 static void test_GetFontSignature(void)
8229 IDWriteFontCollection *syscollection;
8230 IDWriteGdiInterop1 *interop1;
8231 IDWriteGdiInterop *interop;
8232 IDWriteFactory *factory;
8233 FONTSIGNATURE fontsig;
8234 UINT count, i;
8235 HRESULT hr;
8236 ULONG ref;
8238 factory = create_factory();
8240 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
8241 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8243 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
8244 IDWriteGdiInterop_Release(interop);
8245 if (FAILED(hr)) {
8246 win_skip("GetFontSignature() is not supported.\n");
8247 IDWriteGdiInterop_Release(interop);
8248 IDWriteFactory_Release(factory);
8249 return;
8251 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8253 hr = IDWriteGdiInterop1_GetFontSignature(interop1, NULL, &fontsig);
8254 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
8256 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8257 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8258 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8260 for (i = 0; i < count; i++) {
8261 FONTSIGNATURE expected_signature;
8262 IDWriteLocalizedStrings *names;
8263 IDWriteFontFamily *family;
8264 IDWriteFont *font;
8265 WCHAR nameW[256];
8267 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8268 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8270 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8271 DWRITE_FONT_STYLE_NORMAL, &font);
8272 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8274 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8275 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8277 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8279 IDWriteLocalizedStrings_Release(names);
8281 hr = IDWriteGdiInterop1_GetFontSignature(interop1, font, &fontsig);
8282 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8284 get_expected_fontsig(font, &expected_signature);
8286 winetest_push_context("Font %s\n", wine_dbgstr_w(nameW));
8288 ok(fontsig.fsUsb[0] == expected_signature.fsUsb[0], "fsUsb[0] %#lx, expected %#lx.\n",
8289 fontsig.fsUsb[0], expected_signature.fsUsb[0]);
8290 ok(fontsig.fsUsb[1] == expected_signature.fsUsb[1], "fsUsb[1] %#lx, expected %#lx.\n",
8291 fontsig.fsUsb[1], expected_signature.fsUsb[1]);
8292 ok(fontsig.fsUsb[2] == expected_signature.fsUsb[2], "fsUsb[2] %#lx, expected %#lx.\n",
8293 fontsig.fsUsb[2], expected_signature.fsUsb[2]);
8294 ok(fontsig.fsUsb[3] == expected_signature.fsUsb[3], "fsUsb[3] %#lx, expected %#lx.\n",
8295 fontsig.fsUsb[3], expected_signature.fsUsb[3]);
8297 ok(fontsig.fsCsb[0] == expected_signature.fsCsb[0], "fsCsb[0] %#lx, expected %#lx.\n",
8298 fontsig.fsCsb[0], expected_signature.fsCsb[0]);
8299 ok(fontsig.fsCsb[1] == expected_signature.fsCsb[1], "fsCsb[1] %#lx, expected %#lx.\n",
8300 fontsig.fsCsb[1], expected_signature.fsCsb[1]);
8302 winetest_pop_context();
8304 IDWriteFont_Release(font);
8305 IDWriteFontFamily_Release(family);
8308 IDWriteGdiInterop1_Release(interop1);
8309 IDWriteFontCollection_Release(syscollection);
8310 ref = IDWriteFactory_Release(factory);
8311 ok(ref == 0, "factory not released, %lu\n", ref);
8314 static void test_font_properties(void)
8316 IDWriteFontFace3 *fontface3;
8317 IDWriteFontFace *fontface;
8318 IDWriteFactory *factory;
8319 DWRITE_FONT_STYLE style;
8320 IDWriteFont *font;
8321 HRESULT hr;
8322 ULONG ref;
8324 factory = create_factory();
8326 /* this creates simulated font */
8327 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
8329 style = IDWriteFont_GetStyle(font);
8330 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
8332 hr = IDWriteFont_CreateFontFace(font, &fontface);
8333 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8335 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
8336 IDWriteFontFace_Release(fontface);
8337 if (hr == S_OK) {
8338 style = IDWriteFontFace3_GetStyle(fontface3);
8339 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
8341 IDWriteFontFace3_Release(fontface3);
8344 IDWriteFont_Release(font);
8345 ref = IDWriteFactory_Release(factory);
8346 ok(ref == 0, "factory not released, %lu\n", ref);
8349 static BOOL has_vertical_glyph_variants(IDWriteFontFace1 *fontface)
8351 const OT_FeatureList *featurelist;
8352 const OT_LookupList *lookup_list;
8353 BOOL exists = FALSE, ret = FALSE;
8354 const GSUB_Header *header;
8355 const void *data;
8356 void *context;
8357 UINT32 size;
8358 HRESULT hr;
8359 UINT16 i;
8361 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
8362 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8364 if (!exists)
8365 return FALSE;
8367 header = data;
8368 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
8369 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
8371 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
8372 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
8373 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
8374 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
8375 const GSUB_SingleSubstFormat2 *subst2;
8376 const OT_LookupTable *lookup_table;
8377 UINT32 offset;
8379 if (lookup_count == 0)
8380 continue;
8382 for (i = 0; i < lookup_count; i++) {
8383 /* check if lookup is empty */
8384 index = GET_BE_WORD(feature->LookupListIndex[i]);
8385 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
8387 type = GET_BE_WORD(lookup_table->LookupType);
8388 ok(type == 1 || type == 7, "got unexpected lookup type %u\n", type);
8390 count = GET_BE_WORD(lookup_table->SubTableCount);
8391 if (count == 0)
8392 continue;
8394 ok(count > 0, "got unexpected subtable count %u\n", count);
8396 offset = GET_BE_WORD(lookup_table->SubTable[0]);
8397 if (type == 7) {
8398 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
8399 if (GET_BE_WORD(ext->SubstFormat) == 1)
8400 offset += GET_BE_DWORD(ext->ExtensionOffset);
8401 else
8402 ok(0, "Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
8405 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
8406 index = GET_BE_WORD(subst2->SubstFormat);
8407 if (index == 1)
8408 ret = TRUE;
8409 else if (index == 2) {
8410 /* SimSun-ExtB has 0 glyph count for this substitution */
8411 if (GET_BE_WORD(subst2->GlyphCount) > 0)
8412 ret = TRUE;
8414 else
8415 ok(0, "unknown Single Substitution Format, %u\n", index);
8417 if (ret)
8418 break;
8423 IDWriteFontFace1_ReleaseFontTable(fontface, context);
8425 return ret;
8428 static void test_HasVerticalGlyphVariants(void)
8430 IDWriteFontCollection *syscollection;
8431 IDWriteFontFace1 *fontface1;
8432 IDWriteFontFace *fontface;
8433 IDWriteFactory *factory;
8434 UINT32 count, i;
8435 HRESULT hr;
8436 ULONG ref;
8438 factory = create_factory();
8439 fontface = create_fontface(factory);
8441 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8442 IDWriteFontFace_Release(fontface);
8443 if (hr != S_OK) {
8444 win_skip("HasVerticalGlyphVariants() is not supported.\n");
8445 IDWriteFactory_Release(factory);
8446 return;
8448 IDWriteFontFace1_Release(fontface1);
8450 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8451 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8452 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8454 for (i = 0; i < count; i++) {
8455 IDWriteLocalizedStrings *names;
8456 BOOL expected_vert, has_vert;
8457 IDWriteFontFamily *family;
8458 IDWriteFont *font;
8459 WCHAR nameW[256];
8461 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8462 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8464 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8465 DWRITE_FONT_STYLE_NORMAL, &font);
8466 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8468 hr = IDWriteFont_CreateFontFace(font, &fontface);
8469 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8471 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8472 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8474 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8475 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8477 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8479 expected_vert = has_vertical_glyph_variants(fontface1);
8480 has_vert = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
8482 ok(expected_vert == has_vert, "%s: expected vertical feature %d, got %d\n",
8483 wine_dbgstr_w(nameW), expected_vert, has_vert);
8485 IDWriteLocalizedStrings_Release(names);
8486 IDWriteFont_Release(font);
8488 IDWriteFontFace1_Release(fontface1);
8489 IDWriteFontFace_Release(fontface);
8490 IDWriteFontFamily_Release(family);
8493 IDWriteFontCollection_Release(syscollection);
8494 ref = IDWriteFactory_Release(factory);
8495 ok(ref == 0, "factory not released, %lu\n", ref);
8498 static void test_HasKerningPairs(void)
8500 IDWriteFontCollection *syscollection;
8501 IDWriteFontFace1 *fontface1;
8502 IDWriteFontFace *fontface;
8503 IDWriteFactory *factory;
8504 UINT32 count, i;
8505 HRESULT hr;
8506 ULONG ref;
8508 factory = create_factory();
8509 fontface = create_fontface(factory);
8511 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8512 IDWriteFontFace_Release(fontface);
8513 if (hr != S_OK) {
8514 win_skip("HasKerningPairs() is not supported.\n");
8515 IDWriteFactory_Release(factory);
8516 return;
8518 IDWriteFontFace1_Release(fontface1);
8520 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8521 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8522 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8524 for (i = 0; i < count; i++) {
8525 IDWriteLocalizedStrings *names;
8526 BOOL exists, has_kerningpairs;
8527 IDWriteFontFamily *family;
8528 IDWriteFont *font;
8529 WCHAR nameW[256];
8530 const void *data;
8531 void *context;
8532 UINT32 size;
8534 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8535 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8537 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8538 DWRITE_FONT_STYLE_NORMAL, &font);
8539 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8541 hr = IDWriteFont_CreateFontFace(font, &fontface);
8542 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8544 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
8545 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8547 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8548 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8550 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8552 exists = FALSE;
8553 hr = IDWriteFontFace1_TryGetFontTable(fontface1, MS_KERN_TAG, &data, &size, &context, &exists);
8554 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8555 IDWriteFontFace1_ReleaseFontTable(fontface1, context);
8557 has_kerningpairs = IDWriteFontFace1_HasKerningPairs(fontface1);
8558 if (!exists)
8559 ok(!has_kerningpairs, "%s: expected %d, got %d\n", wine_dbgstr_w(nameW), exists, has_kerningpairs);
8561 IDWriteLocalizedStrings_Release(names);
8562 IDWriteFont_Release(font);
8564 IDWriteFontFace1_Release(fontface1);
8565 IDWriteFontFace_Release(fontface);
8566 IDWriteFontFamily_Release(family);
8569 IDWriteFontCollection_Release(syscollection);
8570 ref = IDWriteFactory_Release(factory);
8571 ok(ref == 0, "factory not released, %lu\n", ref);
8574 static float get_scaled_metric(const DWRITE_GLYPH_RUN *run, float metric, const DWRITE_FONT_METRICS *m)
8576 return run->fontEmSize * metric / m->designUnitsPerEm;
8579 static void get_expected_glyph_origins(D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *run,
8580 D2D1_POINT_2F *origins)
8582 DWRITE_GLYPH_METRICS glyph_metrics[2];
8583 DWRITE_FONT_METRICS metrics;
8584 unsigned int i;
8585 HRESULT hr;
8587 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
8589 hr = IDWriteFontFace_GetDesignGlyphMetrics(run->fontFace, run->glyphIndices, run->glyphCount, glyph_metrics,
8590 run->isSideways);
8591 ok(hr == S_OK, "Failed to get glyph metrics, hr %#lx.\n", hr);
8593 if (run->bidiLevel & 1)
8595 float advance;
8597 advance = get_scaled_metric(run, run->isSideways ? glyph_metrics[0].advanceHeight :
8598 glyph_metrics[0].advanceWidth, &metrics);
8600 baseline_origin.x -= advance;
8602 for (i = 0; i < run->glyphCount; ++i)
8604 origins[i] = baseline_origin;
8606 if (run->isSideways)
8608 origins[i].x += get_scaled_metric(run, glyph_metrics[i].verticalOriginY, &metrics);
8609 origins[i].y += metrics.designUnitsPerEm / (4.0f * run->fontEmSize);
8612 origins[i].x -= run->glyphOffsets[i].advanceOffset;
8613 origins[i].y -= run->glyphOffsets[i].ascenderOffset;
8615 baseline_origin.x -= run->glyphAdvances[i];
8618 else
8620 for (i = 0; i < run->glyphCount; ++i)
8622 origins[i] = baseline_origin;
8624 if (run->isSideways)
8626 origins[i].x += get_scaled_metric(run, glyph_metrics[i].verticalOriginY, &metrics);
8627 origins[i].y += metrics.designUnitsPerEm / (4.0f * run->fontEmSize);
8630 origins[i].x += run->glyphOffsets[i].advanceOffset;
8631 origins[i].y -= run->glyphOffsets[i].ascenderOffset;
8633 baseline_origin.x += run->glyphAdvances[i];
8638 static void test_ComputeGlyphOrigins(void)
8640 static const struct origins_test
8642 D2D1_POINT_2F baseline_origin;
8643 float advances[2];
8644 DWRITE_GLYPH_OFFSET offsets[2];
8645 unsigned int bidi_level;
8646 unsigned int sideways;
8648 origins_tests[] =
8650 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } } },
8651 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } } },
8652 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 1 },
8654 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 0, 1 },
8655 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } }, 0, 1 },
8656 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 1, 1 },
8657 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } }, 1, 1 },
8659 IDWriteFactory4 *factory;
8660 DWRITE_GLYPH_RUN run;
8661 HRESULT hr;
8662 D2D1_POINT_2F origins[2], expected_origins[2];
8663 D2D1_POINT_2F baseline_origin;
8664 UINT16 glyphs[2] = { 0 };
8665 FLOAT advances[2];
8666 DWRITE_MATRIX m;
8667 ULONG ref;
8668 unsigned int i, j;
8669 IDWriteFontFace *fontface;
8671 factory = create_factory_iid(&IID_IDWriteFactory4);
8672 if (!factory) {
8673 win_skip("ComputeGlyphOrigins() is not supported.\n");
8674 return;
8677 fontface = create_fontface((IDWriteFactory *)factory);
8679 for (i = 0; i < ARRAY_SIZE(origins_tests); ++i)
8681 run.fontFace = fontface;
8682 run.fontEmSize = 32.0f;
8683 run.glyphCount = 2;
8684 run.glyphIndices = glyphs;
8685 run.glyphAdvances = origins_tests[i].advances;
8686 run.glyphOffsets = origins_tests[i].offsets;
8687 run.isSideways = !!origins_tests[i].sideways;
8688 run.bidiLevel = origins_tests[i].bidi_level;
8690 get_expected_glyph_origins(origins_tests[i].baseline_origin, &run, expected_origins);
8692 memset(origins, 0, sizeof(origins));
8693 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, origins_tests[i].baseline_origin, origins);
8694 ok(hr == S_OK, "%u: failed to compute glyph origins, hr %#lx.\n", i, hr);
8695 for (j = 0; j < run.glyphCount; ++j)
8697 todo_wine_if(run.isSideways)
8698 ok(!memcmp(&origins[j], &expected_origins[j], sizeof(origins[j])),
8699 "%u: unexpected origin[%u] (%f, %f) - (%f, %f).\n", i, j, origins[j].x, origins[j].y,
8700 expected_origins[j].x, expected_origins[j].y);
8704 IDWriteFontFace_Release(fontface);
8706 advances[0] = 10.0f;
8707 advances[1] = 20.0f;
8709 run.fontFace = NULL;
8710 run.fontEmSize = 16.0f;
8711 run.glyphCount = 2;
8712 run.glyphIndices = glyphs;
8713 run.glyphAdvances = advances;
8714 run.glyphOffsets = NULL;
8715 run.isSideways = FALSE;
8716 run.bidiLevel = 0;
8718 baseline_origin.x = 123.0f;
8719 baseline_origin.y = 321.0f;
8721 memset(origins, 0, sizeof(origins));
8722 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, baseline_origin, origins);
8723 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
8724 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8725 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8727 memset(origins, 0, sizeof(origins));
8728 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
8729 NULL, origins);
8730 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8731 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8733 /* transform is not applied to returned origins */
8734 m.m11 = 2.0f;
8735 m.m12 = 0.0f;
8736 m.m21 = 0.0f;
8737 m.m22 = 1.0f;
8738 m.dx = 0.0f;
8739 m.dy = 0.0f;
8741 memset(origins, 0, sizeof(origins));
8742 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
8743 &m, origins);
8744 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8745 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8747 ref = IDWriteFactory4_Release(factory);
8748 ok(ref == 0, "factory not released, %lu\n", ref);
8751 static void test_object_lifetime(void)
8753 IDWriteFontCollection *collection, *collection2;
8754 IDWriteFontList *fontlist, *fontlist2;
8755 IDWriteGdiInterop *interop, *interop2;
8756 IDWriteFontFamily *family, *family2;
8757 IDWriteFontFace *fontface;
8758 IDWriteFont *font, *font2;
8759 IDWriteFactory *factory;
8760 HRESULT hr;
8761 ULONG ref;
8763 factory = create_factory();
8764 EXPECT_REF(factory, 1);
8766 /* system collection takes factory reference */
8767 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
8768 ok(hr == S_OK, "got %#lx\n", hr);
8770 EXPECT_REF(collection, 1);
8771 EXPECT_REF(factory, 2);
8773 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection2, FALSE);
8774 ok(hr == S_OK, "got %#lx\n", hr);
8775 ok(collection2 == collection, "expected same collection\n");
8777 EXPECT_REF(collection, 2);
8778 EXPECT_REF(factory, 2);
8780 IDWriteFontCollection_Release(collection2);
8782 IDWriteFontCollection_AddRef(collection);
8783 EXPECT_REF(collection, 2);
8784 EXPECT_REF(factory, 2);
8785 IDWriteFontCollection_Release(collection);
8787 EXPECT_REF(collection, 1);
8789 /* family takes collection reference */
8790 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
8791 ok(hr == S_OK, "got %#lx\n", hr);
8793 EXPECT_REF(family, 1);
8794 EXPECT_REF(collection, 2);
8795 EXPECT_REF(factory, 2);
8797 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family2);
8798 ok(hr == S_OK, "got %#lx\n", hr);
8800 EXPECT_REF(family2, 1);
8801 EXPECT_REF(collection, 3);
8802 EXPECT_REF(factory, 2);
8804 IDWriteFontFamily_Release(family2);
8806 EXPECT_REF(family, 1);
8807 EXPECT_REF(collection, 2);
8808 EXPECT_REF(factory, 2);
8810 /* font takes family reference */
8811 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
8812 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
8813 ok(hr == S_OK, "got %#lx\n", hr);
8815 EXPECT_REF(family, 2);
8816 EXPECT_REF(collection, 2);
8817 EXPECT_REF(factory, 2);
8819 hr = IDWriteFont_GetFontFamily(font, &family2);
8820 ok(hr == S_OK, "got %#lx\n", hr);
8821 ok(family2 == family, "unexpected family pointer\n");
8822 IDWriteFontFamily_Release(family2);
8824 EXPECT_REF(font, 1);
8825 EXPECT_REF(factory, 2);
8827 /* Fontface takes factory reference and nothing else. */
8828 hr = IDWriteFont_CreateFontFace(font, &fontface);
8829 ok(hr == S_OK, "got %#lx\n", hr);
8831 EXPECT_REF(font, 1);
8832 EXPECT_REF_BROKEN(fontface, 1, 2);
8833 EXPECT_REF(family, 2);
8834 EXPECT_REF(collection, 2);
8835 EXPECT_REF_BROKEN(factory, 3, 2);
8837 /* get font from fontface */
8838 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
8839 ok(hr == S_OK, "got %#lx\n", hr);
8841 EXPECT_REF(font, 1);
8842 EXPECT_REF(font2, 1);
8843 EXPECT_REF_BROKEN(fontface, 1, 2);
8844 EXPECT_REF(family, 2);
8845 EXPECT_REF(collection, 3);
8846 EXPECT_REF_BROKEN(factory, 3, 2);
8848 IDWriteFont_Release(font2);
8849 IDWriteFontFace_Release(fontface);
8851 EXPECT_REF(font, 1);
8852 EXPECT_REF(family, 2);
8853 EXPECT_REF(collection, 2);
8854 EXPECT_REF(factory, 2);
8856 IDWriteFont_Release(font);
8858 EXPECT_REF(family, 1);
8859 EXPECT_REF(collection, 2);
8860 EXPECT_REF(factory, 2);
8862 /* Matching fonts list takes family reference. */
8863 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
8864 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
8865 ok(hr == S_OK, "got %#lx\n", hr);
8867 EXPECT_REF(family, 2);
8868 EXPECT_REF(collection, 2);
8869 EXPECT_REF(factory, 2);
8871 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
8872 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
8873 ok(hr == S_OK, "got %#lx\n", hr);
8874 ok(fontlist2 != fontlist, "unexpected font list\n");
8875 IDWriteFontList_Release(fontlist2);
8877 IDWriteFontList_Release(fontlist);
8879 IDWriteFontFamily_Release(family);
8880 EXPECT_REF(collection, 1);
8882 EXPECT_REF(factory, 2);
8883 ref = IDWriteFontCollection_Release(collection);
8884 ok(ref == 0, "collection not released, %lu\n", ref);
8885 EXPECT_REF(factory, 1);
8887 /* GDI interop object takes factory reference */
8888 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
8889 ok(hr == S_OK, "got %#lx\n", hr);
8890 EXPECT_REF(interop, 1);
8891 EXPECT_REF(factory, 2);
8893 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
8894 ok(hr == S_OK, "got %#lx\n", hr);
8895 ok(interop == interop2, "got unexpected interop pointer\n");
8897 EXPECT_REF(interop, 2);
8898 EXPECT_REF(factory, 2);
8900 IDWriteGdiInterop_Release(interop2);
8901 ref = IDWriteGdiInterop_Release(interop);
8902 ok(ref == 0, "interop not released, %lu\n", ref);
8904 ref = IDWriteFactory_Release(factory);
8905 ok(ref == 0, "factory not released, %lu\n", ref);
8908 struct testowner_object
8910 IUnknown IUnknown_iface;
8911 LONG ref;
8914 static inline struct testowner_object *impl_from_IUnknown(IUnknown *iface)
8916 return CONTAINING_RECORD(iface, struct testowner_object, IUnknown_iface);
8919 static HRESULT WINAPI testowner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
8921 if (IsEqualIID(riid, &IID_IUnknown)) {
8922 *obj = iface;
8923 IUnknown_AddRef(iface);
8924 return S_OK;
8927 *obj = NULL;
8928 return E_NOINTERFACE;
8931 static ULONG WINAPI testowner_AddRef(IUnknown *iface)
8933 struct testowner_object *object = impl_from_IUnknown(iface);
8934 return InterlockedIncrement(&object->ref);
8937 static ULONG WINAPI testowner_Release(IUnknown *iface)
8939 struct testowner_object *object = impl_from_IUnknown(iface);
8940 return InterlockedDecrement(&object->ref);
8943 static const IUnknownVtbl testownervtbl = {
8944 testowner_QueryInterface,
8945 testowner_AddRef,
8946 testowner_Release,
8949 static void testowner_init(struct testowner_object *object)
8951 object->IUnknown_iface.lpVtbl = &testownervtbl;
8952 object->ref = 1;
8955 static void test_inmemory_file_loader(void)
8957 IDWriteFontFileStream *stream, *stream2, *stream3;
8958 IDWriteInMemoryFontFileLoader *loader, *loader2;
8959 IDWriteInMemoryFontFileLoader *inmemory;
8960 IDWriteFontFileLoader *fileloader;
8961 struct testowner_object ownerobject;
8962 const void *key, *data, *frag_start;
8963 UINT64 file_size, size, writetime;
8964 IDWriteFontFile *file, *file2;
8965 IDWriteFontFace *fontface;
8966 void *context, *context2;
8967 IDWriteFactory5 *factory;
8968 UINT32 count, key_size;
8969 DWORD ref_key;
8970 HRESULT hr;
8971 ULONG ref;
8973 factory = create_factory_iid(&IID_IDWriteFactory5);
8974 if (!factory) {
8975 win_skip("CreateInMemoryFontFileLoader() is not supported\n");
8976 return;
8979 EXPECT_REF(factory, 1);
8980 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
8981 ok(hr == S_OK, "got %#lx\n", hr);
8982 EXPECT_REF(factory, 1);
8984 testowner_init(&ownerobject);
8985 fontface = create_fontface((IDWriteFactory *)factory);
8987 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader2);
8988 ok(hr == S_OK, "got %#lx\n", hr);
8989 ok(loader != loader2, "unexpected pointer\n");
8990 IDWriteInMemoryFontFileLoader_Release(loader2);
8992 inmemory = loader;
8994 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
8995 ok(!count, "Unexpected file count %u.\n", count);
8997 /* Use whole font blob to construct in-memory file. */
8998 count = 1;
8999 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
9000 ok(hr == S_OK, "got %#lx\n", hr);
9002 hr = IDWriteFontFile_GetLoader(file, &fileloader);
9003 ok(hr == S_OK, "got %#lx\n", hr);
9005 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
9006 ok(hr == S_OK, "got %#lx\n", hr);
9008 hr = IDWriteFontFileLoader_CreateStreamFromKey(fileloader, key, key_size, &stream);
9009 ok(hr == S_OK, "got %#lx\n", hr);
9010 IDWriteFontFileLoader_Release(fileloader);
9011 IDWriteFontFile_Release(file);
9013 hr = IDWriteFontFileStream_GetFileSize(stream, &file_size);
9014 ok(hr == S_OK, "got %#lx\n", hr);
9016 hr = IDWriteFontFileStream_ReadFileFragment(stream, &data, 0, file_size, &context);
9017 ok(hr == S_OK, "got %#lx\n", hr);
9019 /* Not registered yet. */
9020 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9021 file_size, NULL, &file);
9022 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
9024 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9025 ok(count == 1, "Unexpected file count %u.\n", count);
9027 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9028 ok(hr == S_OK, "got %#lx\n", hr);
9029 EXPECT_REF(inmemory, 2);
9031 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
9032 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9033 file_size, &ownerobject.IUnknown_iface, &file);
9034 ok(hr == S_OK, "got %#lx\n", hr);
9035 EXPECT_REF(&ownerobject.IUnknown_iface, 2);
9036 EXPECT_REF(inmemory, 3);
9038 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9039 ok(count == 2, "Unexpected file count %u.\n", count);
9041 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9042 file_size, &ownerobject.IUnknown_iface, &file2);
9043 ok(hr == S_OK, "got %#lx\n", hr);
9044 ok(file2 != file, "got unexpected file\n");
9045 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9046 EXPECT_REF(inmemory, 4);
9048 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9049 ok(count == 3, "Unexpected file count %u.\n", count);
9051 /* Check in-memory reference key format. */
9052 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
9053 ok(hr == S_OK, "got %#lx\n", hr);
9055 ok(key && *(DWORD*)key == 1, "got wrong ref key\n");
9056 ok(key_size == 4, "ref key size %u\n", key_size);
9058 hr = IDWriteFontFile_GetReferenceKey(file2, &key, &key_size);
9059 ok(hr == S_OK, "got %#lx\n", hr);
9061 ok(key && *(DWORD*)key == 2, "got wrong ref key\n");
9062 ok(key_size == 4, "ref key size %u\n", key_size);
9064 EXPECT_REF(inmemory, 4);
9065 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream2);
9066 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9067 EXPECT_REF(stream2, 1);
9068 EXPECT_REF(inmemory, 4);
9070 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream3);
9071 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9073 ok(stream2 != stream3, "Unexpected stream.\n");
9075 IDWriteFontFileStream_Release(stream2);
9076 IDWriteFontFileStream_Release(stream3);
9078 /* Release file at index 1, create new one to see if index is reused. */
9079 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9080 ref = IDWriteFontFile_Release(file);
9081 ok(ref == 0, "File object not released, %lu.\n", ref);
9082 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9084 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9085 ok(count == 3, "Unexpected file count %u.\n", count);
9087 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9088 ref = IDWriteFontFile_Release(file2);
9089 ok(ref == 0, "File object not released, %lu.\n", ref);
9090 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9092 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9093 ok(count == 3, "Unexpected file count %u.\n", count);
9095 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9096 ok(hr == S_OK, "got %#lx\n", hr);
9097 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9099 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
9100 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
9101 ok(ref == 0, "loader not released, %lu.\n", ref);
9102 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
9104 /* Test reference key for first added file. */
9105 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
9106 ok(hr == S_OK, "Failed to create loader, hr %#lx.\n", hr);
9108 inmemory = loader;
9110 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9111 ok(hr == S_OK, "Failed to register loader, hr %#lx.\n", hr);
9113 ref_key = 0;
9114 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
9115 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9117 /* With owner object. */
9118 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9119 file_size, &ownerobject.IUnknown_iface, &file);
9120 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#lx.\n", hr);
9122 ref_key = 0;
9123 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
9124 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9126 context2 = (void *)0xdeadbeef;
9127 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
9128 ok(hr == S_OK, "Failed to read a fragment, hr %#lx.\n", hr);
9129 ok(context2 == NULL, "Unexpected context %p.\n", context2);
9130 ok(frag_start == data, "Unexpected fragment pointer %p.\n", frag_start);
9132 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
9133 ok(hr == S_OK, "Failed to get file size, hr %#lx.\n", hr);
9134 ok(size == file_size, "Unexpected file size.\n");
9136 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
9138 writetime = 1;
9139 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
9140 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
9141 ok(writetime == 0, "Unexpected writetime.\n");
9143 IDWriteFontFileStream_Release(stream2);
9145 /* Without owner object. */
9146 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9147 file_size, NULL, &file2);
9148 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#lx.\n", hr);
9150 ref_key = 1;
9151 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
9152 ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
9154 context2 = (void *)0xdeadbeef;
9155 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
9156 ok(hr == S_OK, "Failed to read a fragment, hr %#lx.\n", hr);
9157 ok(context2 == NULL, "Unexpected context %p.\n", context2);
9158 ok(frag_start != data, "Unexpected fragment pointer %p.\n", frag_start);
9160 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
9161 ok(hr == S_OK, "Failed to get file size, hr %#lx.\n", hr);
9162 ok(size == file_size, "Unexpected file size.\n");
9164 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
9166 writetime = 1;
9167 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
9168 ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
9169 ok(writetime == 0, "Unexpected writetime.\n");
9171 IDWriteFontFileStream_Release(stream2);
9172 IDWriteFontFile_Release(file2);
9174 /* Key size validation. */
9175 ref_key = 0;
9176 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, NULL, sizeof(ref_key) - 1, &stream2);
9177 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9179 ref_key = 0;
9180 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) - 1, &stream2);
9181 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9183 ref_key = 0;
9184 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) + 1, &stream2);
9185 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9187 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9188 ok(count == 2, "Unexpected file count %u.\n", count);
9190 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
9191 ok(hr == S_OK, "Failed to get reference key, hr %#lx.\n", hr);
9193 ok(key && *(DWORD*)key == 0, "Unexpected reference key.\n");
9194 ok(key_size == 4, "Unexpected key size %u.\n", key_size);
9196 IDWriteFontFile_Release(file);
9198 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9199 ok(count == 2, "Unexpected file count %u.\n", count);
9201 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9202 ok(hr == S_OK, "Failed to unregister loader, hr %#lx.\n", hr);
9204 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
9205 IDWriteFontFileStream_Release(stream);
9206 IDWriteFontFace_Release(fontface);
9208 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
9209 ok(ref == 0, "loader not released, %lu.\n", ref);
9211 ref = IDWriteFactory5_Release(factory);
9212 ok(ref == 0, "factory not released, %lu\n", ref);
9215 static BOOL face_has_table(IDWriteFontFace4 *fontface, UINT32 tag)
9217 BOOL exists = FALSE;
9218 const void *data;
9219 void *context;
9220 UINT32 size;
9221 HRESULT hr;
9223 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
9224 ok(hr == S_OK, "TryGetFontTable() failed, %#lx\n", hr);
9225 if (exists)
9226 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9228 return exists;
9231 static DWORD get_sbix_formats(IDWriteFontFace4 *fontface)
9233 UINT32 size, s, num_strikes;
9234 const sbix_header *header;
9235 UINT16 g, num_glyphs;
9236 BOOL exists = FALSE;
9237 const maxp *maxp;
9238 const void *data;
9239 DWORD ret = 0;
9240 void *context;
9241 HRESULT hr;
9243 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
9244 ok(hr == S_OK, "TryGetFontTable() failed, %#lx\n", hr);
9245 ok(exists, "Expected maxp table\n");
9247 if (!exists)
9248 return 0;
9250 maxp = data;
9251 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
9253 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists);
9254 ok(hr == S_OK, "TryGetFontTable() failed, %#lx\n", hr);
9255 ok(exists, "Expected sbix table\n");
9257 header = data;
9258 num_strikes = GET_BE_DWORD(header->numStrikes);
9260 for (s = 0; s < num_strikes; s++) {
9261 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
9263 for (g = 0; g < num_glyphs; g++) {
9264 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
9265 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
9266 sbix_glyph_data *glyph_data;
9267 DWORD format;
9269 if (offset == offset_next)
9270 continue;
9272 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
9273 switch (format = glyph_data->graphicType)
9275 case MS_PNG__TAG:
9276 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
9277 break;
9278 case MS_JPG__TAG:
9279 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
9280 break;
9281 case MS_TIFF_TAG:
9282 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
9283 break;
9284 default:
9285 ok(0, "unexpected format, %#lx\n", GET_BE_DWORD(format));
9290 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9292 return ret;
9295 static DWORD get_cblc_formats(IDWriteFontFace4 *fontface)
9297 CBLCBitmapSizeTable *sizes;
9298 UINT32 num_sizes, size, s;
9299 BOOL exists = FALSE;
9300 CBLCHeader *header;
9301 DWORD ret = 0;
9302 void *context;
9303 HRESULT hr;
9305 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&header, &size, &context, &exists);
9306 ok(hr == S_OK, "TryGetFontTable() failed, %#lx\n", hr);
9307 ok(exists, "Expected CBLC table\n");
9309 if (!exists)
9310 return 0;
9312 num_sizes = GET_BE_DWORD(header->numSizes);
9313 sizes = (CBLCBitmapSizeTable *)(header + 1);
9315 for (s = 0; s < num_sizes; s++) {
9316 BYTE bpp = sizes[s].bitDepth;
9318 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
9319 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
9320 else if (bpp == 32)
9321 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
9324 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9326 return ret;
9329 static DWORD get_face_glyph_image_formats(IDWriteFontFace4 *fontface)
9331 DWORD ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
9333 if (face_has_table(fontface, MS_GLYF_TAG))
9334 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
9336 if (face_has_table(fontface, MS_CFF__TAG) ||
9337 face_has_table(fontface, MS_CFF2_TAG))
9338 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
9340 if (face_has_table(fontface, MS_COLR_TAG))
9341 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
9343 if (face_has_table(fontface, MS_SVG__TAG))
9344 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
9346 if (face_has_table(fontface, MS_SBIX_TAG))
9347 ret |= get_sbix_formats(fontface);
9349 if (face_has_table(fontface, MS_CBLC_TAG))
9350 ret |= get_cblc_formats(fontface);
9352 return ret;
9355 static void test_GetGlyphImageFormats(void)
9357 IDWriteFontCollection *syscollection;
9358 IDWriteFactory *factory;
9359 UINT32 i, count;
9360 HRESULT hr;
9361 ULONG ref;
9362 IDWriteFontFace *fontface;
9363 IDWriteFontFace4 *fontface4;
9365 factory = create_factory();
9367 fontface = create_fontface(factory);
9368 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
9369 IDWriteFontFace_Release(fontface);
9370 if (FAILED(hr)) {
9371 win_skip("GetGlyphImageFormats() is not supported\n");
9372 IDWriteFactory_Release(factory);
9373 return;
9375 IDWriteFontFace4_Release(fontface4);
9377 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
9378 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9379 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
9381 for (i = 0; i < count; i++) {
9382 WCHAR familynameW[256], facenameW[128];
9383 IDWriteLocalizedStrings *names;
9384 IDWriteFontFamily *family;
9385 UINT32 j, fontcount;
9386 IDWriteFont *font;
9388 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
9389 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9391 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
9392 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9394 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
9395 IDWriteLocalizedStrings_Release(names);
9397 fontcount = IDWriteFontFamily_GetFontCount(family);
9398 for (j = 0; j < fontcount; j++) {
9399 DWORD formats, expected_formats;
9401 hr = IDWriteFontFamily_GetFont(family, j, &font);
9402 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9404 hr = IDWriteFont_CreateFontFace(font, &fontface);
9405 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9407 hr = IDWriteFont_GetFaceNames(font, &names);
9408 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
9410 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
9412 IDWriteLocalizedStrings_Release(names);
9414 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
9416 /* Mask describes font as a whole. */
9417 formats = IDWriteFontFace4_GetGlyphImageFormats(fontface4);
9418 expected_formats = get_face_glyph_image_formats(fontface4);
9419 ok(formats == expected_formats, "%s - %s, expected formats %#lx, got formats %#lx.\n",
9420 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), expected_formats, formats);
9422 IDWriteFontFace4_Release(fontface4);
9423 IDWriteFontFace_Release(fontface);
9424 IDWriteFont_Release(font);
9427 IDWriteFontFamily_Release(family);
9430 IDWriteFontCollection_Release(syscollection);
9431 ref = IDWriteFactory_Release(factory);
9432 ok(ref == 0, "factory not released, %lu\n", ref);
9435 static void test_CreateCustomRenderingParams(void)
9437 static const struct custom_params_test
9439 FLOAT gamma;
9440 FLOAT contrast;
9441 FLOAT cleartype_level;
9442 DWRITE_PIXEL_GEOMETRY geometry;
9443 DWRITE_RENDERING_MODE rendering_mode;
9444 HRESULT hr;
9445 } params_tests[] =
9447 { 0.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9448 { 0.0f, 0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9449 { 0.0f, 0.0f, 0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9450 { -0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9451 { 0.1f, -0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9452 { 0.1f, 0.0f, -0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9453 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
9454 { 0.01f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
9455 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR + 1, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9456 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_OUTLINE + 1, E_INVALIDARG },
9457 { 0.1f, 0.0f, 2.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_NATURAL },
9459 IDWriteFactory *factory;
9460 unsigned int i;
9461 HRESULT hr;
9462 ULONG ref;
9464 factory = create_factory();
9466 for (i = 0; i < ARRAY_SIZE(params_tests); i++) {
9467 IDWriteRenderingParams *params;
9469 winetest_push_context("%u", i);
9471 params = (void *)0xdeadbeef;
9472 hr = IDWriteFactory_CreateCustomRenderingParams(factory, params_tests[i].gamma, params_tests[i].contrast,
9473 params_tests[i].cleartype_level, params_tests[i].geometry, params_tests[i].rendering_mode, &params);
9474 ok(hr == params_tests[i].hr, "unexpected hr %#lx, expected %#lx.\n", hr, params_tests[i].hr);
9476 if (hr == S_OK) {
9477 ok(params_tests[i].gamma == IDWriteRenderingParams_GetGamma(params), "unexpected gamma %f, expected %f.\n",
9478 IDWriteRenderingParams_GetGamma(params), params_tests[i].gamma);
9479 ok(params_tests[i].contrast == IDWriteRenderingParams_GetEnhancedContrast(params),
9480 "unexpected contrast %f, expected %f.\n",
9481 IDWriteRenderingParams_GetEnhancedContrast(params), params_tests[i].contrast);
9482 ok(params_tests[i].cleartype_level == IDWriteRenderingParams_GetClearTypeLevel(params),
9483 "unexpected ClearType level %f, expected %f.\n",
9484 IDWriteRenderingParams_GetClearTypeLevel(params), params_tests[i].cleartype_level);
9485 ok(params_tests[i].geometry == IDWriteRenderingParams_GetPixelGeometry(params),
9486 "unexpected pixel geometry %u, expected %u.\n", IDWriteRenderingParams_GetPixelGeometry(params),
9487 params_tests[i].geometry);
9488 ok(params_tests[i].rendering_mode == IDWriteRenderingParams_GetRenderingMode(params),
9489 "unexpected rendering mode %u, expected %u.\n", IDWriteRenderingParams_GetRenderingMode(params),
9490 params_tests[i].rendering_mode);
9491 IDWriteRenderingParams_Release(params);
9493 else
9494 ok(params == NULL, "%u: expected NULL interface pointer on failure.\n", i);
9496 winetest_pop_context();
9499 ref = IDWriteFactory_Release(factory);
9500 ok(ref == 0, "factory not released, %lu\n", ref);
9503 static void test_localfontfileloader(void)
9505 IDWriteFontFileLoader *loader, *loader2;
9506 IDWriteFactory *factory, *factory2;
9507 IDWriteFontFile *file, *file2;
9508 WCHAR *path;
9509 HRESULT hr;
9510 ULONG ref;
9512 factory = create_factory();
9513 factory2 = create_factory();
9515 path = create_testfontfile(test_fontfile);
9517 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
9518 ok(hr == S_OK, "Failed to create file reference, hr %#lx.\n", hr);
9520 hr = IDWriteFactory_CreateFontFileReference(factory2, path, NULL, &file2);
9521 ok(hr == S_OK, "Failed to create file reference, hr %#lx.\n", hr);
9522 ok(file != file2, "Unexpected file instance.\n");
9524 hr = IDWriteFontFile_GetLoader(file, &loader);
9525 ok(hr == S_OK, "Failed to get loader, hr %#lx.\n", hr);
9527 hr = IDWriteFontFile_GetLoader(file2, &loader2);
9528 ok(hr == S_OK, "Failed to get loader, hr %#lx.\n", hr);
9529 ok(loader == loader2, "Unexpected loader instance\n");
9531 IDWriteFontFile_Release(file);
9532 IDWriteFontFile_Release(file2);
9533 IDWriteFontFileLoader_Release(loader);
9534 IDWriteFontFileLoader_Release(loader2);
9535 ref = IDWriteFactory_Release(factory);
9536 ok(ref == 0, "factory not released, %lu\n", ref);
9537 ref = IDWriteFactory_Release(factory2);
9538 ok(ref == 0, "factory not released, %lu\n", ref);
9539 DELETE_FONTFILE(path);
9542 static void test_AnalyzeContainerType(void)
9544 struct WOFFHeader2 woff2_header;
9545 struct WOFFHeader woff_header;
9546 DWRITE_CONTAINER_TYPE type;
9547 IDWriteFactory5 *factory;
9549 factory = create_factory_iid(&IID_IDWriteFactory5);
9550 if (!factory) {
9551 win_skip("AnalyzeContainerType() is not supported.\n");
9552 return;
9555 type = IDWriteFactory5_AnalyzeContainerType(factory, NULL, 0);
9556 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9558 type = IDWriteFactory5_AnalyzeContainerType(factory, (void const *)0xdeadbeef, 0);
9559 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9561 memset(&woff_header, 0xff, sizeof(woff_header));
9562 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9563 woff_header.length = 0;
9564 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header));
9565 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
9567 memset(&woff_header, 0xff, sizeof(woff_header));
9568 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9569 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature));
9570 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
9572 memset(&woff_header, 0xff, sizeof(woff_header));
9573 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9574 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature) - 1);
9575 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9577 memset(&woff2_header, 0xff, sizeof(woff2_header));
9578 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9579 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header));
9580 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
9582 memset(&woff2_header, 0xff, sizeof(woff2_header));
9583 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9584 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature));
9585 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
9587 memset(&woff2_header, 0xff, sizeof(woff2_header));
9588 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9589 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature) - 1);
9590 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9592 IDWriteFactory5_Release(factory);
9595 static void test_fontsetbuilder(void)
9597 IDWriteFontFaceReference *ref, *ref2, *ref3;
9598 IDWriteFontCollection1 *collection;
9599 IDWriteFontFaceReference1 *ref1;
9600 IDWriteFontSetBuilder1 *builder1;
9601 IDWriteFontSetBuilder *builder;
9602 DWRITE_FONT_AXIS_VALUE axis_values[4];
9603 IDWriteFactory3 *factory;
9604 UINT32 count, i, refcount;
9605 IDWriteFontSet *fontset;
9606 IDWriteFontFile *file;
9607 WCHAR *path;
9608 HRESULT hr;
9610 factory = create_factory_iid(&IID_IDWriteFactory3);
9611 if (!factory)
9613 win_skip("IDWriteFontSetBuilder is not supported.\n");
9614 return;
9617 EXPECT_REF(factory, 1);
9618 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
9619 ok(hr == S_OK, "Failed to create font set builder, hr %#lx.\n", hr);
9620 EXPECT_REF(factory, 2);
9622 if (SUCCEEDED(hr = IDWriteFontSetBuilder_QueryInterface(builder, &IID_IDWriteFontSetBuilder1, (void **)&builder1)))
9624 path = create_testfontfile(test_fontfile);
9626 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
9627 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9629 hr = IDWriteFontSetBuilder1_AddFontFile(builder1, file);
9630 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9632 hr = IDWriteFontSetBuilder1_CreateFontSet(builder1, &fontset);
9633 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9634 hr = IDWriteFactory3_CreateFontCollectionFromFontSet(factory, fontset, &collection);
9635 todo_wine
9636 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9637 if (SUCCEEDED(hr))
9639 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9640 ok(count == 1, "Unexpected family count %u.\n", count);
9641 IDWriteFontCollection1_Release(collection);
9643 IDWriteFontSet_Release(fontset);
9645 hr = IDWriteFontSetBuilder1_AddFontFile(builder1, file);
9646 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9648 hr = IDWriteFontSetBuilder1_CreateFontSet(builder1, &fontset);
9649 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9651 hr = IDWriteFactory3_CreateFontCollectionFromFontSet(factory, fontset, &collection);
9652 todo_wine
9653 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9654 if (SUCCEEDED(hr))
9656 check_familymodel(collection, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE);
9657 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9658 ok(count == 1, "Unexpected family count %u.\n", count);
9659 IDWriteFontCollection1_Release(collection);
9662 /* No attempt to eliminate duplicates. */
9663 count = IDWriteFontSet_GetFontCount(fontset);
9664 ok(count == 2, "Unexpected font count %u.\n", count);
9666 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref);
9667 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9669 hr = IDWriteFontFaceReference_QueryInterface(ref, &IID_IDWriteFontFaceReference1, (void **)&ref1);
9670 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9672 count = IDWriteFontFaceReference1_GetFontAxisValueCount(ref1);
9673 todo_wine
9674 ok(count == 4, "Unexpected axis count %u.\n", count);
9676 if (count == 4)
9678 hr = IDWriteFontFaceReference1_GetFontAxisValues(ref1, axis_values, ARRAY_SIZE(axis_values));
9679 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
9681 ok(axis_values[0].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT, "Unexpected tag[0] %s.\n",
9682 wine_dbgstr_an((char *)&axis_values[0].axisTag, 4));
9683 ok(axis_values[0].value == 500.0f, "Unexpected value[0] %f.\n", axis_values[0].value);
9684 ok(axis_values[1].axisTag == DWRITE_FONT_AXIS_TAG_WIDTH, "Unexpected tag[1] %s.\n",
9685 wine_dbgstr_an((char *)&axis_values[1].axisTag, 4));
9686 ok(axis_values[1].value == 100.0f, "Unexpected value[1] %f.\n", axis_values[1].value);
9687 ok(axis_values[2].axisTag == DWRITE_FONT_AXIS_TAG_ITALIC, "Unexpected tag[2] %s.\n",
9688 wine_dbgstr_an((char *)&axis_values[2].axisTag, 4));
9689 ok(axis_values[2].value == 0.0f, "Unexpected value[2] %f.\n", axis_values[2].value);
9690 ok(axis_values[3].axisTag == DWRITE_FONT_AXIS_TAG_SLANT, "Unexpected tag[3] %s.\n",
9691 wine_dbgstr_an((char *)&axis_values[3].axisTag, 4));
9692 ok(axis_values[3].value == 0.0f, "Unexpected value[3] %f.\n", axis_values[3].value);
9695 IDWriteFontFaceReference1_Release(ref1);
9697 IDWriteFontFaceReference_Release(ref);
9699 IDWriteFontSet_Release(fontset);
9701 IDWriteFontFile_Release(file);
9702 IDWriteFontSetBuilder1_Release(builder1);
9704 else
9705 win_skip("IDWriteFontSetBuilder1 is not available.\n");
9706 IDWriteFontSetBuilder_Release(builder);
9708 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
9709 ok(hr == S_OK, "Failed to get system collection, hr %#lx.\n", hr);
9710 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9712 for (i = 0; i < count; i++) {
9713 IDWriteFontFamily1 *family;
9714 UINT32 j, fontcount;
9715 IDWriteFont3 *font;
9717 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
9718 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
9720 fontcount = IDWriteFontFamily1_GetFontCount(family);
9721 for (j = 0; j < fontcount; ++j)
9723 IDWriteFontSet *fontset;
9724 UINT32 setcount, id;
9726 hr = IDWriteFontFamily1_GetFont(family, j, &font);
9727 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
9729 /* Create a set with a single font reference, test set properties. */
9730 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
9731 ok(hr == S_OK, "Failed to create font set builder, hr %#lx.\n", hr);
9733 hr = IDWriteFont3_GetFontFaceReference(font, &ref);
9734 ok(hr == S_OK, "Failed to get fontface reference, hr %#lx.\n", hr);
9736 EXPECT_REF(ref, 1);
9737 hr = IDWriteFontSetBuilder_AddFontFaceReference(builder, ref);
9738 ok(hr == S_OK, "Failed to add fontface reference, hr %#lx.\n", hr);
9739 EXPECT_REF(ref, 1);
9741 hr = IDWriteFontSetBuilder_CreateFontSet(builder, &fontset);
9742 ok(hr == S_OK, "Failed to create a font set, hr %#lx.\n", hr);
9744 setcount = IDWriteFontSet_GetFontCount(fontset);
9745 ok(setcount == 1, "Unexpected font count %u.\n", setcount);
9747 ref2 = (void *)0xdeadbeef;
9748 hr = IDWriteFontSet_GetFontFaceReference(fontset, setcount, &ref2);
9749 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
9750 ok(!ref2, "Unexpected pointer.\n");
9752 ref2 = NULL;
9753 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref2);
9754 ok(hr == S_OK, "Failed to get font face reference, hr %#lx.\n", hr);
9755 ok(ref2 != ref, "Unexpected reference.\n");
9757 ref3 = NULL;
9758 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref3);
9759 ok(hr == S_OK, "Failed to get font face reference, hr %#lx.\n", hr);
9760 ok(ref2 != ref3, "Unexpected reference.\n");
9762 IDWriteFontFaceReference_Release(ref3);
9763 IDWriteFontFaceReference_Release(ref2);
9765 for (id = DWRITE_FONT_PROPERTY_ID_FAMILY_NAME; id < DWRITE_FONT_PROPERTY_ID_TOTAL; ++id)
9767 IDWriteLocalizedStrings *values;
9768 WCHAR buffW[255], buff2W[255];
9769 UINT32 c, ivalue = 0;
9770 BOOL exists = FALSE;
9772 hr = IDWriteFontSet_GetPropertyValues(fontset, 0, id, &exists, &values);
9773 ok(hr == S_OK, "Failed to get property value, hr %#lx.\n", hr);
9775 if (id == DWRITE_FONT_PROPERTY_ID_WEIGHT || id == DWRITE_FONT_PROPERTY_ID_STRETCH
9776 || id == DWRITE_FONT_PROPERTY_ID_STYLE)
9778 todo_wine
9779 ok(exists, "Property %u expected to exist.\n", id);
9782 if (!exists)
9783 continue;
9785 switch (id)
9787 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
9788 ivalue = IDWriteFont3_GetWeight(font);
9789 break;
9790 case DWRITE_FONT_PROPERTY_ID_STRETCH:
9791 ivalue = IDWriteFont3_GetStretch(font);
9792 break;
9793 case DWRITE_FONT_PROPERTY_ID_STYLE:
9794 ivalue = IDWriteFont3_GetStyle(font);
9795 break;
9796 default:
9800 switch (id)
9802 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
9803 case DWRITE_FONT_PROPERTY_ID_STRETCH:
9804 case DWRITE_FONT_PROPERTY_ID_STYLE:
9805 c = IDWriteLocalizedStrings_GetCount(values);
9806 ok(c == 1, "Unexpected string count %u.\n", c);
9808 buffW[0] = 'a';
9809 hr = IDWriteLocalizedStrings_GetLocaleName(values, 0, buffW, ARRAY_SIZE(buffW));
9810 ok(hr == S_OK, "Failed to get locale name, hr %#lx.\n", hr);
9811 ok(!*buffW, "Unexpected locale %s.\n", wine_dbgstr_w(buffW));
9813 buff2W[0] = 0;
9814 hr = IDWriteLocalizedStrings_GetString(values, 0, buff2W, ARRAY_SIZE(buff2W));
9815 ok(hr == S_OK, "Failed to get property string, hr %#lx.\n", hr);
9817 wsprintfW(buffW, L"%u", ivalue);
9818 ok(!lstrcmpW(buffW, buff2W), "Unexpected property value %s, expected %s.\n", wine_dbgstr_w(buff2W),
9819 wine_dbgstr_w(buffW));
9820 break;
9821 default:
9825 IDWriteLocalizedStrings_Release(values);
9828 IDWriteFontSet_Release(fontset);
9829 IDWriteFontFaceReference_Release(ref);
9830 IDWriteFontSetBuilder_Release(builder);
9832 IDWriteFont3_Release(font);
9835 IDWriteFontFamily1_Release(family);
9838 IDWriteFontCollection1_Release(collection);
9840 refcount = IDWriteFactory3_Release(factory);
9841 ok(!refcount, "Factory not released, %u.\n", refcount);
9844 static void test_font_resource(void)
9846 IDWriteFontFaceReference1 *reference, *reference2;
9847 IDWriteFontResource *resource, *resource2;
9848 IDWriteFontFile *fontfile, *fontfile2;
9849 DWRITE_FONT_AXIS_VALUE axis_values[2];
9850 IDWriteFontFace5 *fontface5;
9851 IDWriteFontFace *fontface;
9852 IDWriteFactory6 *factory;
9853 UINT32 count, index;
9854 HRESULT hr;
9855 ULONG ref;
9856 BOOL ret;
9858 if (!(factory = create_factory_iid(&IID_IDWriteFactory6)))
9860 win_skip("IDWriteFactory6 is not supported.\n");
9861 return;
9864 fontface = create_fontface((IDWriteFactory *)factory);
9866 count = 1;
9867 hr = IDWriteFontFace_GetFiles(fontface, &count, &fontfile);
9868 ok(hr == S_OK, "Failed to get file object, hr %#lx.\n", hr);
9870 hr = IDWriteFactory6_CreateFontResource(factory, fontfile, 0, &resource);
9871 ok(hr == S_OK, "Failed to create font resource, hr %#lx.\n", hr);
9873 hr = IDWriteFactory6_CreateFontResource(factory, fontfile, 0, &resource2);
9874 ok(hr == S_OK, "Failed to create font resource, hr %#lx.\n", hr);
9875 ok(resource != resource2, "Unexpected instance.\n");
9876 IDWriteFontResource_Release(resource2);
9878 hr = IDWriteFontResource_GetFontFile(resource, &fontfile2);
9879 ok(hr == S_OK, "Failed to get font file, hr %#lx.\n", hr);
9880 ok(fontfile2 == fontfile, "Unexpected file instance.\n");
9881 IDWriteFontFile_Release(fontfile2);
9883 index = IDWriteFontResource_GetFontFaceIndex(resource);
9884 ok(!index, "Unexpected index %u.\n", index);
9886 /* Specify axis value, font has no variations. */
9887 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9888 axis_values[0].value = 400.0f;
9889 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 1, &reference);
9890 ok(hr == S_OK, "Failed to create reference object, hr %#lx.\n", hr);
9892 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9893 ok(count == 1, "Unexpected axis value count.\n");
9895 IDWriteFontFaceReference1_Release(reference);
9897 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 1,
9898 &reference);
9899 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9900 ok(count == 1, "Unexpected axis value count.\n");
9901 IDWriteFontFaceReference1_Release(reference);
9903 EXPECT_REF(resource, 1);
9904 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0, &reference);
9905 ok(hr == S_OK, "Failed to create reference object, hr %#lx.\n", hr);
9906 EXPECT_REF(resource, 1);
9908 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0, &reference2);
9909 ok(hr == S_OK, "Failed to create reference object, hr %#lx.\n", hr);
9910 ok(reference != reference2, "Unexpected reference instance.\n");
9911 IDWriteFontFaceReference1_Release(reference2);
9912 IDWriteFontFaceReference1_Release(reference);
9914 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5);
9915 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
9917 hr = IDWriteFontFace5_GetFontResource(fontface5, &resource2);
9918 ok(hr == S_OK, "Failed to get font resource, hr %#lx.\n", hr);
9919 ok(resource != resource2, "Unexpected resource instance.\n");
9920 IDWriteFontResource_Release(resource);
9922 hr = IDWriteFontFace5_GetFontResource(fontface5, &resource);
9923 ok(hr == S_OK, "Failed to get font resource, hr %#lx.\n", hr);
9924 ok(resource != resource2, "Unexpected resource instance.\n");
9925 EXPECT_REF(resource, 1);
9926 IDWriteFontResource_Release(resource);
9927 IDWriteFontResource_Release(resource2);
9929 IDWriteFontFace5_Release(fontface5);
9931 /* Reference equality regarding set axis values. */
9932 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9933 axis_values[0].value = 400.0f;
9934 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9935 axis_values[1].value = 1.0f;
9936 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9937 &reference);
9938 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9939 ok(count == 2, "Unexpected axis value count.\n");
9941 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0,
9942 &reference2);
9943 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9944 ok(!count, "Unexpected axis value count.\n");
9946 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9947 ok(!ret, "Unexpected result.\n");
9948 IDWriteFontFaceReference1_Release(reference2);
9950 /* Different values order. */
9951 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9952 axis_values[0].value = 1.0f;
9953 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9954 axis_values[1].value = 400.0f;
9955 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9956 &reference2);
9957 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9958 ok(count == 2, "Unexpected axis value count.\n");
9960 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9961 ok(!ret, "Unexpected result.\n");
9962 IDWriteFontFaceReference1_Release(reference2);
9964 /* Different axis values. */
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 = 401.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 memset(axis_values, 0, sizeof(axis_values));
9979 hr = IDWriteFontFaceReference1_GetFontAxisValues(reference, axis_values, 1);
9980 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
9981 ok(!axis_values[0].axisTag, "Unexpected axis tag.\n");
9983 memset(axis_values, 0, sizeof(axis_values));
9984 hr = IDWriteFontFaceReference1_GetFontAxisValues(reference, axis_values, 2);
9985 ok(hr == S_OK, "Failed to get axis values, hr %#lx.\n", hr);
9986 ok(axis_values[0].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT, "Unexpected axis tag.\n");
9988 hr = IDWriteFontFaceReference1_CreateFontFace(reference, &fontface5);
9989 ok(hr == S_OK, "Failed to create a font face, hr %#lx.\n", hr);
9990 IDWriteFontFace5_Release(fontface5);
9992 IDWriteFontFaceReference1_Release(reference);
9994 IDWriteFontFile_Release(fontfile);
9996 IDWriteFontFace_Release(fontface);
9997 ref = IDWriteFactory6_Release(factory);
9998 ok(ref == 0, "Factory wasn't released, %lu.\n", ref);
10001 static BOOL get_expected_is_color(IDWriteFontFace2 *fontface)
10003 void *context;
10004 UINT32 size;
10005 BOOL exists;
10006 void *data;
10007 HRESULT hr;
10009 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_CPAL_TAG, (const void **)&data, &size, &context, &exists);
10010 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10011 if (context)
10012 IDWriteFontFace2_ReleaseFontTable(fontface, context);
10014 if (exists)
10016 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_COLR_TAG, (const void **)&data, &size, &context, &exists);
10017 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10018 if (context)
10019 IDWriteFontFace2_ReleaseFontTable(fontface, context);
10022 return exists;
10025 static void test_IsColorFont(void)
10027 IDWriteFontCollection *collection;
10028 IDWriteFactory2 *factory;
10029 UINT32 count, i;
10030 ULONG refcount;
10031 HRESULT hr;
10033 factory = create_factory_iid(&IID_IDWriteFactory2);
10035 if (!factory)
10037 win_skip("IsColorFont() is not supported.\n");
10038 return;
10041 hr = IDWriteFactory2_GetSystemFontCollection(factory, &collection, FALSE);
10042 ok(hr == S_OK, "Failed to get font collection, hr %#lx.\n", hr);
10044 count = IDWriteFontCollection_GetFontFamilyCount(collection);
10045 for (i = 0; i < count; ++i)
10047 IDWriteLocalizedStrings *names;
10048 IDWriteFontFamily *family;
10049 UINT32 font_count, j;
10050 WCHAR nameW[256];
10052 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
10053 ok(hr == S_OK, "Failed to get family, hr %#lx.\n", hr);
10055 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
10056 ok(hr == S_OK, "Failed to get names, hr %#lx.\n", hr);
10057 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
10058 IDWriteLocalizedStrings_Release(names);
10060 font_count = IDWriteFontFamily_GetFontCount(family);
10062 for (j = 0; j < font_count; ++j)
10064 BOOL is_color_font, is_color_face, is_color_expected;
10065 IDWriteFontFace2 *fontface2;
10066 IDWriteFontFace *fontface;
10067 IDWriteFont2 *font2;
10068 IDWriteFont *font;
10070 hr = IDWriteFontFamily_GetFont(family, j, &font);
10071 ok(hr == S_OK, "Failed to get font, hr %#lx.\n", hr);
10073 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont2, (void **)&font2);
10074 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
10075 IDWriteFont_Release(font);
10077 hr = IDWriteFont2_CreateFontFace(font2, &fontface);
10078 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
10080 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void **)&fontface2);
10081 ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
10082 IDWriteFontFace_Release(fontface);
10084 is_color_font = IDWriteFont2_IsColorFont(font2);
10085 is_color_face = IDWriteFontFace2_IsColorFont(fontface2);
10086 ok(is_color_font == is_color_face, "Unexpected color flag.\n");
10088 is_color_expected = get_expected_is_color(fontface2);
10089 ok(is_color_expected == is_color_face, "Unexpected is_color flag %d for %s, font %d.\n",
10090 is_color_face, wine_dbgstr_w(nameW), j);
10092 IDWriteFontFace2_Release(fontface2);
10093 IDWriteFont2_Release(font2);
10096 IDWriteFontFamily_Release(family);
10099 IDWriteFontCollection_Release(collection);
10100 refcount = IDWriteFactory2_Release(factory);
10101 ok(refcount == 0, "Factory not released, refcount %lu.\n", refcount);
10104 static void test_GetVerticalGlyphVariants(void)
10106 UINT16 glyphs[1], glyph_variants[1];
10107 IDWriteFontFace1 *fontface1;
10108 IDWriteFontFace *fontface;
10109 IDWriteFactory *factory;
10110 unsigned int ch;
10111 ULONG refcount;
10112 HRESULT hr;
10113 BOOL ret;
10115 factory = create_factory();
10117 fontface = create_fontface(factory);
10118 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
10119 IDWriteFontFace_Release(fontface);
10120 if (FAILED(hr))
10122 win_skip("GetVerticalGlyphVariants() is not supported.\n");
10123 IDWriteFactory_Release(factory);
10124 return;
10127 ch = 'A';
10128 *glyphs = 0;
10129 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &ch, 1, glyphs);
10130 ok(hr == S_OK, "Failed to get glyph, hr %#lx.\n", hr);
10131 ok(!!*glyphs, "Unexpected glyph %u.\n", glyphs[0]);
10133 memset(glyph_variants, 0, sizeof(glyph_variants));
10134 hr = IDWriteFontFace1_GetVerticalGlyphVariants(fontface1, 1, glyphs, glyph_variants);
10135 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10136 ok(glyphs[0] == glyph_variants[0], "Unexpected glyph.\n");
10138 ret = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
10139 ok(!ret, "Unexpected flag.\n");
10141 IDWriteFontFace1_Release(fontface1);
10142 refcount = IDWriteFactory_Release(factory);
10143 ok(!refcount, "Factory not released, refcount %lu.\n", refcount);
10146 static HANDLE get_collection_expiration_event(IDWriteFontCollection *collection)
10148 IDWriteFontCollection3 *collection3;
10149 HANDLE event;
10150 HRESULT hr;
10152 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
10153 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10154 event = IDWriteFontCollection3_GetExpirationEvent(collection3);
10155 IDWriteFontCollection3_Release(collection3);
10157 return event;
10160 static void test_expiration_event(void)
10162 IDWriteFontCollection *collection, *collection2;
10163 IDWriteFontCollection3 *collection3;
10164 IDWriteFactory *factory, *factory2;
10165 unsigned int refcount;
10166 HANDLE event, event2;
10167 HRESULT hr;
10169 factory = create_factory();
10171 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
10172 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10174 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
10175 if (FAILED(hr))
10177 win_skip("Expiration events are not supported.\n");
10178 IDWriteFontCollection_Release(collection);
10179 IDWriteFactory_Release(factory);
10180 return;
10182 IDWriteFontCollection3_Release(collection3);
10184 event = get_collection_expiration_event(collection);
10185 todo_wine
10186 ok(!!event, "Unexpected event handle.\n");
10188 /* Compare handles with another isolated factory. */
10189 factory2 = create_factory();
10191 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection2, FALSE);
10192 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10193 event2 = get_collection_expiration_event(collection2);
10194 todo_wine {
10195 ok(!!event2, "Unexpected event handle.\n");
10196 ok(event != event2, "Unexpected event handle.\n");
10198 IDWriteFontCollection_Release(collection2);
10200 IDWriteFontCollection_Release(collection);
10202 refcount = IDWriteFactory_Release(factory2);
10203 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10204 refcount = IDWriteFactory_Release(factory);
10205 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10208 static void test_family_font_set(void)
10210 IDWriteFontCollection *collection;
10211 IDWriteFontFamily2 *family2;
10212 IDWriteFontFamily *family;
10213 IDWriteFactory *factory;
10214 unsigned int count, refcount;
10215 IDWriteFontSet1 *fontset, *fontset2;
10216 IDWriteLocalizedStrings *values;
10217 IDWriteFontResource *resource;
10218 WCHAR buffW[64];
10219 BOOL exists;
10220 HRESULT hr;
10222 factory = create_factory();
10224 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
10225 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10227 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
10228 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10230 if (SUCCEEDED(IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily2, (void **)&family2)))
10232 hr = IDWriteFontFamily2_GetFontSet(family2, &fontset);
10233 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10234 hr = IDWriteFontFamily2_GetFontSet(family2, &fontset2);
10235 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10236 ok(fontset != fontset2, "Unexpected fontset instance.\n");
10238 count = IDWriteFontSet1_GetFontCount(fontset);
10240 /* Invalid property id. */
10241 exists = TRUE;
10242 values = (void *)0xdeadbeef;
10243 hr = IDWriteFontSet1_GetPropertyValues(fontset, 0, 100, &exists, &values);
10244 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
10245 ok(!exists && !values, "Unexpected return value.\n");
10247 /* Invalid index. */
10248 exists = TRUE;
10249 values = (void *)0xdeadbeef;
10250 hr = IDWriteFontSet1_GetPropertyValues(fontset, count, DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, &exists, &values);
10251 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
10252 ok(!exists && !values, "Unexpected return value.\n");
10254 exists = TRUE;
10255 values = (void *)0xdeadbeef;
10256 hr = IDWriteFontSet1_GetPropertyValues(fontset, count, 100, &exists, &values);
10257 ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
10258 ok(!exists && !values, "Unexpected return value.\n");
10260 hr = IDWriteFontSet1_GetPropertyValues(fontset, 0, DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, &exists, &values);
10261 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10262 ok(exists == !!values, "Unexpected return value.\n");
10263 if (values)
10265 hr = IDWriteLocalizedStrings_GetString(values, 0, buffW, ARRAY_SIZE(buffW));
10266 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10267 IDWriteLocalizedStrings_Release(values);
10270 hr = IDWriteFontSet1_CreateFontResource(fontset, 100, &resource);
10271 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
10273 hr = IDWriteFontSet1_CreateFontResource(fontset, 0, &resource);
10274 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10275 IDWriteFontResource_Release(resource);
10277 IDWriteFontSet1_Release(fontset2);
10278 IDWriteFontSet1_Release(fontset);
10280 IDWriteFontFamily2_Release(family2);
10282 else
10283 win_skip("IDWriteFontFamily2 is not supported.\n");
10285 IDWriteFontFamily_Release(family);
10286 IDWriteFontCollection_Release(collection);
10288 refcount = IDWriteFactory_Release(factory);
10289 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10292 static void test_system_font_set(void)
10294 IDWriteFontSet *fontset, *filtered_set;
10295 IDWriteFontFaceReference *ref;
10296 IDWriteFontFace3 *fontface;
10297 IDWriteFactory3 *factory;
10298 DWRITE_FONT_PROPERTY p;
10299 unsigned int count;
10300 HRESULT hr;
10302 if (!(factory = create_factory_iid(&IID_IDWriteFactory3)))
10304 win_skip("System font set is not supported.\n");
10305 return;
10308 hr = IDWriteFactory3_GetSystemFontSet(factory, &fontset);
10309 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10311 count = IDWriteFontSet_GetFontCount(fontset);
10312 ok(!!count, "Unexpected font count %u.\n", count);
10314 p.propertyId = DWRITE_FONT_PROPERTY_ID_FULL_NAME;
10315 p.propertyValue = L"Tahoma";
10316 p.localeName = L"";
10317 hr = IDWriteFontSet_GetMatchingFonts(fontset, &p, 1, &filtered_set);
10318 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10319 count = IDWriteFontSet_GetFontCount(filtered_set);
10320 ok(!!count, "Unexpected font count %u.\n", count);
10322 hr = IDWriteFontSet_GetFontFaceReference(filtered_set, 0, &ref);
10323 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10325 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
10326 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10328 IDWriteFontFace3_Release(fontface);
10329 IDWriteFontFaceReference_Release(ref);
10331 IDWriteFontSet_Release(filtered_set);
10333 IDWriteFontSet_Release(fontset);
10335 IDWriteFactory3_Release(factory);
10338 static void test_CreateFontCollectionFromFontSet(void)
10340 unsigned int index, count, refcount;
10341 IDWriteFontCollection1 *collection;
10342 IDWriteFontSetBuilder1 *builder;
10343 DWRITE_FONT_PROPERTY props[1];
10344 IDWriteFontFaceReference *ref;
10345 IDWriteFactory5 *factory;
10346 IDWriteFontSet *fontset;
10347 IDWriteFontFile *file;
10348 WCHAR *path;
10349 BOOL exists;
10350 HRESULT hr;
10352 if (!(factory = create_factory_iid(&IID_IDWriteFactory5)))
10354 win_skip("_CreateFontCollectionFromFontSet() is not available.\n");
10355 return;
10358 hr = IDWriteFactory5_CreateFontSetBuilder(factory, &builder);
10359 ok(hr == S_OK, "Failed to create font set builder, hr %#lx.\n", hr);
10361 path = create_testfontfile(test_fontfile);
10363 hr = IDWriteFactory5_CreateFontFileReference(factory, path, NULL, &file);
10364 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10366 hr = IDWriteFontSetBuilder1_AddFontFile(builder, file);
10367 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10369 /* Add same file, with explicit properties. */
10370 hr = IDWriteFactory5_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
10371 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10372 props[0].propertyId = DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME;
10373 props[0].propertyValue = L"Another Font";
10374 props[0].localeName = L"en-US";
10375 hr = IDWriteFontSetBuilder1_AddFontFaceReference_(builder, ref, props, 1);
10376 todo_wine
10377 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10378 IDWriteFontFaceReference_Release(ref);
10380 hr = IDWriteFontSetBuilder1_CreateFontSet(builder, &fontset);
10381 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10383 hr = IDWriteFactory5_CreateFontCollectionFromFontSet(factory, fontset, &collection);
10384 todo_wine
10385 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10387 if (SUCCEEDED(hr))
10389 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
10390 ok(count == 2, "Unexpected family count %u.\n", count);
10392 /* Explicit fontset properties are prioritized and not replaced by actual properties from a file. */
10393 exists = FALSE;
10394 hr = IDWriteFontCollection1_FindFamilyName(collection, L"Another Font", &index, &exists);
10395 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
10396 ok(!!exists, "Unexpected return value %d.\n", exists);
10398 IDWriteFontCollection1_Release(collection);
10400 IDWriteFontSet_Release(fontset);
10402 IDWriteFontSetBuilder1_Release(builder);
10404 IDWriteFontFile_Release(file);
10405 refcount = IDWriteFactory5_Release(factory);
10406 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10407 DELETE_FONTFILE(path);
10410 static void test_GetMatchingFontsByLOGFONT(void)
10412 IDWriteFontSet *systemset, *set;
10413 IDWriteGdiInterop1 *interop;
10414 IDWriteGdiInterop *interop0;
10415 IDWriteFactory3 *factory;
10416 ULONG refcount, count;
10417 LOGFONTW logfont;
10418 HRESULT hr;
10420 factory = create_factory_iid(&IID_IDWriteFactory3);
10421 if (!factory)
10423 win_skip("Skipping GetMatchingFontsByLOGFONT() tests.\n");
10424 return;
10427 hr = IDWriteFactory3_GetSystemFontSet(factory, &systemset);
10428 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10430 interop = NULL;
10431 hr = IDWriteFactory3_GetGdiInterop(factory, &interop0);
10432 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10434 hr = IDWriteGdiInterop_QueryInterface(interop0, &IID_IDWriteGdiInterop1, (void **)&interop);
10435 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10436 IDWriteGdiInterop_Release(interop0);
10438 memset(&logfont, 0, sizeof(logfont));
10439 logfont.lfHeight = 12;
10440 logfont.lfWidth = 12;
10441 logfont.lfWeight = FW_BOLD;
10442 logfont.lfItalic = 1;
10443 lstrcpyW(logfont.lfFaceName, L"tahoma");
10445 hr = IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(interop, NULL, systemset, &set);
10446 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
10448 hr = IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(interop, &logfont, NULL, &set);
10449 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
10451 hr = IDWriteGdiInterop1_GetMatchingFontsByLOGFONT(interop, &logfont, systemset, &set);
10452 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
10454 count = IDWriteFontSet_GetFontCount(set);
10455 ok(count > 0, "Unexpected count %lu.\n", count);
10457 IDWriteFontSet_Release(set);
10459 IDWriteGdiInterop1_Release(interop);
10460 IDWriteFontSet_Release(systemset);
10462 refcount = IDWriteFactory3_Release(factory);
10463 ok(!refcount, "Factory wasn't released, %lu.\n", refcount);
10466 START_TEST(font)
10468 IDWriteFactory *factory;
10470 if (!(factory = create_factory())) {
10471 win_skip("failed to create factory\n");
10472 return;
10475 test_object_lifetime();
10476 test_CreateFontFromLOGFONT();
10477 test_CreateBitmapRenderTarget();
10478 test_GetFontFamily();
10479 test_GetFamilyNames();
10480 test_CreateFontFace();
10481 test_GetMetrics();
10482 test_system_fontcollection();
10483 test_ConvertFontFaceToLOGFONT();
10484 test_CustomFontCollection();
10485 test_CreateCustomFontFileReference();
10486 test_CreateFontFileReference();
10487 test_shared_isolated();
10488 test_GetUnicodeRanges();
10489 test_GetFontFromFontFace();
10490 test_GetFirstMatchingFont();
10491 test_GetMatchingFonts();
10492 test_GetInformationalStrings();
10493 test_GetGdiInterop();
10494 test_CreateFontFaceFromHdc();
10495 test_GetSimulations();
10496 test_GetFaceNames();
10497 test_TryGetFontTable();
10498 test_ConvertFontToLOGFONT();
10499 test_CreateStreamFromKey();
10500 test_ReadFileFragment();
10501 test_GetDesignGlyphMetrics();
10502 test_GetDesignGlyphAdvances();
10503 test_IsMonospacedFont();
10504 test_GetGlyphRunOutline();
10505 test_GetEudcFontCollection();
10506 test_GetCaretMetrics();
10507 test_GetGlyphCount();
10508 test_GetKerningPairAdjustments();
10509 test_CreateRenderingParams();
10510 test_CreateGlyphRunAnalysis();
10511 test_GetGdiCompatibleMetrics();
10512 test_GetPanose();
10513 test_GetGdiCompatibleGlyphAdvances();
10514 test_GetRecommendedRenderingMode();
10515 test_GetAlphaBlendParams();
10516 test_CreateAlphaTexture();
10517 test_IsSymbolFont();
10518 test_GetPaletteEntries();
10519 test_TranslateColorGlyphRun();
10520 test_HasCharacter();
10521 test_CreateFontFaceReference();
10522 test_GetFontSignature();
10523 test_font_properties();
10524 test_HasVerticalGlyphVariants();
10525 test_HasKerningPairs();
10526 test_ComputeGlyphOrigins();
10527 test_inmemory_file_loader();
10528 test_GetGlyphImageFormats();
10529 test_CreateCustomRenderingParams();
10530 test_localfontfileloader();
10531 test_AnalyzeContainerType();
10532 test_fontsetbuilder();
10533 test_font_resource();
10534 test_IsColorFont();
10535 test_GetVerticalGlyphVariants();
10536 test_expiration_event();
10537 test_family_font_set();
10538 test_system_font_set();
10539 test_CreateFontCollectionFromFontSet();
10540 test_GetMatchingFontsByLOGFONT();
10542 IDWriteFactory_Release(factory);