Release 6.15.
[wine.git] / dlls / dwrite / tests / font.c
blobbe367463414d8011a297403fa2ca78abaf89c6ce
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/heap.h"
34 #include "wine/test.h"
36 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
37 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
38 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
39 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
40 #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
41 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
42 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
43 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
44 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
45 #define MS_KERN_TAG DWRITE_MAKE_OPENTYPE_TAG('k','e','r','n')
46 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
47 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
48 #define MS_CFF2_TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F','2')
49 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
50 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
51 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
52 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
53 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
55 /* 'sbix' formats */
56 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
57 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
58 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
60 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
61 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
66 #define GET_LE_WORD(x) RtlUshortByteSwap(x)
67 #define GET_LE_DWORD(x) RtlUlongByteSwap(x)
68 #else
69 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
70 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
71 #define GET_LE_WORD(x) (x)
72 #define GET_LE_DWORD(x) (x)
73 #endif
75 #define EXPECT_HR(hr,hr_exp) \
76 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
78 #define DEFINE_EXPECT(func) \
79 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
81 #define SET_EXPECT(func) \
82 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
84 #define CHECK_EXPECT2(func) \
85 do { \
86 ok(expect_ ##func, "unexpected call " #func "\n"); \
87 called_ ## func = TRUE; \
88 }while(0)
90 #define CHECK_EXPECT(func) \
91 do { \
92 CHECK_EXPECT2(func); \
93 expect_ ## func = FALSE; \
94 }while(0)
96 #define CHECK_CALLED(func) \
97 do { \
98 ok(called_ ## func, "expected " #func "\n"); \
99 expect_ ## func = called_ ## func = FALSE; \
100 }while(0)
102 #define CLEAR_CALLED(func) \
103 expect_ ## func = called_ ## func = FALSE
105 DEFINE_EXPECT(setfillmode);
107 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
108 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
110 ULONG rc;
111 IUnknown_AddRef(obj);
112 rc = IUnknown_Release(obj);
113 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
116 #define EXPECT_REF_BROKEN(obj,ref,brokenref) _expect_ref_broken((IUnknown*)obj, ref, brokenref, __LINE__)
117 static void _expect_ref_broken(IUnknown* obj, ULONG ref, ULONG brokenref, int line)
119 ULONG rc;
120 IUnknown_AddRef(obj);
121 rc = IUnknown_Release(obj);
122 ok_(__FILE__,line)(rc == ref || broken(rc == brokenref), "expected refcount %d, got %d\n", ref, rc);
125 static BOOL (WINAPI *pGetFontRealizationInfo)(HDC hdc, void *);
127 static const WCHAR test_fontfile[] = L"wine_test_font.ttf";
129 /* PANOSE is 10 bytes in size, need to pack the structure properly */
130 #include "pshpack2.h"
131 typedef struct
133 USHORT majorVersion;
134 USHORT minorVersion;
135 ULONG revision;
136 ULONG checksumadj;
137 ULONG magic;
138 USHORT flags;
139 USHORT unitsPerEm;
140 ULONGLONG created;
141 ULONGLONG modified;
142 SHORT xMin;
143 SHORT yMin;
144 SHORT xMax;
145 SHORT yMax;
146 USHORT macStyle;
147 USHORT lowestRecPPEM;
148 SHORT direction_hint;
149 SHORT index_format;
150 SHORT glyphdata_format;
151 } TT_HEAD;
153 enum TT_HEAD_MACSTYLE
155 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
156 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
157 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
158 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
159 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
160 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
161 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
164 typedef struct
166 USHORT version;
167 SHORT xAvgCharWidth;
168 USHORT usWeightClass;
169 USHORT usWidthClass;
170 SHORT fsType;
171 SHORT ySubscriptXSize;
172 SHORT ySubscriptYSize;
173 SHORT ySubscriptXOffset;
174 SHORT ySubscriptYOffset;
175 SHORT ySuperscriptXSize;
176 SHORT ySuperscriptYSize;
177 SHORT ySuperscriptXOffset;
178 SHORT ySuperscriptYOffset;
179 SHORT yStrikeoutSize;
180 SHORT yStrikeoutPosition;
181 SHORT sFamilyClass;
182 PANOSE panose;
183 ULONG ulUnicodeRange1;
184 ULONG ulUnicodeRange2;
185 ULONG ulUnicodeRange3;
186 ULONG ulUnicodeRange4;
187 CHAR achVendID[4];
188 USHORT fsSelection;
189 USHORT usFirstCharIndex;
190 USHORT usLastCharIndex;
191 /* According to the Apple spec, original version didn't have the below fields,
192 * version numbers were taken from the OpenType spec.
194 /* version 0 (TrueType 1.5) */
195 USHORT sTypoAscender;
196 USHORT sTypoDescender;
197 USHORT sTypoLineGap;
198 USHORT usWinAscent;
199 USHORT usWinDescent;
200 /* version 1 (TrueType 1.66) */
201 ULONG ulCodePageRange1;
202 ULONG ulCodePageRange2;
203 /* version 2 (OpenType 1.2) */
204 SHORT sxHeight;
205 SHORT sCapHeight;
206 USHORT usDefaultChar;
207 USHORT usBreakChar;
208 USHORT usMaxContext;
209 } TT_OS2_V2;
211 enum OS2_FSSELECTION {
212 OS2_FSSELECTION_ITALIC = 1 << 0,
213 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
214 OS2_FSSELECTION_NEGATIVE = 1 << 2,
215 OS2_FSSELECTION_OUTLINED = 1 << 3,
216 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
217 OS2_FSSELECTION_BOLD = 1 << 5,
218 OS2_FSSELECTION_REGULAR = 1 << 6,
219 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
220 OS2_FSSELECTION_WWS = 1 << 8,
221 OS2_FSSELECTION_OBLIQUE = 1 << 9
224 typedef struct {
225 ULONG Version;
226 ULONG italicAngle;
227 SHORT underlinePosition;
228 SHORT underlineThickness;
229 ULONG fixed_pitch;
230 ULONG minmemType42;
231 ULONG maxmemType42;
232 ULONG minmemType1;
233 ULONG maxmemType1;
234 } TT_POST;
236 typedef struct {
237 USHORT majorVersion;
238 USHORT minorVersion;
239 SHORT ascender;
240 SHORT descender;
241 SHORT linegap;
242 USHORT advanceWidthMax;
243 SHORT minLeftSideBearing;
244 SHORT minRightSideBearing;
245 SHORT xMaxExtent;
246 SHORT caretSlopeRise;
247 SHORT caretSlopeRun;
248 SHORT caretOffset;
249 SHORT reserved[4];
250 SHORT metricDataFormat;
251 USHORT numberOfHMetrics;
252 } TT_HHEA;
254 typedef struct {
255 DWORD version;
256 WORD ScriptList;
257 WORD FeatureList;
258 WORD LookupList;
259 } GSUB_Header;
261 typedef struct {
262 CHAR FeatureTag[4];
263 WORD Feature;
264 } OT_FeatureRecord;
266 typedef struct {
267 WORD FeatureCount;
268 OT_FeatureRecord FeatureRecord[1];
269 } OT_FeatureList;
271 typedef struct {
272 WORD FeatureParams;
273 WORD LookupCount;
274 WORD LookupListIndex[1];
275 } OT_Feature;
277 typedef struct {
278 WORD LookupCount;
279 WORD Lookup[1];
280 } OT_LookupList;
282 typedef struct {
283 WORD LookupType;
284 WORD LookupFlag;
285 WORD SubTableCount;
286 WORD SubTable[1];
287 } OT_LookupTable;
289 typedef struct {
290 WORD SubstFormat;
291 WORD Coverage;
292 WORD DeltaGlyphID;
293 } GSUB_SingleSubstFormat1;
295 typedef struct {
296 WORD SubstFormat;
297 WORD Coverage;
298 WORD GlyphCount;
299 WORD Substitute[1];
300 } GSUB_SingleSubstFormat2;
302 typedef struct {
303 WORD SubstFormat;
304 WORD ExtensionLookupType;
305 DWORD ExtensionOffset;
306 } GSUB_ExtensionPosFormat1;
308 typedef struct {
309 WORD version;
310 WORD flags;
311 DWORD numStrikes;
312 DWORD strikeOffset[1];
313 } sbix_header;
315 typedef struct {
316 WORD ppem;
317 WORD ppi;
318 DWORD glyphDataOffsets[1];
319 } sbix_strike;
321 typedef struct {
322 WORD originOffsetX;
323 WORD originOffsetY;
324 DWORD graphicType;
325 BYTE data[1];
326 } sbix_glyph_data;
328 typedef struct {
329 WORD majorVersion;
330 WORD minorVersion;
331 DWORD numSizes;
332 } CBLCHeader;
334 typedef struct {
335 BYTE res[12];
336 } sbitLineMetrics;
338 typedef struct {
339 DWORD indexSubTableArrayOffset;
340 DWORD indexTablesSize;
341 DWORD numberofIndexSubTables;
342 DWORD colorRef;
343 sbitLineMetrics hori;
344 sbitLineMetrics vert;
345 WORD startGlyphIndex;
346 WORD endGlyphIndex;
347 BYTE ppemX;
348 BYTE ppemY;
349 BYTE bitDepth;
350 BYTE flags;
351 } CBLCBitmapSizeTable;
353 typedef struct {
354 DWORD version;
355 WORD numGlyphs;
356 } maxp;
358 struct WOFFHeader
360 ULONG signature;
361 ULONG flavor;
362 ULONG length;
363 USHORT numTables;
364 USHORT reserved;
365 ULONG totalSfntSize;
366 USHORT majorVersion;
367 USHORT minorVersion;
368 ULONG metaOffset;
369 ULONG metaLength;
370 ULONG metaOrigLength;
371 ULONG privOffset;
372 ULONG privLength;
375 struct WOFFHeader2
377 ULONG signature;
378 ULONG flavor;
379 ULONG length;
380 USHORT numTables;
381 USHORT reserved;
382 ULONG totalSfntSize;
383 ULONG totalCompressedSize;
384 USHORT majorVersion;
385 USHORT minorVersion;
386 ULONG metaOffset;
387 ULONG metaLength;
388 ULONG metaOrigLength;
389 ULONG privOffset;
390 ULONG privLength;
393 struct cmap_encoding_record
395 WORD platformID;
396 WORD encodingID;
397 DWORD offset;
400 struct cmap_header
402 WORD version;
403 WORD num_tables;
404 struct cmap_encoding_record tables[1];
407 struct cmap_segmented_coverage_group
409 DWORD startCharCode;
410 DWORD endCharCode;
411 DWORD startGlyphID;
414 struct cmap_segmented_coverage
416 WORD format;
417 WORD reserved;
418 DWORD length;
419 DWORD language;
420 DWORD nGroups;
421 struct cmap_segmented_coverage_group groups[1];
424 struct cmap_segmented_mapping_0
426 WORD format;
427 WORD length;
428 WORD language;
429 WORD segCountX2;
430 WORD searchRange;
431 WORD entrySelector;
432 WORD rangeShift;
433 WORD endCode[1];
436 enum opentype_cmap_table_platform
438 OPENTYPE_CMAP_TABLE_PLATFORM_WIN = 3,
441 enum opentype_cmap_table_encoding
443 OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL = 0,
444 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP = 1,
445 OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL = 10,
448 enum opentype_cmap_table_format
450 OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
451 OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12,
454 #include "poppack.h"
456 static void *create_factory_iid(REFIID riid)
458 IUnknown *factory = NULL;
459 DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, riid, &factory);
460 return factory;
463 static IDWriteFactory *create_factory(void)
465 IDWriteFactory *factory = create_factory_iid(&IID_IDWriteFactory);
466 ok(factory != NULL, "Failed to create factory.\n");
467 return factory;
470 static IDWriteFontFace *create_fontface(IDWriteFactory *factory)
472 IDWriteGdiInterop *interop;
473 IDWriteFontFace *fontface;
474 IDWriteFont *font;
475 LOGFONTW logfont;
476 HRESULT hr;
478 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
479 ok(hr == S_OK, "got 0x%08x\n", hr);
481 memset(&logfont, 0, sizeof(logfont));
482 logfont.lfHeight = 12;
483 logfont.lfWidth = 12;
484 logfont.lfWeight = FW_NORMAL;
485 logfont.lfItalic = 1;
486 lstrcpyW(logfont.lfFaceName, L"Tahoma");
488 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
489 ok(hr == S_OK, "got 0x%08x\n", hr);
491 hr = IDWriteFont_CreateFontFace(font, &fontface);
492 ok(hr == S_OK, "got 0x%08x\n", hr);
494 IDWriteFont_Release(font);
495 IDWriteGdiInterop_Release(interop);
497 return fontface;
500 static IDWriteFont *get_font(IDWriteFactory *factory, const WCHAR *name, DWRITE_FONT_STYLE style)
502 IDWriteFontCollection *collection;
503 IDWriteFontFamily *family;
504 IDWriteFont *font = NULL;
505 UINT32 index;
506 BOOL exists;
507 HRESULT hr;
509 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
510 ok(hr == S_OK, "got 0x%08x\n", hr);
512 index = ~0;
513 exists = FALSE;
514 hr = IDWriteFontCollection_FindFamilyName(collection, name, &index, &exists);
515 ok(hr == S_OK, "got 0x%08x\n", hr);
516 if (!exists) goto not_found;
518 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
519 ok(hr == S_OK, "got 0x%08x\n", hr);
521 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
522 DWRITE_FONT_STRETCH_NORMAL, style, &font);
523 ok(hr == S_OK, "got 0x%08x\n", hr);
525 IDWriteFontFamily_Release(family);
526 not_found:
527 IDWriteFontCollection_Release(collection);
528 return font;
531 static IDWriteFont *get_tahoma_instance(IDWriteFactory *factory, DWRITE_FONT_STYLE style)
533 IDWriteFont *font = get_font(factory, L"Tahoma", style);
534 ok(font != NULL, "failed to get Tahoma\n");
535 return font;
538 static WCHAR *create_testfontfile(const WCHAR *filename)
540 static WCHAR pathW[MAX_PATH];
541 DWORD written;
542 HANDLE file;
543 HRSRC res;
544 void *ptr;
546 GetTempPathW(ARRAY_SIZE(pathW), pathW);
547 lstrcatW(pathW, filename);
549 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
550 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW),
551 GetLastError());
553 res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
554 ok( res != 0, "couldn't find resource\n" );
555 ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
556 WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
557 ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
558 CloseHandle( file );
560 return pathW;
563 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
564 static void _delete_testfontfile(const WCHAR *filename, int line)
566 BOOL ret = DeleteFileW(filename);
567 ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError());
570 static void get_combined_font_name(const WCHAR *familyW, const WCHAR *faceW, WCHAR *nameW)
572 lstrcpyW(nameW, familyW);
573 lstrcatW(nameW, L" ");
574 lstrcatW(nameW, faceW);
577 static BOOL has_face_variations(IDWriteFontFace *fontface)
579 IDWriteFontFace5 *fontface5;
580 BOOL ret = FALSE;
582 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5))) {
583 ret = IDWriteFontFace5_HasVariations(fontface5);
584 IDWriteFontFace5_Release(fontface5);
587 return ret;
590 #define check_familymodel(a,b) _check_familymodel(a,b,__LINE__)
591 static void _check_familymodel(void *iface_ptr, DWRITE_FONT_FAMILY_MODEL expected_model, unsigned int line)
593 IDWriteFontCollection2 *collection;
594 DWRITE_FONT_FAMILY_MODEL model;
596 if (SUCCEEDED(IUnknown_QueryInterface((IUnknown *)iface_ptr, &IID_IDWriteFontCollection2, (void **)&collection)))
598 model = IDWriteFontCollection2_GetFontFamilyModel(collection);
599 ok_(__FILE__,line)(model == expected_model, "Unexpected family model %d, expected %d.\n", model, expected_model);
600 IDWriteFontCollection2_Release(collection);
604 struct test_fontenumerator
606 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
607 LONG ref;
609 DWORD index;
610 IDWriteFontFile *font_file;
613 static inline struct test_fontenumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
615 return CONTAINING_RECORD(iface, struct test_fontenumerator, IDWriteFontFileEnumerator_iface);
618 static HRESULT WINAPI singlefontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
620 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
622 *obj = iface;
623 IDWriteFontFileEnumerator_AddRef(iface);
624 return S_OK;
626 return E_NOINTERFACE;
629 static ULONG WINAPI singlefontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
631 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
632 return InterlockedIncrement(&This->ref);
635 static ULONG WINAPI singlefontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
637 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
638 ULONG ref = InterlockedDecrement(&This->ref);
639 if (!ref) {
640 IDWriteFontFile_Release(This->font_file);
641 heap_free(This);
643 return ref;
646 static HRESULT WINAPI singlefontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **font_file)
648 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
649 IDWriteFontFile_AddRef(This->font_file);
650 *font_file = This->font_file;
651 return S_OK;
654 static HRESULT WINAPI singlefontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
656 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
658 if (This->index > 1) {
659 *current = FALSE;
660 return S_OK;
663 This->index++;
664 *current = TRUE;
665 return S_OK;
668 static const struct IDWriteFontFileEnumeratorVtbl singlefontfileenumeratorvtbl =
670 singlefontfileenumerator_QueryInterface,
671 singlefontfileenumerator_AddRef,
672 singlefontfileenumerator_Release,
673 singlefontfileenumerator_MoveNext,
674 singlefontfileenumerator_GetCurrentFontFile
677 static HRESULT create_enumerator(IDWriteFontFile *font_file, IDWriteFontFileEnumerator **ret)
679 struct test_fontenumerator *enumerator;
681 enumerator = heap_alloc(sizeof(struct test_fontenumerator));
682 if (!enumerator)
683 return E_OUTOFMEMORY;
685 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &singlefontfileenumeratorvtbl;
686 enumerator->ref = 1;
687 enumerator->index = 0;
688 enumerator->font_file = font_file;
689 IDWriteFontFile_AddRef(font_file);
691 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
692 return S_OK;
695 struct test_fontcollectionloader
697 IDWriteFontCollectionLoader IDWriteFontFileCollectionLoader_iface;
698 IDWriteFontFileLoader *loader;
701 static inline struct test_fontcollectionloader *impl_from_IDWriteFontFileCollectionLoader(IDWriteFontCollectionLoader* iface)
703 return CONTAINING_RECORD(iface, struct test_fontcollectionloader, IDWriteFontFileCollectionLoader_iface);
706 static HRESULT WINAPI resourcecollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
708 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontCollectionLoader))
710 *obj = iface;
711 IDWriteFontCollectionLoader_AddRef(iface);
712 return S_OK;
714 return E_NOINTERFACE;
717 static ULONG WINAPI resourcecollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
719 return 2;
722 static ULONG WINAPI resourcecollectionloader_Release(IDWriteFontCollectionLoader *iface)
724 return 1;
727 static HRESULT WINAPI resourcecollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory,
728 const void * collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator ** fontFileEnumerator)
730 struct test_fontcollectionloader *This = impl_from_IDWriteFontFileCollectionLoader(iface);
731 IDWriteFontFile *font_file;
732 HRESULT hr;
734 hr = IDWriteFactory_CreateCustomFontFileReference(factory, collectionKey, collectionKeySize, This->loader, &font_file);
735 ok(hr == S_OK, "Failed to create custom file reference, hr %#x.\n", hr);
737 hr = create_enumerator(font_file, fontFileEnumerator);
738 ok(hr == S_OK, "got 0x%08x\n", hr);
740 IDWriteFontFile_Release(font_file);
741 return hr;
744 static const struct IDWriteFontCollectionLoaderVtbl resourcecollectionloadervtbl = {
745 resourcecollectionloader_QueryInterface,
746 resourcecollectionloader_AddRef,
747 resourcecollectionloader_Release,
748 resourcecollectionloader_CreateEnumeratorFromKey
751 /* Here is a functional custom font set of interfaces */
752 struct test_fontdatastream
754 IDWriteFontFileStream IDWriteFontFileStream_iface;
755 LONG ref;
757 LPVOID data;
758 DWORD size;
761 static inline struct test_fontdatastream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream* iface)
763 return CONTAINING_RECORD(iface, struct test_fontdatastream, IDWriteFontFileStream_iface);
766 static HRESULT WINAPI fontdatastream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
768 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
770 *obj = iface;
771 IDWriteFontFileStream_AddRef(iface);
772 return S_OK;
774 *obj = NULL;
775 return E_NOINTERFACE;
778 static ULONG WINAPI fontdatastream_AddRef(IDWriteFontFileStream *iface)
780 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
781 ULONG ref = InterlockedIncrement(&This->ref);
782 return ref;
785 static ULONG WINAPI fontdatastream_Release(IDWriteFontFileStream *iface)
787 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
788 ULONG ref = InterlockedDecrement(&This->ref);
789 if (ref == 0)
790 HeapFree(GetProcessHeap(), 0, This);
791 return ref;
794 static HRESULT WINAPI fontdatastream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
796 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
797 *fragment_context = NULL;
798 if (offset+fragment_size > This->size)
800 *fragment_start = NULL;
801 return E_FAIL;
803 else
805 *fragment_start = (BYTE*)This->data + offset;
806 return S_OK;
810 static void WINAPI fontdatastream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
812 /* Do Nothing */
815 static HRESULT WINAPI fontdatastream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
817 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
818 *size = This->size;
819 return S_OK;
822 static HRESULT WINAPI fontdatastream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
824 return E_NOTIMPL;
827 static const IDWriteFontFileStreamVtbl fontdatastreamvtbl =
829 fontdatastream_QueryInterface,
830 fontdatastream_AddRef,
831 fontdatastream_Release,
832 fontdatastream_ReadFileFragment,
833 fontdatastream_ReleaseFileFragment,
834 fontdatastream_GetFileSize,
835 fontdatastream_GetLastWriteTime
838 static HRESULT create_fontdatastream(LPVOID data, UINT size, IDWriteFontFileStream** iface)
840 struct test_fontdatastream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct test_fontdatastream));
841 if (!This)
842 return E_OUTOFMEMORY;
844 This->data = data;
845 This->size = size;
846 This->ref = 1;
847 This->IDWriteFontFileStream_iface.lpVtbl = &fontdatastreamvtbl;
849 *iface = &This->IDWriteFontFileStream_iface;
850 return S_OK;
853 static HRESULT WINAPI resourcefontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
855 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
857 *obj = iface;
858 return S_OK;
860 *obj = NULL;
861 return E_NOINTERFACE;
864 static ULONG WINAPI resourcefontfileloader_AddRef(IDWriteFontFileLoader *iface)
866 return 2;
869 static ULONG WINAPI resourcefontfileloader_Release(IDWriteFontFileLoader *iface)
871 return 1;
874 static HRESULT WINAPI resourcefontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
875 IDWriteFontFileStream **stream)
877 LPVOID data;
878 DWORD size;
879 HGLOBAL mem;
881 mem = LoadResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
882 ok(mem != NULL, "Failed to lock font resource\n");
883 if (mem)
885 size = SizeofResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
886 data = LockResource(mem);
887 return create_fontdatastream(data, size, stream);
889 return E_FAIL;
892 static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = {
893 resourcefontfileloader_QueryInterface,
894 resourcefontfileloader_AddRef,
895 resourcefontfileloader_Release,
896 resourcefontfileloader_CreateStreamFromKey
899 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
901 static D2D1_POINT_2F g_startpoints[2];
902 static int g_startpoint_count;
904 static HRESULT WINAPI test_geometrysink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **ret)
906 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
907 IsEqualIID(riid, &IID_IUnknown))
909 *ret = iface;
910 ID2D1SimplifiedGeometrySink_AddRef(iface);
911 return S_OK;
914 *ret = NULL;
915 return E_NOINTERFACE;
918 static ULONG WINAPI test_geometrysink_AddRef(ID2D1SimplifiedGeometrySink *iface)
920 return 2;
923 static ULONG WINAPI test_geometrysink_Release(ID2D1SimplifiedGeometrySink *iface)
925 return 1;
928 static void WINAPI test_geometrysink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
930 CHECK_EXPECT(setfillmode);
931 ok(mode == D2D1_FILL_MODE_WINDING, "fill mode %d\n", mode);
934 static void WINAPI test_geometrysink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT flags)
936 ok(0, "unexpected SetSegmentFlags() - flags %d\n", flags);
939 static void WINAPI test_geometrysink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
940 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
942 ok(figureBegin == D2D1_FIGURE_BEGIN_FILLED, "begin figure %d\n", figureBegin);
943 if (g_startpoint_count < ARRAY_SIZE(g_startpoints))
944 g_startpoints[g_startpoint_count] = startPoint;
945 g_startpoint_count++;
948 static void WINAPI test_geometrysink_AddLines(ID2D1SimplifiedGeometrySink *iface,
949 const D2D1_POINT_2F *points, UINT32 count)
953 static void WINAPI test_geometrysink_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
954 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
958 static void WINAPI test_geometrysink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
960 ok(figureEnd == D2D1_FIGURE_END_CLOSED, "end figure %d\n", figureEnd);
963 static HRESULT WINAPI test_geometrysink_Close(ID2D1SimplifiedGeometrySink *iface)
965 ok(0, "unexpected Close()\n");
966 return E_NOTIMPL;
969 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink_vtbl = {
970 test_geometrysink_QueryInterface,
971 test_geometrysink_AddRef,
972 test_geometrysink_Release,
973 test_geometrysink_SetFillMode,
974 test_geometrysink_SetSegmentFlags,
975 test_geometrysink_BeginFigure,
976 test_geometrysink_AddLines,
977 test_geometrysink_AddBeziers,
978 test_geometrysink_EndFigure,
979 test_geometrysink_Close
982 static void WINAPI test_geometrysink2_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
983 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
985 ok(0, "unexpected call\n");
988 static void WINAPI test_geometrysink2_AddLines(ID2D1SimplifiedGeometrySink *iface,
989 const D2D1_POINT_2F *points, UINT32 count)
991 ok(0, "unexpected call\n");
994 static void WINAPI test_geometrysink2_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
995 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
997 ok(0, "unexpected call\n");
1000 static void WINAPI test_geometrysink2_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
1002 ok(0, "unexpected call\n");
1005 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink2_vtbl = {
1006 test_geometrysink_QueryInterface,
1007 test_geometrysink_AddRef,
1008 test_geometrysink_Release,
1009 test_geometrysink_SetFillMode,
1010 test_geometrysink_SetSegmentFlags,
1011 test_geometrysink2_BeginFigure,
1012 test_geometrysink2_AddLines,
1013 test_geometrysink2_AddBeziers,
1014 test_geometrysink2_EndFigure,
1015 test_geometrysink_Close
1018 static ID2D1SimplifiedGeometrySink test_geomsink = { &test_geometrysink_vtbl };
1019 static ID2D1SimplifiedGeometrySink test_geomsink2 = { &test_geometrysink2_vtbl };
1021 static void test_CreateFontFromLOGFONT(void)
1023 IDWriteGdiInterop1 *interop1;
1024 IDWriteGdiInterop *interop;
1025 DWRITE_FONT_WEIGHT weight;
1026 DWRITE_FONT_STYLE style;
1027 IDWriteFont *font;
1028 LOGFONTW logfont;
1029 LONG weights[][2] = {
1030 {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
1031 {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
1032 { 0, DWRITE_FONT_WEIGHT_NORMAL},
1033 { 50, DWRITE_FONT_WEIGHT_NORMAL},
1034 {150, DWRITE_FONT_WEIGHT_NORMAL},
1035 {250, DWRITE_FONT_WEIGHT_NORMAL},
1036 {350, DWRITE_FONT_WEIGHT_NORMAL},
1037 {450, DWRITE_FONT_WEIGHT_NORMAL},
1038 {650, DWRITE_FONT_WEIGHT_BOLD},
1039 {750, DWRITE_FONT_WEIGHT_BOLD},
1040 {850, DWRITE_FONT_WEIGHT_BOLD},
1041 {950, DWRITE_FONT_WEIGHT_BOLD},
1042 {960, DWRITE_FONT_WEIGHT_BOLD},
1044 OUTLINETEXTMETRICW otm;
1045 IDWriteFactory *factory;
1046 HRESULT hr;
1047 BOOL ret;
1048 HDC hdc;
1049 HFONT hfont;
1050 BOOL exists;
1051 ULONG ref;
1052 int i;
1053 UINT r;
1055 factory = create_factory();
1057 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1058 ok(hr == S_OK, "got %#x\n", hr);
1060 if (0)
1061 /* null out parameter crashes this call */
1062 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
1064 font = (void*)0xdeadbeef;
1065 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
1066 EXPECT_HR(hr, E_INVALIDARG);
1067 ok(font == NULL, "got %p\n", font);
1069 memset(&logfont, 0, sizeof(logfont));
1070 logfont.lfHeight = 12;
1071 logfont.lfWidth = 12;
1072 logfont.lfWeight = FW_NORMAL;
1073 logfont.lfItalic = 1;
1074 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1076 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1077 EXPECT_HR(hr, S_OK);
1079 hfont = CreateFontIndirectW(&logfont);
1080 hdc = CreateCompatibleDC(0);
1081 SelectObject(hdc, hfont);
1083 otm.otmSize = sizeof(otm);
1084 r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
1085 ok(r, "got %d\n", r);
1086 DeleteDC(hdc);
1087 DeleteObject(hfont);
1089 exists = TRUE;
1090 hr = IDWriteFont_HasCharacter(font, 0xd800, &exists);
1091 ok(hr == S_OK, "got 0x%08x\n", hr);
1092 ok(exists == FALSE, "got %d\n", exists);
1094 exists = FALSE;
1095 hr = IDWriteFont_HasCharacter(font, 0x20, &exists);
1096 ok(hr == S_OK, "got 0x%08x\n", hr);
1097 ok(exists == TRUE, "got %d\n", exists);
1099 /* now check properties */
1100 weight = IDWriteFont_GetWeight(font);
1101 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1103 style = IDWriteFont_GetStyle(font);
1104 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1105 ok(otm.otmfsSelection & 1, "got 0x%08x\n", otm.otmfsSelection);
1107 ret = IDWriteFont_IsSymbolFont(font);
1108 ok(!ret, "got %d\n", ret);
1110 IDWriteFont_Release(font);
1112 /* weight values */
1113 for (i = 0; i < ARRAY_SIZE(weights); i++)
1115 memset(&logfont, 0, sizeof(logfont));
1116 logfont.lfHeight = 12;
1117 logfont.lfWidth = 12;
1118 logfont.lfWeight = weights[i][0];
1119 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1121 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1122 EXPECT_HR(hr, S_OK);
1124 weight = IDWriteFont_GetWeight(font);
1125 ok(weight == weights[i][1],
1126 "%d: got %d, expected %d\n", i, weight, weights[i][1]);
1128 IDWriteFont_Release(font);
1131 /* weight not from enum */
1132 memset(&logfont, 0, sizeof(logfont));
1133 logfont.lfHeight = 12;
1134 logfont.lfWidth = 12;
1135 logfont.lfWeight = 550;
1136 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1138 font = NULL;
1139 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1140 ok(hr == S_OK, "got 0x%08x\n", hr);
1142 weight = IDWriteFont_GetWeight(font);
1143 ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
1144 "got %d\n", weight);
1146 IDWriteFont_Release(font);
1148 /* empty or nonexistent face name */
1149 memset(&logfont, 0, sizeof(logfont));
1150 logfont.lfHeight = 12;
1151 logfont.lfWidth = 12;
1152 logfont.lfWeight = FW_NORMAL;
1153 lstrcpyW(logfont.lfFaceName, L"Blah!");
1155 font = (void*)0xdeadbeef;
1156 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1157 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1158 ok(font == NULL, "got %p\n", font);
1160 /* Try with name 'Tahoma ' */
1161 memset(&logfont, 0, sizeof(logfont));
1162 logfont.lfHeight = 12;
1163 logfont.lfWidth = 12;
1164 logfont.lfWeight = FW_NORMAL;
1165 lstrcpyW(logfont.lfFaceName, L"Tahoma ");
1167 font = (void*)0xdeadbeef;
1168 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1169 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1170 ok(font == NULL, "got %p\n", font);
1172 /* empty string as a facename */
1173 memset(&logfont, 0, sizeof(logfont));
1174 logfont.lfHeight = 12;
1175 logfont.lfWidth = 12;
1176 logfont.lfWeight = FW_NORMAL;
1178 font = (void*)0xdeadbeef;
1179 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1180 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1181 ok(font == NULL, "got %p\n", font);
1183 /* IDWriteGdiInterop1::CreateFontFromLOGFONT() */
1184 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
1185 if (hr == S_OK) {
1186 memset(&logfont, 0, sizeof(logfont));
1187 logfont.lfHeight = 12;
1188 logfont.lfWidth = 12;
1189 logfont.lfWeight = FW_NORMAL;
1190 logfont.lfItalic = 1;
1191 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1193 hr = IDWriteGdiInterop1_CreateFontFromLOGFONT(interop1, &logfont, NULL, &font);
1194 ok(hr == S_OK, "got 0x%08x\n", hr);
1196 IDWriteFont_Release(font);
1197 IDWriteGdiInterop1_Release(interop1);
1199 else
1200 win_skip("IDWriteGdiInterop1 is not supported, skipping CreateFontFromLOGFONT() tests.\n");
1202 ref = IDWriteGdiInterop_Release(interop);
1203 ok(ref == 0, "interop is not released, %u\n", ref);
1204 ref = IDWriteFactory_Release(factory);
1205 ok(ref == 0, "factory is not released, %u\n", ref);
1208 static void test_CreateBitmapRenderTarget(void)
1210 IDWriteBitmapRenderTarget *target, *target2;
1211 IDWriteBitmapRenderTarget1 *target1;
1212 IDWriteRenderingParams *params;
1213 IDWriteGdiInterop *interop;
1214 IDWriteFontFace *fontface;
1215 IDWriteFactory *factory;
1216 DWRITE_GLYPH_RUN run;
1217 HBITMAP hbm, hbm2;
1218 UINT16 glyphs[2];
1219 DWRITE_MATRIX m;
1220 DIBSECTION ds;
1221 XFORM xform;
1222 COLORREF c;
1223 HRESULT hr;
1224 FLOAT pdip;
1225 SIZE size;
1226 ULONG ref;
1227 UINT32 ch;
1228 HDC hdc;
1229 int ret;
1231 factory = create_factory();
1233 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1234 EXPECT_HR(hr, S_OK);
1236 target = NULL;
1237 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
1238 EXPECT_HR(hr, S_OK);
1240 if (0) /* crashes on native */
1241 hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
1243 size.cx = size.cy = -1;
1244 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1245 EXPECT_HR(hr, S_OK);
1246 ok(size.cx == 0, "got %d\n", size.cx);
1247 ok(size.cy == 0, "got %d\n", size.cy);
1249 target2 = NULL;
1250 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
1251 EXPECT_HR(hr, S_OK);
1252 ok(target != target2, "got %p, %p\n", target2, target);
1253 IDWriteBitmapRenderTarget_Release(target2);
1255 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1256 ok(hdc != NULL, "got %p\n", hdc);
1258 /* test mode */
1259 ret = GetGraphicsMode(hdc);
1260 ok(ret == GM_ADVANCED, "got %d\n", ret);
1262 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1263 ok(hbm != NULL, "got %p\n", hbm);
1265 /* check DIB properties */
1266 ret = GetObjectW(hbm, sizeof(ds), &ds);
1267 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1268 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1269 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1270 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1271 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1272 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1274 IDWriteBitmapRenderTarget_Release(target);
1276 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1277 ok(!hbm, "got %p\n", hbm);
1279 target = NULL;
1280 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
1281 EXPECT_HR(hr, S_OK);
1283 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1284 ok(hdc != NULL, "got %p\n", hdc);
1286 /* test context settings */
1287 c = GetTextColor(hdc);
1288 ok(c == RGB(0, 0, 0), "got 0x%08x\n", c);
1289 ret = GetBkMode(hdc);
1290 ok(ret == OPAQUE, "got %d\n", ret);
1291 c = GetBkColor(hdc);
1292 ok(c == RGB(255, 255, 255), "got 0x%08x\n", c);
1294 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1295 ok(hbm != NULL, "got %p\n", hbm);
1297 /* check DIB properties */
1298 ret = GetObjectW(hbm, sizeof(ds), &ds);
1299 ok(ret == sizeof(ds), "got %d\n", ret);
1300 ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
1301 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1302 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1303 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1304 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1306 size.cx = size.cy = -1;
1307 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1308 EXPECT_HR(hr, S_OK);
1309 ok(size.cx == 10, "got %d\n", size.cx);
1310 ok(size.cy == 5, "got %d\n", size.cy);
1312 /* resize to same size */
1313 hr = IDWriteBitmapRenderTarget_Resize(target, 10, 5);
1314 ok(hr == S_OK, "got 0x%08x\n", hr);
1316 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1317 ok(hbm2 == hbm, "got %p, %p\n", hbm2, hbm);
1319 /* shrink */
1320 hr = IDWriteBitmapRenderTarget_Resize(target, 5, 5);
1321 ok(hr == S_OK, "got 0x%08x\n", hr);
1323 size.cx = size.cy = -1;
1324 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1325 ok(hr == S_OK, "got 0x%08x\n", hr);
1326 ok(size.cx == 5, "got %d\n", size.cx);
1327 ok(size.cy == 5, "got %d\n", size.cy);
1329 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1330 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1332 hr = IDWriteBitmapRenderTarget_Resize(target, 20, 5);
1333 ok(hr == S_OK, "got 0x%08x\n", hr);
1335 size.cx = size.cy = -1;
1336 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1337 ok(hr == S_OK, "got 0x%08x\n", hr);
1338 ok(size.cx == 20, "got %d\n", size.cx);
1339 ok(size.cy == 5, "got %d\n", size.cy);
1341 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1342 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1344 hr = IDWriteBitmapRenderTarget_Resize(target, 1, 5);
1345 ok(hr == S_OK, "got 0x%08x\n", hr);
1347 size.cx = size.cy = -1;
1348 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1349 ok(hr == S_OK, "got 0x%08x\n", hr);
1350 ok(size.cx == 1, "got %d\n", size.cx);
1351 ok(size.cy == 5, "got %d\n", size.cy);
1353 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1354 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1356 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1357 ok(ret == sizeof(ds), "got %d\n", ret);
1358 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1359 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1360 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1361 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1362 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1364 /* empty rectangle */
1365 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 5);
1366 ok(hr == S_OK, "got 0x%08x\n", hr);
1368 size.cx = size.cy = -1;
1369 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1370 ok(hr == S_OK, "got 0x%08x\n", hr);
1371 ok(size.cx == 0, "got %d\n", size.cx);
1372 ok(size.cy == 5, "got %d\n", size.cy);
1374 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1375 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1377 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1378 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1379 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1380 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1381 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1382 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1383 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1385 /* transform tests, current hdc transform is not immediately affected */
1386 if (0) /* crashes on native */
1387 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, NULL);
1389 memset(&m, 0xcc, sizeof(m));
1390 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1391 ok(hr == S_OK, "got 0x%08x\n", hr);
1392 ok(m.m11 == 1.0 && m.m22 == 1.0 && m.m12 == 0.0 && m.m21 == 0.0, "got %.1f,%.1f,%.1f,%.1f\n", m.m11, m.m22, m.m12, m.m21);
1393 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1394 ret = GetWorldTransform(hdc, &xform);
1395 ok(ret, "got %d\n", ret);
1396 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1397 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1399 memset(&m, 0, sizeof(m));
1400 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1401 ok(hr == S_OK, "got 0x%08x\n", hr);
1403 memset(&m, 0xcc, sizeof(m));
1404 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1405 ok(hr == S_OK, "got 0x%08x\n", hr);
1406 ok(m.m11 == 0.0 && m.m22 == 0.0 && m.m12 == 0.0 && m.m21 == 0.0, "got %.1f,%.1f,%.1f,%.1f\n", m.m11, m.m22, m.m12, m.m21);
1407 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1408 ret = GetWorldTransform(hdc, &xform);
1409 ok(ret, "got %d\n", ret);
1410 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1411 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1413 memset(&m, 0, sizeof(m));
1414 m.m11 = 2.0; m.m22 = 1.0;
1415 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1416 ok(hr == S_OK, "got 0x%08x\n", hr);
1417 ret = GetWorldTransform(hdc, &xform);
1418 ok(ret, "got %d\n", ret);
1419 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1420 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1422 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, NULL);
1423 ok(hr == S_OK, "got 0x%08x\n", hr);
1425 memset(&m, 0xcc, sizeof(m));
1426 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1427 ok(hr == S_OK, "got 0x%08x\n", hr);
1428 ok(m.m11 == 1.0 && m.m22 == 1.0 && m.m12 == 0.0 && m.m21 == 0.0, "got %.1f,%.1f,%.1f,%.1f\n", m.m11, m.m22, m.m12, m.m21);
1429 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1431 /* pixels per dip */
1432 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1433 ok(pdip == 1.0, "got %.2f\n", pdip);
1435 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
1436 ok(hr == S_OK, "got 0x%08x\n", hr);
1438 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, -1.0);
1439 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1441 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 0.0);
1442 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1444 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1445 ok(pdip == 2.0, "got %.2f\n", pdip);
1447 hr = IDWriteBitmapRenderTarget_QueryInterface(target, &IID_IDWriteBitmapRenderTarget1, (void**)&target1);
1448 if (hr == S_OK) {
1449 DWRITE_TEXT_ANTIALIAS_MODE mode;
1451 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1452 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1454 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE+1);
1455 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1457 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1458 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1460 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
1461 ok(hr == S_OK, "got 0x%08x\n", hr);
1463 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1464 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, "got %d\n", mode);
1466 IDWriteBitmapRenderTarget1_Release(target1);
1468 else
1469 win_skip("IDWriteBitmapRenderTarget1 is not supported.\n");
1471 /* DrawGlyphRun() argument validation. */
1472 hr = IDWriteBitmapRenderTarget_Resize(target, 16, 16);
1473 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
1475 fontface = create_fontface(factory);
1477 ch = 'A';
1478 glyphs[0] = 0;
1479 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, glyphs);
1480 ok(hr == S_OK, "got 0x%08x\n", hr);
1481 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
1482 glyphs[1] = glyphs[0];
1484 memset(&run, 0, sizeof(run));
1485 run.fontFace = fontface;
1486 run.fontEmSize = 12.0f;
1487 run.glyphCount = 2;
1488 run.glyphIndices = glyphs;
1490 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
1491 DWRITE_RENDERING_MODE_DEFAULT, &params);
1492 ok(hr == S_OK, "Failed to create rendering params, hr %#x.\n", hr);
1494 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1495 &run, NULL, RGB(255, 0, 0), NULL);
1496 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1498 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1499 &run, NULL, RGB(255, 0, 0), NULL);
1500 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1502 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1503 &run, params, RGB(255, 0, 0), NULL);
1504 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Unexpected hr %#x.\n", hr);
1506 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL,
1507 &run, params, RGB(255, 0, 0), NULL);
1508 ok(hr == S_OK, "Failed to draw a run, hr %#x.\n", hr);
1510 IDWriteRenderingParams_Release(params);
1512 /* Zero sized target returns earlier. */
1513 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 16);
1514 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
1516 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1517 &run, NULL, RGB(255, 0, 0), NULL);
1518 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1520 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1521 &run, params, RGB(255, 0, 0), NULL);
1522 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1524 IDWriteFontFace_Release(fontface);
1526 ref = IDWriteBitmapRenderTarget_Release(target);
1527 ok(ref == 0, "render target not released, %u\n", ref);
1528 ref = IDWriteGdiInterop_Release(interop);
1529 ok(ref == 0, "interop not released, %u\n", ref);
1530 ref = IDWriteFactory_Release(factory);
1531 ok(ref == 0, "factory not released, %u\n", ref);
1534 static void test_GetFontFamily(void)
1536 IDWriteFontCollection *collection, *collection2;
1537 IDWriteFontCollection *syscoll;
1538 IDWriteFontCollection2 *coll2;
1539 IDWriteFontFamily *family, *family2;
1540 IDWriteFontFamily1 *family1;
1541 IDWriteGdiInterop *interop;
1542 IDWriteFont *font, *font2;
1543 IDWriteFactory *factory;
1544 LOGFONTW logfont;
1545 ULONG ref, count;
1546 HRESULT hr;
1548 factory = create_factory();
1550 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1551 EXPECT_HR(hr, S_OK);
1553 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1554 ok(hr == S_OK, "got 0x%08x\n", hr);
1556 memset(&logfont, 0, sizeof(logfont));
1557 logfont.lfHeight = 12;
1558 logfont.lfWidth = 12;
1559 logfont.lfWeight = FW_NORMAL;
1560 logfont.lfItalic = 1;
1561 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1563 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1564 ok(hr == S_OK, "got 0x%08x\n", hr);
1566 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1567 ok(hr == S_OK, "got 0x%08x\n", hr);
1568 ok(font2 != font, "got %p, %p\n", font2, font);
1570 if (0) /* crashes on native */
1571 hr = IDWriteFont_GetFontFamily(font, NULL);
1573 EXPECT_REF(font, 1);
1574 hr = IDWriteFont_GetFontFamily(font, &family);
1575 EXPECT_HR(hr, S_OK);
1576 EXPECT_REF(font, 1);
1577 EXPECT_REF(family, 2);
1579 hr = IDWriteFont_GetFontFamily(font, &family2);
1580 EXPECT_HR(hr, S_OK);
1581 ok(family2 == family, "got %p, previous %p\n", family2, family);
1582 EXPECT_REF(font, 1);
1583 EXPECT_REF(family, 3);
1584 IDWriteFontFamily_Release(family2);
1586 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
1587 EXPECT_HR(hr, E_NOINTERFACE);
1588 ok(family2 == NULL, "got %p\n", family2);
1590 hr = IDWriteFont_GetFontFamily(font2, &family2);
1591 ok(hr == S_OK, "got 0x%08x\n", hr);
1592 ok(family2 != family, "got %p, %p\n", family2, family);
1594 collection = NULL;
1595 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
1596 ok(hr == S_OK, "got 0x%08x\n", hr);
1598 collection2 = NULL;
1599 hr = IDWriteFontFamily_GetFontCollection(family2, &collection2);
1600 ok(hr == S_OK, "got 0x%08x\n", hr);
1601 ok(collection == collection2, "got %p, %p\n", collection, collection2);
1602 ok(collection == syscoll, "got %p, %p\n", collection, syscoll);
1604 IDWriteFont_Release(font);
1605 IDWriteFont_Release(font2);
1607 hr = IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily1, (void**)&family1);
1608 if (hr == S_OK) {
1609 IDWriteFontFaceReference *ref, *ref1;
1610 IDWriteFontList1 *fontlist1;
1611 IDWriteFontList2 *fontlist2;
1612 IDWriteFontList *fontlist;
1613 IDWriteFont3 *font3;
1614 IDWriteFont1 *font1;
1616 font3 = (void*)0xdeadbeef;
1617 hr = IDWriteFontFamily1_GetFont(family1, ~0u, &font3);
1618 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1619 ok(font3 == NULL, "got %p\n", font3);
1621 hr = IDWriteFontFamily1_GetFont(family1, 0, &font3);
1622 ok(hr == S_OK, "got 0x%08x\n", hr);
1624 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont, (void**)&font);
1625 ok(hr == S_OK, "got 0x%08x\n", hr);
1626 IDWriteFont_Release(font);
1628 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont1, (void**)&font1);
1629 ok(hr == S_OK, "got 0x%08x\n", hr);
1630 IDWriteFont1_Release(font1);
1632 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList1, (void **)&fontlist1);
1633 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Failed to get interface, hr %#x.\n", hr);
1634 if (hr == S_OK) {
1635 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void **)&fontlist);
1636 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1637 ok(fontlist == (IDWriteFontList *)fontlist1, "Unexpected interface pointer.\n");
1638 ok(fontlist != (IDWriteFontList *)family1, "Unexpected interface pointer.\n");
1639 ok(fontlist != (IDWriteFontList *)family, "Unexpected interface pointer.\n");
1641 if (SUCCEEDED(IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList2, (void **)&fontlist2)))
1643 IDWriteFontSet1 *fontset = NULL, *fontset2 = NULL;
1645 ok(fontlist == (IDWriteFontList *)fontlist2, "Unexpected interface pointer.\n");
1647 hr = IDWriteFontList2_GetFontSet(fontlist2, &fontset);
1648 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1650 hr = IDWriteFontList2_GetFontSet(fontlist2, &fontset2);
1651 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1652 ok(fontset != fontset2, "Unexpected instance.\n");
1654 IDWriteFontSet1_Release(fontset2);
1655 IDWriteFontSet1_Release(fontset);
1657 IDWriteFontList2_Release(fontlist2);
1659 else
1660 win_skip("IDWriteFontList2 is not supported.\n");
1662 IDWriteFontList1_Release(fontlist1);
1663 IDWriteFontList_Release(fontlist);
1666 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void**)&fontlist);
1667 ok(hr == S_OK, "got 0x%08x\n", hr);
1668 IDWriteFontList_Release(fontlist);
1670 IDWriteFont3_Release(font3);
1672 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref);
1673 ok(hr == S_OK, "got 0x%08x\n", hr);
1675 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref1);
1676 ok(hr == S_OK, "got 0x%08x\n", hr);
1677 ok(ref != ref1, "got %p, %p\n", ref, ref1);
1679 IDWriteFontFaceReference_Release(ref);
1680 IDWriteFontFaceReference_Release(ref1);
1682 IDWriteFontFamily1_Release(family1);
1684 else
1685 win_skip("IDWriteFontFamily1 is not supported.\n");
1687 /* IDWriteFontCollection2::GetFontFamily() */
1688 if (SUCCEEDED(IDWriteFontCollection_QueryInterface(syscoll, &IID_IDWriteFontCollection2, (void **)&coll2)))
1690 IDWriteFontFamily2 *family2;
1692 count = IDWriteFontCollection2_GetFontFamilyCount(coll2);
1693 ok(!!count, "Unexpected family count.\n");
1695 family2 = (void *)0xdeadbeef;
1696 hr = IDWriteFontCollection2_GetFontFamily(coll2, count, &family2);
1697 ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
1698 ok(!family2, "Unexpected pointer.\n");
1700 hr = IDWriteFontCollection2_GetFontFamily(coll2, 0, &family2);
1701 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
1702 IDWriteFontFamily2_Release(family2);
1704 IDWriteFontCollection2_Release(coll2);
1706 else
1707 win_skip("IDWriteFontCollection2 is not supported.\n");
1709 IDWriteFontCollection_Release(syscoll);
1710 IDWriteFontCollection_Release(collection2);
1711 IDWriteFontCollection_Release(collection);
1712 IDWriteFontFamily_Release(family2);
1713 IDWriteFontFamily_Release(family);
1714 IDWriteGdiInterop_Release(interop);
1715 ref = IDWriteFactory_Release(factory);
1716 ok(ref == 0, "factory not released, %u\n", ref);
1719 static void test_GetFamilyNames(void)
1721 IDWriteLocalizedStrings *names, *names2;
1722 IDWriteFontFace3 *fontface3;
1723 IDWriteGdiInterop *interop;
1724 IDWriteFontFamily *family;
1725 IDWriteFontFace *fontface;
1726 IDWriteFactory *factory;
1727 IDWriteFont *font;
1728 LOGFONTW logfont;
1729 WCHAR buffer[100];
1730 HRESULT hr;
1731 UINT32 len;
1732 ULONG ref;
1734 factory = create_factory();
1736 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1737 EXPECT_HR(hr, S_OK);
1739 memset(&logfont, 0, sizeof(logfont));
1740 logfont.lfHeight = 12;
1741 logfont.lfWidth = 12;
1742 logfont.lfWeight = FW_NORMAL;
1743 logfont.lfItalic = 1;
1744 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1746 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1747 EXPECT_HR(hr, S_OK);
1749 hr = IDWriteFont_GetFontFamily(font, &family);
1750 EXPECT_HR(hr, S_OK);
1752 if (0) /* crashes on native */
1753 hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
1755 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1756 ok(hr == S_OK, "got 0x%08x\n", hr);
1757 EXPECT_REF(names, 1);
1759 hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
1760 ok(hr == S_OK, "got 0x%08x\n", hr);
1761 EXPECT_REF(names2, 1);
1762 ok(names != names2, "got %p, was %p\n", names2, names);
1764 IDWriteLocalizedStrings_Release(names2);
1766 /* GetStringLength */
1767 if (0) /* crashes on native */
1768 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
1770 len = 100;
1771 hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
1772 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1773 ok(len == (UINT32)-1, "got %u\n", len);
1775 len = 0;
1776 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
1777 ok(hr == S_OK, "got 0x%08x\n", hr);
1778 ok(len > 0, "got %u\n", len);
1780 /* GetString */
1781 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
1782 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1784 hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
1785 ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
1787 if (0)
1788 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
1790 buffer[0] = 1;
1791 hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
1792 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1793 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1795 buffer[0] = 1;
1796 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
1797 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1798 ok(buffer[0] == 0 || broken(buffer[0] == 'T'), "Unexpected buffer contents, %#x.\n", buffer[0]);
1800 buffer[0] = 1;
1801 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
1802 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1803 ok(buffer[0] == 0 || broken(buffer[0] == 'T'), "Unexpected buffer contents, %#x.\n", buffer[0]);
1805 buffer[0] = 0;
1806 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1807 ok(hr == S_OK, "Failed to get a string, hr %#x.\n", hr);
1808 ok(!lstrcmpW(buffer, L"Tahoma"), "Unexpected family name %s.\n", wine_dbgstr_w(buffer));
1810 IDWriteLocalizedStrings_Release(names);
1812 /* GetFamilyNames() on font face */
1813 hr = IDWriteFont_CreateFontFace(font, &fontface);
1814 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
1816 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
1818 hr = IDWriteFontFace3_GetFamilyNames(fontface3, &names);
1819 ok(hr == S_OK, "Failed to get family names, hr %#x.\n", hr);
1821 buffer[0] = 0;
1822 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1823 ok(hr == S_OK, "Failed to get a string, hr %#x.\n", hr);
1824 ok(!lstrcmpW(buffer, L"Tahoma"), "Unexpected family name %s.\n", wine_dbgstr_w(buffer));
1826 IDWriteLocalizedStrings_Release(names);
1827 IDWriteFontFace3_Release(fontface3);
1829 else
1830 win_skip("IDWriteFontFace3::GetFamilyNames() is not supported.\n");
1832 IDWriteFontFace_Release(fontface);
1834 IDWriteFontFamily_Release(family);
1835 IDWriteFont_Release(font);
1836 IDWriteGdiInterop_Release(interop);
1837 ref = IDWriteFactory_Release(factory);
1838 ok(ref == 0, "factory not released, %u\n", ref);
1841 static void test_CreateFontFace(void)
1843 IDWriteFontFace *fontface, *fontface2;
1844 IDWriteFontCollection *collection;
1845 DWRITE_FONT_FILE_TYPE file_type;
1846 DWRITE_FONT_FACE_TYPE face_type;
1847 IDWriteFontFace5 *fontface5;
1848 IDWriteGdiInterop *interop;
1849 IDWriteFont *font, *font2;
1850 IDWriteFontFamily *family;
1851 IDWriteFactory *factory;
1852 IDWriteFontFile *file;
1853 BOOL supported, ret;
1854 LOGFONTW logfont;
1855 UINT32 count;
1856 WCHAR *path;
1857 HRESULT hr;
1858 ULONG ref;
1860 factory = create_factory();
1862 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1863 EXPECT_HR(hr, S_OK);
1865 memset(&logfont, 0, sizeof(logfont));
1866 logfont.lfHeight = 12;
1867 logfont.lfWidth = 12;
1868 logfont.lfWeight = FW_NORMAL;
1869 logfont.lfItalic = 1;
1870 lstrcpyW(logfont.lfFaceName, L"Tahoma");
1872 font = NULL;
1873 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1874 ok(hr == S_OK, "got 0x%08x\n", hr);
1876 font2 = NULL;
1877 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1878 ok(hr == S_OK, "got 0x%08x\n", hr);
1879 ok(font != font2, "got %p, %p\n", font, font2);
1881 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
1882 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1884 if (0) /* crashes on native */
1885 hr = IDWriteFont_CreateFontFace(font, NULL);
1887 fontface = NULL;
1888 hr = IDWriteFont_CreateFontFace(font, &fontface);
1889 ok(hr == S_OK, "got 0x%08x\n", hr);
1891 fontface2 = NULL;
1892 hr = IDWriteFont_CreateFontFace(font, &fontface2);
1893 ok(hr == S_OK, "got 0x%08x\n", hr);
1894 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1895 IDWriteFontFace_Release(fontface2);
1897 fontface2 = NULL;
1898 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1899 ok(hr == S_OK, "got 0x%08x\n", hr);
1900 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1901 IDWriteFontFace_Release(fontface2);
1903 IDWriteFont_Release(font2);
1904 IDWriteFont_Release(font);
1906 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFont, (void**)&font);
1907 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL), "got 0x%08x\n", hr);
1909 IDWriteFontFace_Release(fontface);
1910 IDWriteGdiInterop_Release(interop);
1912 /* Create from system collection */
1913 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1914 ok(hr == S_OK, "got 0x%08x\n", hr);
1916 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
1917 ok(hr == S_OK, "got 0x%08x\n", hr);
1919 font = NULL;
1920 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1921 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1922 ok(hr == S_OK, "got 0x%08x\n", hr);
1924 font2 = NULL;
1925 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1926 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
1927 ok(hr == S_OK, "got 0x%08x\n", hr);
1928 ok(font != font2, "got %p, %p\n", font, font2);
1930 fontface = NULL;
1931 hr = IDWriteFont_CreateFontFace(font, &fontface);
1932 ok(hr == S_OK, "got 0x%08x\n", hr);
1934 fontface2 = NULL;
1935 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1936 ok(hr == S_OK, "got 0x%08x\n", hr);
1937 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1939 /* Trivial equality test */
1940 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5)))
1942 ret = IDWriteFontFace5_Equals(fontface5, fontface2);
1943 ok(ret, "Unexpected result %d.\n", ret);
1944 IDWriteFontFace5_Release(fontface5);
1947 IDWriteFontFace_Release(fontface);
1948 IDWriteFontFace_Release(fontface2);
1949 IDWriteFont_Release(font2);
1950 IDWriteFont_Release(font);
1951 IDWriteFontFamily_Release(family);
1952 IDWriteFontCollection_Release(collection);
1953 ref = IDWriteFactory_Release(factory);
1954 ok(ref == 0, "factory not released, %u.\n", ref);
1956 /* IDWriteFactory::CreateFontFace() */
1957 path = create_testfontfile(test_fontfile);
1958 factory = create_factory();
1960 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
1961 ok(hr == S_OK, "got 0x%08x\n",hr);
1963 supported = FALSE;
1964 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1965 face_type = DWRITE_FONT_FACE_TYPE_CFF;
1966 count = 0;
1967 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &count);
1968 ok(hr == S_OK, "got 0x%08x\n", hr);
1969 ok(supported == TRUE, "got %i\n", supported);
1970 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
1971 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
1972 ok(count == 1, "got %i\n", count);
1974 /* invalid simulation flags */
1975 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, ~0u, &fontface);
1976 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1978 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0xf, &fontface);
1979 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1981 /* try mismatching face type, the one that's not supported */
1982 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1983 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
1985 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, 1, &file, 0,
1986 DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1987 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* < win10 */, "got 0x%08x\n", hr);
1989 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_RAW_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1990 todo_wine
1991 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == E_INVALIDARG) /* older versions */, "got 0x%08x\n", hr);
1993 fontface = (void*)0xdeadbeef;
1994 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TYPE1, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1995 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1996 ok(fontface == NULL, "got %p\n", fontface);
1998 fontface = (void*)0xdeadbeef;
1999 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_VECTOR, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2000 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2001 ok(fontface == NULL, "got %p\n", fontface);
2003 fontface = (void*)0xdeadbeef;
2004 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_BITMAP, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2005 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2006 ok(fontface == NULL, "got %p\n", fontface);
2008 fontface = NULL;
2009 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_UNKNOWN, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2010 todo_wine
2011 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* < win10 */, "got 0x%08x\n", hr);
2012 if (hr == S_OK) {
2013 ok(fontface != NULL, "got %p\n", fontface);
2014 face_type = IDWriteFontFace_GetType(fontface);
2015 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %d\n", face_type);
2016 IDWriteFontFace_Release(fontface);
2019 IDWriteFontFile_Release(file);
2020 ref = IDWriteFactory_Release(factory);
2021 ok(ref == 0, "factory not released, %u.\n", ref);
2022 DELETE_FONTFILE(path);
2025 static void get_expected_font_metrics(IDWriteFontFace *fontface, DWRITE_FONT_METRICS1 *metrics)
2027 void *os2_context, *head_context, *post_context, *hhea_context;
2028 const TT_OS2_V2 *tt_os2;
2029 const TT_HEAD *tt_head;
2030 const TT_POST *tt_post;
2031 const TT_HHEA *tt_hhea;
2032 UINT32 size;
2033 BOOL exists;
2034 HRESULT hr;
2036 memset(metrics, 0, sizeof(*metrics));
2038 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
2039 ok(hr == S_OK, "got 0x%08x\n", hr);
2040 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void**)&tt_head, &size, &head_context, &exists);
2041 ok(hr == S_OK, "got 0x%08x\n", hr);
2042 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HHEA_TAG, (const void**)&tt_hhea, &size, &hhea_context, &exists);
2043 ok(hr == S_OK, "got 0x%08x\n", hr);
2044 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_POST_TAG, (const void**)&tt_post, &size, &post_context, &exists);
2045 ok(hr == S_OK, "got 0x%08x\n", hr);
2047 if (tt_head) {
2048 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
2049 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
2050 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
2051 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
2052 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
2055 if (tt_os2) {
2056 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
2057 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
2058 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
2059 metrics->descent = descent < 0 ? -descent : 0;
2060 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
2061 metrics->hasTypographicMetrics = TRUE;
2063 else {
2064 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
2065 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
2066 interpreted as large unsigned value. */
2067 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
2069 if (tt_hhea) {
2070 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
2071 INT32 linegap;
2073 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
2074 metrics->ascent - metrics->descent;
2075 metrics->lineGap = linegap > 0 ? linegap : 0;
2079 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
2080 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
2082 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
2083 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
2084 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
2085 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
2086 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
2087 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
2088 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
2089 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
2091 else {
2092 metrics->strikethroughPosition = metrics->designUnitsPerEm / 3;
2093 if (tt_hhea) {
2094 metrics->ascent = GET_BE_WORD(tt_hhea->ascender);
2095 metrics->descent = abs((SHORT)GET_BE_WORD(tt_hhea->descender));
2099 if (tt_post) {
2100 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
2101 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
2104 if (metrics->underlineThickness == 0)
2105 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
2106 if (metrics->strikethroughThickness == 0)
2107 metrics->strikethroughThickness = metrics->underlineThickness;
2109 if (tt_os2)
2110 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2111 if (tt_head)
2112 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2113 if (tt_hhea)
2114 IDWriteFontFace_ReleaseFontTable(fontface, hhea_context);
2115 if (tt_post)
2116 IDWriteFontFace_ReleaseFontTable(fontface, post_context);
2119 static void check_font_metrics(const WCHAR *nameW, IDWriteFontFace *fontface, const DWRITE_FONT_METRICS1 *expected)
2121 IDWriteFontFace1 *fontface1 = NULL;
2122 DWRITE_FONT_METRICS1 metrics;
2123 DWORD simulations;
2124 BOOL has_metrics1;
2126 has_metrics1 = SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1));
2127 simulations = IDWriteFontFace_GetSimulations(fontface);
2129 if (fontface1) {
2130 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
2131 IDWriteFontFace1_Release(fontface1);
2133 else
2134 IDWriteFontFace_GetMetrics(fontface, (DWRITE_FONT_METRICS *)&metrics);
2136 ok(metrics.designUnitsPerEm == expected->designUnitsPerEm, "font %s: designUnitsPerEm %u, expected %u\n",
2137 wine_dbgstr_w(nameW), metrics.designUnitsPerEm, expected->designUnitsPerEm);
2138 ok(metrics.ascent == expected->ascent, "font %s: ascent %u, expected %u\n", wine_dbgstr_w(nameW), metrics.ascent,
2139 expected->ascent);
2140 ok(metrics.descent == expected->descent, "font %s: descent %u, expected %u\n", wine_dbgstr_w(nameW),
2141 metrics.descent, expected->descent);
2142 ok(metrics.lineGap == expected->lineGap, "font %s: lineGap %d, expected %d\n", wine_dbgstr_w(nameW),
2143 metrics.lineGap, expected->lineGap);
2144 ok(metrics.underlinePosition == expected->underlinePosition, "font %s: underlinePosition %d, expected %d\n",
2145 wine_dbgstr_w(nameW), metrics.underlinePosition, expected->underlinePosition);
2146 ok(metrics.underlineThickness == expected->underlineThickness, "font %s: underlineThickness %u, "
2147 "expected %u\n", wine_dbgstr_w(nameW), metrics.underlineThickness, expected->underlineThickness);
2148 ok(metrics.strikethroughPosition == expected->strikethroughPosition, "font %s: strikethroughPosition %d, expected %d\n",
2149 wine_dbgstr_w(nameW), metrics.strikethroughPosition, expected->strikethroughPosition);
2150 ok(metrics.strikethroughThickness == expected->strikethroughThickness, "font %s: strikethroughThickness %u, "
2151 "expected %u\n", wine_dbgstr_w(nameW), metrics.strikethroughThickness, expected->strikethroughThickness);
2153 if (has_metrics1) {
2154 /* For simulated faces metrics are adjusted. Enable tests when exact pattern is understood. */
2155 if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2156 return;
2158 ok(metrics.hasTypographicMetrics == expected->hasTypographicMetrics, "font %s: hasTypographicMetrics %d, "
2159 "expected %d\n", wine_dbgstr_w(nameW), metrics.hasTypographicMetrics, expected->hasTypographicMetrics);
2160 ok(metrics.glyphBoxLeft == expected->glyphBoxLeft, "font %s: glyphBoxLeft %d, expected %d\n",
2161 wine_dbgstr_w(nameW), metrics.glyphBoxLeft, expected->glyphBoxLeft);
2162 ok(metrics.glyphBoxTop == expected->glyphBoxTop, "font %s: glyphBoxTop %d, expected %d\n",
2163 wine_dbgstr_w(nameW), metrics.glyphBoxTop, expected->glyphBoxTop);
2164 ok(metrics.glyphBoxRight == expected->glyphBoxRight, "font %s: glyphBoxRight %d, expected %d\n",
2165 wine_dbgstr_w(nameW), metrics.glyphBoxRight, expected->glyphBoxRight);
2166 ok(metrics.glyphBoxBottom == expected->glyphBoxBottom, "font %s: glyphBoxBottom %d, expected %d\n",
2167 wine_dbgstr_w(nameW), metrics.glyphBoxBottom, expected->glyphBoxBottom);
2169 ok(metrics.subscriptPositionX == expected->subscriptPositionX, "font %s: subscriptPositionX %d, expected %d\n",
2170 wine_dbgstr_w(nameW), metrics.subscriptPositionX, expected->subscriptPositionX);
2171 ok(metrics.subscriptPositionY == expected->subscriptPositionY, "font %s: subscriptPositionY %d, expected %d\n",
2172 wine_dbgstr_w(nameW), metrics.subscriptPositionY, expected->subscriptPositionY);
2173 ok(metrics.subscriptSizeX == expected->subscriptSizeX, "font %s: subscriptSizeX %d, expected %d\n",
2174 wine_dbgstr_w(nameW), metrics.subscriptSizeX, expected->subscriptSizeX);
2175 ok(metrics.subscriptSizeY == expected->subscriptSizeY, "font %s: subscriptSizeY %d, expected %d\n",
2176 wine_dbgstr_w(nameW), metrics.subscriptSizeY, expected->subscriptSizeY);
2177 ok(metrics.superscriptPositionX == expected->superscriptPositionX, "font %s: superscriptPositionX %d, expected %d\n",
2178 wine_dbgstr_w(nameW), metrics.superscriptPositionX, expected->superscriptPositionX);
2179 ok(metrics.superscriptPositionY == expected->superscriptPositionY, "font %s: superscriptPositionY %d, expected %d\n",
2180 wine_dbgstr_w(nameW), metrics.superscriptPositionY, expected->superscriptPositionY);
2181 ok(metrics.superscriptSizeX == expected->superscriptSizeX, "font %s: superscriptSizeX %d, expected %d\n",
2182 wine_dbgstr_w(nameW), metrics.superscriptSizeX, expected->superscriptSizeX);
2183 ok(metrics.superscriptSizeY == expected->superscriptSizeY, "font %s: superscriptSizeY %d, expected %d\n",
2184 wine_dbgstr_w(nameW), metrics.superscriptSizeY, expected->superscriptSizeY);
2188 static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
2190 BOOL exists = FALSE;
2191 UINT32 index;
2192 HRESULT hr;
2194 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
2195 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
2196 if (!exists)
2197 index = 0;
2198 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
2199 ok(hr == S_OK, "got 0x%08x\n", hr);
2202 static void test_GetMetrics(void)
2204 DWRITE_FONT_METRICS metrics, metrics2;
2205 IDWriteFontCollection *syscollection;
2206 IDWriteGdiInterop *interop;
2207 IDWriteFontFace *fontface;
2208 IDWriteFactory *factory;
2209 OUTLINETEXTMETRICW otm;
2210 IDWriteFontFile *file;
2211 IDWriteFont1 *font1;
2212 IDWriteFont *font;
2213 LOGFONTW logfont;
2214 UINT32 count, i;
2215 HRESULT hr;
2216 HDC hdc;
2217 HFONT hfont;
2218 ULONG ref;
2219 int ret;
2221 factory = create_factory();
2223 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2224 EXPECT_HR(hr, S_OK);
2226 memset(&logfont, 0, sizeof(logfont));
2227 logfont.lfHeight = 12;
2228 logfont.lfWidth = 12;
2229 logfont.lfWeight = FW_NORMAL;
2230 logfont.lfItalic = 1;
2231 lstrcpyW(logfont.lfFaceName, L"Tahoma");
2233 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2234 ok(hr == S_OK, "got 0x%08x\n", hr);
2236 hfont = CreateFontIndirectW(&logfont);
2237 hdc = CreateCompatibleDC(0);
2238 SelectObject(hdc, hfont);
2240 otm.otmSize = sizeof(otm);
2241 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
2242 ok(ret, "got %d\n", ret);
2243 DeleteDC(hdc);
2244 DeleteObject(hfont);
2246 if (0) /* crashes on native */
2247 IDWriteFont_GetMetrics(font, NULL);
2249 memset(&metrics, 0, sizeof(metrics));
2250 IDWriteFont_GetMetrics(font, &metrics);
2252 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2253 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2254 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2255 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2256 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2257 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2258 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2259 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2260 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2261 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2263 hr = IDWriteFont_CreateFontFace(font, &fontface);
2264 ok(hr == S_OK, "got 0x%08x\n", hr);
2266 memset(&metrics, 0, sizeof(metrics));
2267 IDWriteFontFace_GetMetrics(fontface, &metrics);
2269 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2270 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2271 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2272 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2273 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2274 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2275 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2276 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2277 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2278 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2280 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
2281 if (hr == S_OK) {
2282 DWRITE_FONT_METRICS1 metrics1;
2283 IDWriteFontFace1 *fontface1;
2285 memset(&metrics1, 0, sizeof(metrics1));
2286 IDWriteFont1_GetMetrics(font1, &metrics1);
2288 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2289 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2290 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2291 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2292 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2293 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2294 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2295 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2296 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2297 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2298 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2299 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2300 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2301 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2302 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2303 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2304 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2305 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2306 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2307 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2308 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2310 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2311 ok(hr == S_OK, "got 0x%08x\n", hr);
2313 memset(&metrics1, 0, sizeof(metrics1));
2314 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2316 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2317 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2318 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2319 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2320 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2321 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2322 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2323 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2324 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2325 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2326 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2327 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2328 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2329 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2330 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2331 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2332 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2333 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2334 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2335 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2336 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2338 IDWriteFontFace1_Release(fontface1);
2339 IDWriteFont1_Release(font1);
2341 else
2342 win_skip("DWRITE_FONT_METRICS1 is not supported.\n");
2344 IDWriteFontFace_Release(fontface);
2345 IDWriteFont_Release(font);
2346 IDWriteGdiInterop_Release(interop);
2348 /* bold simulation affects returned font metrics */
2349 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
2351 /* create regulat Tahoma with bold simulation */
2352 hr = IDWriteFont_CreateFontFace(font, &fontface);
2353 ok(hr == S_OK, "got 0x%08x\n", hr);
2355 count = 1;
2356 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
2357 ok(hr == S_OK, "got 0x%08x\n", hr);
2359 IDWriteFontFace_GetMetrics(fontface, &metrics);
2360 ok(IDWriteFontFace_GetSimulations(fontface) == 0, "wrong simulations flags\n");
2361 IDWriteFontFace_Release(fontface);
2363 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
2364 0, DWRITE_FONT_SIMULATIONS_BOLD, &fontface);
2365 ok(hr == S_OK, "got 0x%08x\n", hr);
2366 IDWriteFontFace_GetMetrics(fontface, &metrics2);
2367 ok(IDWriteFontFace_GetSimulations(fontface) == DWRITE_FONT_SIMULATIONS_BOLD, "wrong simulations flags\n");
2369 ok(metrics.ascent == metrics2.ascent, "got %u, %u\n", metrics2.ascent, metrics.ascent);
2370 ok(metrics.descent == metrics2.descent, "got %u, %u\n", metrics2.descent, metrics.descent);
2371 ok(metrics.lineGap == metrics2.lineGap, "got %d, %d\n", metrics2.lineGap, metrics.lineGap);
2372 ok(metrics.capHeight == metrics2.capHeight, "got %u, %u\n", metrics2.capHeight, metrics.capHeight);
2373 ok(metrics.xHeight == metrics2.xHeight, "got %u, %u\n", metrics2.xHeight, metrics.xHeight);
2374 ok(metrics.underlinePosition == metrics2.underlinePosition, "got %d, %d\n", metrics2.underlinePosition,
2375 metrics.underlinePosition);
2376 ok(metrics.underlineThickness == metrics2.underlineThickness, "got %u, %u\n", metrics2.underlineThickness,
2377 metrics.underlineThickness);
2378 ok(metrics.strikethroughPosition == metrics2.strikethroughPosition, "got %d, %d\n", metrics2.strikethroughPosition,
2379 metrics.strikethroughPosition);
2380 ok(metrics.strikethroughThickness == metrics2.strikethroughThickness, "got %u, %u\n", metrics2.strikethroughThickness,
2381 metrics.strikethroughThickness);
2383 IDWriteFontFile_Release(file);
2384 IDWriteFontFace_Release(fontface);
2385 IDWriteFont_Release(font);
2387 /* test metrics for whole system collection */
2388 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
2389 ok(hr == S_OK, "got 0x%08x\n", hr);
2390 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
2392 for (i = 0; i < count; i++) {
2393 DWRITE_FONT_METRICS1 expected_metrics;
2394 WCHAR familyW[256], faceW[256];
2395 IDWriteLocalizedStrings *names;
2396 IDWriteFontFamily *family;
2397 UINT32 fontcount, j;
2398 IDWriteFont *font;
2400 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
2401 ok(hr == S_OK, "got 0x%08x\n", hr);
2403 fontcount = IDWriteFontFamily_GetFontCount(family);
2405 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2406 ok(hr == S_OK, "Failed to get family names, hr %#x.\n", hr);
2407 get_enus_string(names, familyW, ARRAY_SIZE(familyW));
2408 IDWriteLocalizedStrings_Release(names);
2410 for (j = 0; j < fontcount; j++) {
2411 WCHAR nameW[256];
2413 hr = IDWriteFontFamily_GetFont(family, j, &font);
2414 ok(hr == S_OK, "Failed to get a font, hr %#x.\n", hr);
2416 hr = IDWriteFont_CreateFontFace(font, &fontface);
2417 ok(hr == S_OK, "Failed to create face instance, hr %#x.\n", hr);
2419 hr = IDWriteFont_GetFaceNames(font, &names);
2420 ok(hr == S_OK, "Failed to get face names, hr %#x.\n", hr);
2421 get_enus_string(names, faceW, ARRAY_SIZE(faceW));
2422 IDWriteLocalizedStrings_Release(names);
2424 IDWriteFont_Release(font);
2426 get_combined_font_name(familyW, faceW, nameW);
2428 if (has_face_variations(fontface))
2430 static int once;
2431 if (!once++)
2432 skip("GetMetrics() test does not support variable fonts.\n");
2433 IDWriteFontFace_Release(fontface);
2434 continue;
2437 get_expected_font_metrics(fontface, &expected_metrics);
2438 check_font_metrics(nameW, fontface, &expected_metrics);
2440 IDWriteFontFace_Release(fontface);
2443 IDWriteFontFamily_Release(family);
2445 IDWriteFontCollection_Release(syscollection);
2446 ref = IDWriteFactory_Release(factory);
2447 ok(ref == 0, "factory not released, %u\n", ref);
2450 static void test_system_fontcollection(void)
2452 IDWriteFontCollection *collection, *coll2;
2453 IDWriteLocalFontFileLoader *localloader;
2454 IDWriteFontCollection1 *collection1;
2455 IDWriteFontCollection2 *collection2;
2456 IDWriteFontCollection3 *collection3;
2457 IDWriteFactory *factory, *factory2;
2458 IDWriteFontFileLoader *loader;
2459 IDWriteFontFamily *family;
2460 IDWriteFontFace *fontface;
2461 IDWriteFactory6 *factory6;
2462 IDWriteFontFile *file;
2463 IDWriteFont *font;
2464 HRESULT hr;
2465 ULONG ref;
2466 UINT32 i;
2467 BOOL ret;
2469 factory = create_factory();
2471 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2472 ok(hr == S_OK, "got 0x%08x\n", hr);
2474 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, FALSE);
2475 ok(hr == S_OK, "got 0x%08x\n", hr);
2476 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2477 IDWriteFontCollection_Release(coll2);
2479 factory2 = create_factory();
2480 hr = IDWriteFactory_GetSystemFontCollection(factory2, &coll2, FALSE);
2481 ok(hr == S_OK, "got 0x%08x\n", hr);
2482 ok(coll2 != collection, "got %p, was %p\n", coll2, collection);
2483 IDWriteFontCollection_Release(coll2);
2484 IDWriteFactory_Release(factory2);
2486 i = IDWriteFontCollection_GetFontFamilyCount(collection);
2487 ok(i, "got %u\n", i);
2489 /* invalid index */
2490 family = (void*)0xdeadbeef;
2491 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2492 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2493 ok(family == NULL, "got %p\n", family);
2495 ret = FALSE;
2496 i = (UINT32)-1;
2497 hr = IDWriteFontCollection_FindFamilyName(collection, L"Tahoma", &i, &ret);
2498 ok(hr == S_OK, "got 0x%08x\n", hr);
2499 ok(ret, "got %d\n", ret);
2500 ok(i != (UINT32)-1, "got %u\n", i);
2502 ret = FALSE;
2503 i = (UINT32)-1;
2504 hr = IDWriteFontCollection_FindFamilyName(collection, L"TAHOMA", &i, &ret);
2505 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
2506 ok(ret, "got %d\n", ret);
2507 ok(i != (UINT32)-1, "got %u\n", i);
2509 ret = FALSE;
2510 i = (UINT32)-1;
2511 hr = IDWriteFontCollection_FindFamilyName(collection, L"tAhOmA", &i, &ret);
2512 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
2513 ok(ret, "got %d\n", ret);
2514 ok(i != (UINT32)-1, "got %u\n", i);
2516 /* get back local file loader */
2517 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2518 ok(hr == S_OK, "got 0x%08x\n", hr);
2520 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2521 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2522 ok(hr == S_OK, "got 0x%08x\n", hr);
2523 IDWriteFontFamily_Release(family);
2525 hr = IDWriteFont_CreateFontFace(font, &fontface);
2526 ok(hr == S_OK, "got 0x%08x\n", hr);
2527 IDWriteFont_Release(font);
2529 i = 1;
2530 file = NULL;
2531 hr = IDWriteFontFace_GetFiles(fontface, &i, &file);
2532 ok(hr == S_OK, "got 0x%08x\n", hr);
2533 ok(file != NULL, "got %p\n", file);
2534 IDWriteFontFace_Release(fontface);
2536 hr = IDWriteFontFile_GetLoader(file, &loader);
2537 ok(hr == S_OK, "got 0x%08x\n", hr);
2538 IDWriteFontFile_Release(file);
2540 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2541 ok(hr == S_OK, "got 0x%08x\n", hr);
2542 IDWriteLocalFontFileLoader_Release(localloader);
2544 /* local loader is not registered by default */
2545 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
2546 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2547 hr = IDWriteFactory_UnregisterFontFileLoader(factory, loader);
2548 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2550 /* try with a different factory */
2551 factory2 = create_factory();
2552 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2553 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2554 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2555 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2556 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2557 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2558 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2559 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2560 IDWriteFactory_Release(factory2);
2562 IDWriteFontFileLoader_Release(loader);
2564 ret = TRUE;
2565 i = 0;
2566 hr = IDWriteFontCollection_FindFamilyName(collection, L"Blah!", &i, &ret);
2567 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
2568 ok(!ret, "got %d\n", ret);
2569 ok(i == (UINT32)-1, "got %u\n", i);
2571 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection1, (void**)&collection1);
2572 if (hr == S_OK) {
2573 IDWriteFontSet *fontset, *fontset2;
2574 IDWriteFontFamily1 *family1;
2575 IDWriteFactory3 *factory3;
2577 hr = IDWriteFontCollection1_QueryInterface(collection1, &IID_IDWriteFontCollection, (void**)&coll2);
2578 ok(hr == S_OK, "got 0x%08x\n", hr);
2579 ok(coll2 == collection, "got %p, %p\n", collection, coll2);
2580 IDWriteFontCollection_Release(coll2);
2582 family1 = (void*)0xdeadbeef;
2583 hr = IDWriteFontCollection1_GetFontFamily(collection1, ~0u, &family1);
2584 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2585 ok(family1 == NULL, "got %p\n", family1);
2587 hr = IDWriteFontCollection1_GetFontFamily(collection1, 0, &family1);
2588 ok(hr == S_OK, "got 0x%08x\n", hr);
2589 IDWriteFontFamily1_Release(family1);
2591 /* system fontset */
2592 EXPECT_REF(collection1, 2);
2593 EXPECT_REF(factory, 2);
2594 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset);
2595 todo_wine
2596 ok(hr == S_OK, "Failed to get fontset, hr %#x.\n", hr);
2597 if (hr == S_OK) {
2598 EXPECT_REF(collection1, 2);
2599 EXPECT_REF(factory, 2);
2600 EXPECT_REF(fontset, 1);
2602 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset2);
2603 ok(hr == S_OK, "Failed to get fontset, hr %#x.\n", hr);
2604 ok(fontset != fontset2, "Expected new fontset instance.\n");
2605 EXPECT_REF(fontset2, 1);
2606 IDWriteFontSet_Release(fontset2);
2608 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3);
2609 ok(hr == S_OK, "Failed to get IDWriteFactory3 interface, hr %#x.\n", hr);
2611 EXPECT_REF(factory, 3);
2612 hr = IDWriteFactory3_GetSystemFontSet(factory3, &fontset2);
2613 ok(hr == S_OK, "Failed to get system font set, hr %#x.\n", hr);
2614 ok(fontset != fontset2, "Expected new fontset instance.\n");
2615 EXPECT_REF(fontset2, 1);
2616 EXPECT_REF(factory, 4);
2618 IDWriteFontSet_Release(fontset2);
2619 IDWriteFontSet_Release(fontset);
2621 IDWriteFactory3_Release(factory3);
2623 IDWriteFontCollection1_Release(collection1);
2625 else
2626 win_skip("IDWriteFontCollection1 is not supported.\n");
2628 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
2629 if (SUCCEEDED(hr))
2631 HANDLE event;
2633 event = IDWriteFontCollection3_GetExpirationEvent(collection3);
2634 todo_wine
2635 ok(!!event, "Expected event handle.\n");
2637 check_familymodel(collection3, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE);
2639 IDWriteFontCollection3_Release(collection3);
2641 else
2642 win_skip("IDWriteFontCollection3 is not supported.\n");
2644 /* With specified family model. */
2645 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory6, (void **)&factory6);
2646 if (SUCCEEDED(hr))
2648 IDWriteFontCollection2 *c2;
2650 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
2651 &collection2);
2652 todo_wine
2653 ok(hr == S_OK, "Failed to get collection, hr %#x.\n", hr);
2654 if (SUCCEEDED(hr))
2656 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC, &c2);
2657 ok(hr == S_OK, "Failed to get collection, hr %#x.\n", hr);
2658 ok(c2 == collection2 && collection != (IDWriteFontCollection *)c2, "Unexpected collection instance.\n");
2659 IDWriteFontCollection2_Release(c2);
2660 IDWriteFontCollection2_Release(collection2);
2662 hr = IDWriteFactory6_GetSystemFontCollection(factory6, FALSE, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE,
2663 &collection2);
2664 ok(hr == S_OK, "Failed to get collection, hr %#x.\n", hr);
2665 IDWriteFontCollection2_Release(collection2);
2667 IDWriteFactory6_Release(factory6);
2669 else
2670 win_skip("IDWriteFactory6 is not supported.\n");
2672 ref = IDWriteFontCollection_Release(collection);
2673 ok(!ref, "Collection wasn't released, %u.\n", ref);
2674 ref = IDWriteFactory_Release(factory);
2675 ok(!ref, "Factory wasn't released, %u.\n", ref);
2678 static void get_logfont_from_font(IDWriteFont *font, LOGFONTW *logfont)
2680 void *os2_context, *head_context;
2681 IDWriteLocalizedStrings *names;
2682 DWRITE_FONT_SIMULATIONS sim;
2683 IDWriteFontFace *fontface;
2684 const TT_OS2_V2 *tt_os2;
2685 DWRITE_FONT_STYLE style;
2686 const TT_HEAD *tt_head;
2687 LONG weight;
2688 UINT32 size;
2689 BOOL exists;
2690 HRESULT hr;
2692 /* These are rendering time properties. */
2693 logfont->lfHeight = 0;
2694 logfont->lfWidth = 0;
2695 logfont->lfEscapement = 0;
2696 logfont->lfOrientation = 0;
2697 logfont->lfUnderline = 0;
2698 logfont->lfStrikeOut = 0;
2700 logfont->lfWeight = 0;
2701 logfont->lfItalic = 0;
2703 hr = IDWriteFont_CreateFontFace(font, &fontface);
2704 ok(hr == S_OK, "Failed to create font face, %#x\n", hr);
2706 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size,
2707 &os2_context, &exists);
2708 ok(hr == S_OK, "Failed to get OS/2 table, %#x\n", hr);
2710 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void **)&tt_head, &size,
2711 &head_context, &exists);
2712 ok(hr == S_OK, "Failed to get head table, %#x\n", hr);
2714 sim = IDWriteFont_GetSimulations(font);
2716 /* lfWeight */
2717 weight = FW_REGULAR;
2718 if (tt_os2) {
2719 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
2721 if (usWeightClass >= 1 && usWeightClass <= 9)
2722 usWeightClass *= 100;
2724 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
2725 weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
2726 else if (usWeightClass > 0)
2727 weight = usWeightClass;
2729 else if (tt_head) {
2730 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2731 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
2732 weight = DWRITE_FONT_WEIGHT_BOLD;
2734 if (sim & DWRITE_FONT_SIMULATIONS_BOLD)
2735 weight += (FW_BOLD - FW_REGULAR) / 2 + 1;
2736 logfont->lfWeight = weight;
2738 /* lfItalic */
2739 if (IDWriteFont_GetSimulations(font) & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2740 logfont->lfItalic = 1;
2742 style = IDWriteFont_GetStyle(font);
2743 if (!logfont->lfItalic && ((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE))) {
2744 if (tt_os2) {
2745 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
2746 logfont->lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
2748 else if (tt_head) {
2749 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2750 logfont->lfItalic = !!(macStyle & TT_HEAD_MACSTYLE_ITALIC);
2754 /* lfFaceName */
2755 exists = FALSE;
2756 logfont->lfFaceName[0] = 0;
2757 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &exists);
2758 if (SUCCEEDED(hr))
2760 if (exists)
2762 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
2763 WCHAR nameW[256];
2764 UINT32 index;
2766 /* Fallback to en-us if there's no string for user locale. */
2767 exists = FALSE;
2768 if (GetSystemDefaultLocaleName(localeW, ARRAY_SIZE(localeW)))
2769 IDWriteLocalizedStrings_FindLocaleName(names, localeW, &index, &exists);
2771 if (!exists)
2772 IDWriteLocalizedStrings_FindLocaleName(names, L"en-us", &index, &exists);
2774 if (exists) {
2775 nameW[0] = 0;
2776 hr = IDWriteLocalizedStrings_GetString(names, index, nameW, ARRAY_SIZE(nameW));
2777 ok(hr == S_OK, "Failed to get name string, hr %#x.\n", hr);
2778 lstrcpynW(logfont->lfFaceName, nameW, ARRAY_SIZE(logfont->lfFaceName));
2782 IDWriteLocalizedStrings_Release(names);
2785 if (tt_os2)
2786 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2787 if (tt_head)
2788 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2789 IDWriteFontFace_Release(fontface);
2792 static void test_ConvertFontFaceToLOGFONT(void)
2794 IDWriteFontCollection *collection;
2795 IDWriteGdiInterop *interop;
2796 IDWriteFontFace *fontface;
2797 IDWriteFactory *factory;
2798 LOGFONTW logfont;
2799 UINT32 count, i;
2800 HRESULT hr;
2801 ULONG ref;
2803 factory = create_factory();
2805 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2806 ok(hr == S_OK, "got 0x%08x\n", hr);
2808 if (0) /* crashes on native */
2810 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, NULL);
2811 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, NULL);
2813 memset(&logfont, 0xcc, sizeof(logfont));
2814 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, &logfont);
2815 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2816 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2818 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2819 ok(hr == S_OK, "got 0x%08x\n", hr);
2821 count = IDWriteFontCollection_GetFontFamilyCount(collection);
2822 for (i = 0; i < count; i++) {
2823 WCHAR nameW[128], familynameW[64], facenameW[64];
2824 IDWriteLocalizedStrings *names;
2825 DWRITE_FONT_SIMULATIONS sim;
2826 IDWriteFontFamily *family;
2827 UINT32 font_count, j;
2828 IDWriteFont *font;
2829 LOGFONTW lf;
2831 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2832 ok(hr == S_OK, "got 0x%08x\n", hr);
2834 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2835 ok(hr == S_OK, "got 0x%08x\n", hr);
2837 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
2838 IDWriteLocalizedStrings_Release(names);
2840 font_count = IDWriteFontFamily_GetFontCount(family);
2842 for (j = 0; j < font_count; j++) {
2843 IDWriteFontFace *fontface;
2845 hr = IDWriteFontFamily_GetFont(family, j, &font);
2846 ok(hr == S_OK, "got 0x%08x\n", hr);
2848 hr = IDWriteFont_GetFaceNames(font, &names);
2849 ok(hr == S_OK, "got 0x%08x\n", hr);
2851 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
2852 IDWriteLocalizedStrings_Release(names);
2854 get_combined_font_name(familynameW, facenameW, nameW);
2856 hr = IDWriteFont_CreateFontFace(font, &fontface);
2857 ok(hr == S_OK, "got 0x%08x\n", hr);
2859 if (has_face_variations(fontface))
2861 static int once;
2862 if (!once++)
2863 skip("ConvertFontFaceToLOGFONT() test does not support variable fonts.\n");
2864 IDWriteFontFace_Release(fontface);
2865 IDWriteFont_Release(font);
2866 continue;
2869 memset(&logfont, 0xcc, sizeof(logfont));
2870 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, &logfont);
2871 ok(hr == S_OK, "got 0x%08x\n", hr);
2873 sim = IDWriteFontFace_GetSimulations(fontface);
2874 get_logfont_from_font(font, &lf);
2876 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
2877 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
2878 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
2879 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
2880 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
2881 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
2882 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
2884 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
2885 logfont.lfOutPrecision);
2886 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
2887 logfont.lfClipPrecision);
2888 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
2889 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
2890 logfont.lfPitchAndFamily);
2892 IDWriteFontFace_Release(fontface);
2893 IDWriteFont_Release(font);
2896 IDWriteFontFamily_Release(family);
2899 IDWriteFontCollection_Release(collection);
2900 IDWriteGdiInterop_Release(interop);
2901 ref = IDWriteFactory_Release(factory);
2902 ok(ref == 0, "factory not released, %u\n", ref);
2905 static HRESULT WINAPI fontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2907 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
2909 *obj = iface;
2910 IDWriteFontFileEnumerator_AddRef(iface);
2911 return S_OK;
2913 return E_NOINTERFACE;
2916 static ULONG WINAPI fontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2918 return 2;
2921 static ULONG WINAPI fontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2923 return 1;
2926 static HRESULT WINAPI fontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2928 *file = NULL;
2929 return E_FAIL;
2932 static HRESULT WINAPI fontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2934 *current = FALSE;
2935 return S_OK;
2938 static const struct IDWriteFontFileEnumeratorVtbl dwritefontfileenumeratorvtbl =
2940 fontfileenumerator_QueryInterface,
2941 fontfileenumerator_AddRef,
2942 fontfileenumerator_Release,
2943 fontfileenumerator_MoveNext,
2944 fontfileenumerator_GetCurrentFontFile,
2947 struct collection_loader
2949 IDWriteFontCollectionLoader IDWriteFontCollectionLoader_iface;
2950 LONG ref;
2953 static inline struct collection_loader *impl_from_IDWriteFontCollectionLoader(IDWriteFontCollectionLoader *iface)
2955 return CONTAINING_RECORD(iface, struct collection_loader, IDWriteFontCollectionLoader_iface);
2958 static HRESULT WINAPI fontcollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
2960 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2962 if (IsEqualIID(&IID_IDWriteFontCollectionLoader, riid) ||
2963 IsEqualIID(&IID_IUnknown, riid))
2965 *obj = &loader->IDWriteFontCollectionLoader_iface;
2966 IDWriteFontCollectionLoader_AddRef(iface);
2967 return S_OK;
2970 *obj = NULL;
2971 return E_NOINTERFACE;
2974 static ULONG WINAPI fontcollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
2976 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2977 return InterlockedIncrement(&loader->ref);
2980 static ULONG WINAPI fontcollectionloader_Release(IDWriteFontCollectionLoader *iface)
2982 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2983 ULONG ref = InterlockedDecrement(&loader->ref);
2985 if (!ref)
2986 heap_free(loader);
2988 return ref;
2991 static HRESULT WINAPI fontcollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory, const void *key,
2992 UINT32 key_size, IDWriteFontFileEnumerator **ret)
2994 static IDWriteFontFileEnumerator enumerator = { &dwritefontfileenumeratorvtbl };
2995 *ret = &enumerator;
2996 return S_OK;
2999 static const struct IDWriteFontCollectionLoaderVtbl dwritefontcollectionloadervtbl = {
3000 fontcollectionloader_QueryInterface,
3001 fontcollectionloader_AddRef,
3002 fontcollectionloader_Release,
3003 fontcollectionloader_CreateEnumeratorFromKey
3006 static IDWriteFontCollectionLoader *create_collection_loader(void)
3008 struct collection_loader *loader = heap_alloc(sizeof(*loader));
3010 loader->IDWriteFontCollectionLoader_iface.lpVtbl = &dwritefontcollectionloadervtbl;
3011 loader->ref = 1;
3013 return &loader->IDWriteFontCollectionLoader_iface;
3016 static void test_CustomFontCollection(void)
3018 IDWriteFontCollectionLoader *loader, *loader2, *loader3;
3019 IDWriteFontCollection *font_collection = NULL;
3020 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
3021 struct test_fontcollectionloader resource_collection = { { &resourcecollectionloadervtbl }, &rloader };
3022 IDWriteFontFamily *family, *family2, *family3;
3023 IDWriteFontFace *idfontface, *idfontface2;
3024 IDWriteFontFile *fontfile, *fontfile2;
3025 IDWriteLocalizedStrings *string;
3026 IDWriteFont *idfont, *idfont2;
3027 IDWriteFactory *factory;
3028 UINT32 index, count;
3029 BOOL exists;
3030 HRESULT hr;
3031 HRSRC font;
3032 ULONG ref;
3034 factory = create_factory();
3036 loader = create_collection_loader();
3037 loader2 = create_collection_loader();
3038 loader3 = create_collection_loader();
3040 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, NULL);
3041 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3043 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, NULL);
3044 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3046 EXPECT_REF(loader, 1);
3047 EXPECT_REF(loader2, 1);
3049 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
3050 ok(hr == S_OK, "got 0x%08x\n", hr);
3051 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader2);
3052 ok(hr == S_OK, "got 0x%08x\n", hr);
3053 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
3054 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
3056 EXPECT_REF(loader, 2);
3057 EXPECT_REF(loader2, 2);
3059 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3060 ok(hr == S_OK, "got 0x%08x\n", hr);
3061 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
3062 ok(hr == S_OK, "got 0x%08x\n", hr);
3064 /* Loader wasn't registered. */
3065 font_collection = (void*)0xdeadbeef;
3066 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader3, "Billy", 6, &font_collection);
3067 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3068 ok(font_collection == NULL, "got %p\n", font_collection);
3070 EXPECT_REF(factory, 1);
3071 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader, "Billy", 6, &font_collection);
3072 ok(hr == S_OK, "got 0x%08x\n", hr);
3073 todo_wine
3074 EXPECT_REF(factory, 1);
3075 EXPECT_REF(loader, 2);
3076 IDWriteFontCollection_Release(font_collection);
3078 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader2, "Billy", 6, &font_collection);
3079 ok(hr == S_OK, "got 0x%08x\n", hr);
3080 IDWriteFontCollection_Release(font_collection);
3082 font_collection = (void*)0xdeadbeef;
3083 hr = IDWriteFactory_CreateCustomFontCollection(factory, (IDWriteFontCollectionLoader*)0xdeadbeef, "Billy", 6, &font_collection);
3084 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3085 ok(font_collection == NULL, "got %p\n", font_collection);
3087 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3088 ok(font != NULL, "Failed to find font resource\n");
3090 hr = IDWriteFactory_CreateCustomFontCollection(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface,
3091 &font, sizeof(HRSRC), &font_collection);
3092 ok(hr == S_OK, "got 0x%08x\n",hr);
3093 EXPECT_REF(font_collection, 1);
3095 index = 1;
3096 exists = FALSE;
3097 hr = IDWriteFontCollection_FindFamilyName(font_collection, L"wine_test", &index, &exists);
3098 ok(hr == S_OK, "got 0x%08x\n", hr);
3099 ok(index == 0, "got index %i\n", index);
3100 ok(exists, "got exists %i\n", exists);
3102 count = IDWriteFontCollection_GetFontFamilyCount(font_collection);
3103 ok(count == 1, "got %u\n", count);
3105 family = NULL;
3106 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family);
3107 ok(hr == S_OK, "got 0x%08x\n", hr);
3108 EXPECT_REF(family, 1);
3110 family2 = NULL;
3111 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family2);
3112 ok(hr == S_OK, "got 0x%08x\n", hr);
3113 EXPECT_REF(family2, 1);
3114 ok(family != family2, "got %p, %p\n", family, family2);
3116 hr = IDWriteFontFamily_GetFont(family, 0, &idfont);
3117 ok(hr == S_OK, "got 0x%08x\n", hr);
3118 EXPECT_REF(idfont, 1);
3119 EXPECT_REF(family, 2);
3120 hr = IDWriteFontFamily_GetFont(family, 0, &idfont2);
3121 ok(hr == S_OK, "got 0x%08x\n", hr);
3122 EXPECT_REF(idfont2, 1);
3123 EXPECT_REF(family, 3);
3124 ok(idfont != idfont2, "got %p, %p\n", idfont, idfont2);
3125 IDWriteFont_Release(idfont2);
3127 hr = IDWriteFont_GetInformationalStrings(idfont, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &string, &exists);
3128 ok(hr == S_OK, "got 0x%08x\n", hr);
3129 ok(exists, "got %d\n", exists);
3130 EXPECT_REF(string, 1);
3131 IDWriteLocalizedStrings_Release(string);
3133 family3 = NULL;
3134 hr = IDWriteFont_GetFontFamily(idfont, &family3);
3135 ok(hr == S_OK, "got 0x%08x\n", hr);
3136 EXPECT_REF(family, 3);
3137 ok(family == family3, "got %p, %p\n", family, family3);
3138 IDWriteFontFamily_Release(family3);
3140 idfontface = NULL;
3141 hr = IDWriteFont_CreateFontFace(idfont, &idfontface);
3142 ok(hr == S_OK, "got 0x%08x\n", hr);
3143 EXPECT_REF(idfont, 1);
3145 idfont2 = NULL;
3146 hr = IDWriteFontFamily_GetFont(family2, 0, &idfont2);
3147 ok(hr == S_OK, "got 0x%08x\n", hr);
3148 EXPECT_REF(idfont2, 1);
3149 EXPECT_REF(idfont, 1);
3150 ok(idfont2 != idfont, "Font instances should not match\n");
3152 idfontface2 = NULL;
3153 hr = IDWriteFont_CreateFontFace(idfont2, &idfontface2);
3154 ok(hr == S_OK, "got 0x%08x\n", hr);
3155 ok(idfontface2 == idfontface, "fontfaces should match\n");
3157 index = 1;
3158 fontfile = NULL;
3159 hr = IDWriteFontFace_GetFiles(idfontface, &index, &fontfile);
3160 ok(hr == S_OK, "got 0x%08x\n", hr);
3162 index = 1;
3163 fontfile2 = NULL;
3164 hr = IDWriteFontFace_GetFiles(idfontface2, &index, &fontfile2);
3165 ok(hr == S_OK, "got 0x%08x\n", hr);
3166 ok(fontfile == fontfile2, "fontfiles should match\n");
3168 IDWriteFont_Release(idfont);
3169 IDWriteFont_Release(idfont2);
3170 IDWriteFontFile_Release(fontfile);
3171 IDWriteFontFile_Release(fontfile2);
3172 IDWriteFontFace_Release(idfontface);
3173 IDWriteFontFace_Release(idfontface2);
3174 IDWriteFontFamily_Release(family2);
3175 IDWriteFontFamily_Release(family);
3176 IDWriteFontCollection_Release(font_collection);
3178 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
3179 ok(hr == S_OK, "got 0x%08x\n", hr);
3180 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
3181 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3182 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader2);
3183 ok(hr == S_OK, "got 0x%08x\n", hr);
3184 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
3185 ok(hr == S_OK, "got 0x%08x\n", hr);
3186 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3187 ok(hr == S_OK, "got 0x%08x\n", hr);
3189 IDWriteFontCollectionLoader_Release(loader);
3190 IDWriteFontCollectionLoader_Release(loader2);
3191 IDWriteFontCollectionLoader_Release(loader3);
3193 ref = IDWriteFactory_Release(factory);
3194 ok(ref == 0, "factory not released, %u\n", ref);
3197 static HRESULT WINAPI fontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
3199 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
3201 *obj = iface;
3202 IDWriteFontFileLoader_AddRef(iface);
3203 return S_OK;
3206 *obj = NULL;
3207 return E_NOINTERFACE;
3210 static ULONG WINAPI fontfileloader_AddRef(IDWriteFontFileLoader *iface)
3212 return 2;
3215 static ULONG WINAPI fontfileloader_Release(IDWriteFontFileLoader *iface)
3217 return 1;
3220 static HRESULT WINAPI fontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
3221 IDWriteFontFileStream **stream)
3223 return 0x8faecafe;
3226 static const struct IDWriteFontFileLoaderVtbl dwritefontfileloadervtbl = {
3227 fontfileloader_QueryInterface,
3228 fontfileloader_AddRef,
3229 fontfileloader_Release,
3230 fontfileloader_CreateStreamFromKey
3233 static void test_CreateCustomFontFileReference(void)
3235 IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl };
3236 IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl };
3237 IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl };
3238 IDWriteFactory *factory, *factory2;
3239 IDWriteFontFileLoader *loader;
3240 IDWriteFontFile *file, *file2;
3241 BOOL support;
3242 DWRITE_FONT_FILE_TYPE file_type;
3243 DWRITE_FONT_FACE_TYPE face_type;
3244 UINT32 count;
3245 IDWriteFontFace *face, *face2;
3246 HRESULT hr;
3247 HRSRC fontrsrc;
3248 UINT32 codePoints[1] = {0xa8};
3249 UINT16 indices[2];
3250 const void *key;
3251 UINT32 key_size;
3252 WCHAR *path;
3253 ULONG ref;
3255 path = create_testfontfile(test_fontfile);
3257 factory = create_factory();
3258 factory2 = create_factory();
3260 if (0) { /* crashes on win10 */
3261 hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
3262 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3264 /* local loader is accepted too */
3265 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3266 ok(hr == S_OK, "got 0x%08x\n", hr);
3268 hr = IDWriteFontFile_GetLoader(file, &loader);
3269 ok(hr == S_OK, "got 0x%08x\n", hr);
3271 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3272 ok(hr == S_OK, "got 0x%08x\n", hr);
3274 hr = IDWriteFactory_CreateCustomFontFileReference(factory, key, key_size, loader, &file2);
3275 ok(hr == S_OK, "got 0x%08x\n", hr);
3277 IDWriteFontFile_Release(file2);
3278 IDWriteFontFile_Release(file);
3279 IDWriteFontFileLoader_Release(loader);
3281 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3282 ok(hr == S_OK, "got 0x%08x\n", hr);
3283 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader2);
3284 ok(hr == S_OK, "got 0x%08x\n", hr);
3285 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3286 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
3287 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3288 ok(hr == S_OK, "got 0x%08x\n", hr);
3290 file = NULL;
3291 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3292 ok(hr == S_OK, "got 0x%08x\n", hr);
3293 IDWriteFontFile_Release(file);
3295 file = (void*)0xdeadbeef;
3296 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader3, &file);
3297 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3298 ok(file == NULL, "got %p\n", file);
3300 file = (void*)0xdeadbeef;
3301 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, NULL, &file);
3302 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3303 ok(file == NULL, "got %p\n", file);
3305 file = NULL;
3306 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3307 ok(hr == S_OK, "got 0x%08x\n", hr);
3309 file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
3310 face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
3311 support = TRUE;
3312 count = 1;
3313 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3314 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
3315 ok(support == FALSE, "got %i\n", support);
3316 ok(file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN, "got %i\n", file_type);
3317 ok(face_type == DWRITE_FONT_FACE_TYPE_UNKNOWN, "got %i\n", face_type);
3318 ok(count == 0, "got %i\n", count);
3320 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0, &face);
3321 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
3322 IDWriteFontFile_Release(file);
3324 fontrsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3325 ok(fontrsrc != NULL, "Failed to find font resource\n");
3327 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file);
3328 ok(hr == S_OK, "got 0x%08x\n", hr);
3330 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3331 face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3332 support = FALSE;
3333 count = 0;
3334 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3335 ok(hr == S_OK, "got 0x%08x\n", hr);
3336 ok(support == TRUE, "got %i\n", support);
3337 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
3338 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
3339 ok(count == 1, "got %i\n", count);
3341 /* invalid index */
3342 face = (void*)0xdeadbeef;
3343 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 1, DWRITE_FONT_SIMULATIONS_NONE, &face);
3344 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3345 ok(face == NULL, "got %p\n", face);
3347 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
3348 ok(hr == S_OK, "got 0x%08x\n", hr);
3350 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3351 ok(hr == S_OK, "got 0x%08x\n", hr);
3352 /* fontface instances are reused starting with win7 */
3353 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3354 IDWriteFontFace_Release(face2);
3356 /* file was created with different factory */
3357 face2 = NULL;
3358 hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3359 todo_wine
3360 ok(hr == S_OK, "got 0x%08x\n", hr);
3361 if (face2) {
3362 IDWriteFontFace_Release(face2);
3364 file2 = NULL;
3365 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2);
3366 ok(hr == S_OK, "got 0x%08x\n", hr);
3367 ok(file != file2, "got %p, %p\n", file, file2);
3369 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3370 ok(hr == S_OK, "got 0x%08x\n", hr);
3371 /* fontface instances are reused starting with win7 */
3372 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3373 IDWriteFontFace_Release(face2);
3374 IDWriteFontFile_Release(file2);
3376 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, NULL);
3377 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3379 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, NULL);
3380 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3382 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, indices);
3383 ok(hr == S_OK, "got 0x%08x\n", hr);
3385 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, indices);
3386 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3388 indices[0] = indices[1] = 11;
3389 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, indices);
3390 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3391 ok(indices[0] == 0, "got index %i\n", indices[0]);
3392 ok(indices[1] == 11, "got index %i\n", indices[1]);
3394 if (0) /* crashes on native */
3395 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, NULL);
3397 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 1, indices);
3398 ok(hr == S_OK, "got 0x%08x\n", hr);
3399 ok(indices[0] == 7, "Unexpected glyph index, %u.\n", indices[0]);
3400 IDWriteFontFace_Release(face);
3401 IDWriteFontFile_Release(file);
3403 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3404 ok(hr == S_OK, "got 0x%08x\n", hr);
3405 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3406 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3407 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader2);
3408 ok(hr == S_OK, "got 0x%08x\n", hr);
3409 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3410 ok(hr == S_OK, "got 0x%08x\n", hr);
3412 ref = IDWriteFactory_Release(factory2);
3413 ok(ref == 0, "factory not released, %u\n", ref);
3414 ref = IDWriteFactory_Release(factory);
3415 ok(ref == 0, "factory not released, %u\n", ref);
3416 DELETE_FONTFILE(path);
3419 static void test_CreateFontFileReference(void)
3421 HRESULT hr;
3422 IDWriteFontFile *ffile = NULL;
3423 BOOL support;
3424 DWRITE_FONT_FILE_TYPE type;
3425 DWRITE_FONT_FACE_TYPE face;
3426 UINT32 count;
3427 IDWriteFontFace *fface = NULL;
3428 IDWriteFactory *factory;
3429 WCHAR *path;
3430 ULONG ref;
3432 path = create_testfontfile(test_fontfile);
3433 factory = create_factory();
3435 ffile = (void*)0xdeadbeef;
3436 hr = IDWriteFactory_CreateFontFileReference(factory, NULL, NULL, &ffile);
3437 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
3438 ok(ffile == NULL, "got %p\n", ffile);
3440 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &ffile);
3441 ok(hr == S_OK, "got 0x%08x\n",hr);
3443 support = FALSE;
3444 type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3445 face = DWRITE_FONT_FACE_TYPE_CFF;
3446 count = 0;
3447 hr = IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count);
3448 ok(hr == S_OK, "got 0x%08x\n", hr);
3449 ok(support == TRUE, "got %i\n", support);
3450 ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type);
3451 ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face);
3452 ok(count == 1, "got %i\n", count);
3454 hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface);
3455 ok(hr == S_OK, "got 0x%08x\n", hr);
3457 IDWriteFontFace_Release(fface);
3458 IDWriteFontFile_Release(ffile);
3459 ref = IDWriteFactory_Release(factory);
3460 ok(ref == 0, "factory not released, %u\n", ref);
3462 DELETE_FONTFILE(path);
3465 static void test_shared_isolated(void)
3467 IDWriteFactory *isolated, *isolated2;
3468 IDWriteFactory *shared, *shared2;
3469 HRESULT hr;
3470 ULONG ref;
3472 /* invalid type */
3473 shared = NULL;
3474 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&shared);
3475 ok(hr == S_OK, "got 0x%08x\n", hr);
3476 ok(shared != NULL, "got %p\n", shared);
3477 IDWriteFactory_Release(shared);
3479 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared);
3480 ok(hr == S_OK, "got 0x%08x\n", hr);
3482 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3483 ok(hr == S_OK, "got 0x%08x\n", hr);
3484 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3485 IDWriteFactory_Release(shared2);
3487 IDWriteFactory_Release(shared);
3489 /* we got 2 references, released 2 - still same pointer is returned */
3490 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3491 ok(hr == S_OK, "got 0x%08x\n", hr);
3492 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3493 IDWriteFactory_Release(shared2);
3495 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated);
3496 ok(hr == S_OK, "got 0x%08x\n", hr);
3498 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3499 ok(hr == S_OK, "got 0x%08x\n", hr);
3500 ok(isolated != isolated2, "got %p, and %p\n", isolated, isolated2);
3501 IDWriteFactory_Release(isolated2);
3503 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IUnknown, (IUnknown**)&isolated2);
3504 ok(hr == S_OK, "got 0x%08x\n", hr);
3505 IDWriteFactory_Release(isolated2);
3507 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3508 ok(hr == S_OK, "got 0x%08x\n", hr);
3509 ok(shared != isolated2, "got %p, and %p\n", shared, isolated2);
3511 ref = IDWriteFactory_Release(isolated);
3512 ok(ref == 0, "factory not released, %u\n", ref);
3513 ref = IDWriteFactory_Release(isolated2);
3514 ok(ref == 0, "factory not released, %u\n", ref);
3517 struct dwrite_fonttable
3519 BYTE *data;
3520 void *context;
3521 UINT32 size;
3524 static WORD table_read_be_word(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
3526 if (!ptr)
3527 ptr = table->data;
3529 if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
3530 return 0;
3532 if (offset > table->size - sizeof(WORD))
3533 return 0;
3535 return GET_BE_WORD(*(WORD *)((BYTE *)ptr + offset));
3538 static DWORD table_read_be_dword(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
3540 if (!ptr)
3541 ptr = table->data;
3543 if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
3544 return 0;
3546 if (offset > table->size - sizeof(WORD))
3547 return 0;
3549 return GET_BE_DWORD(*(DWORD *)((BYTE *)ptr + offset));
3552 static void array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
3554 size_t new_capacity, max_capacity;
3555 void *new_elements;
3557 if (count <= *capacity)
3558 return;
3560 max_capacity = ~(SIZE_T)0 / size;
3561 if (count > max_capacity)
3562 return;
3564 new_capacity = max(4, *capacity);
3565 while (new_capacity < count && new_capacity <= max_capacity / 2)
3566 new_capacity *= 2;
3567 if (new_capacity < count)
3568 new_capacity = max_capacity;
3570 if (!(new_elements = heap_realloc(*elements, new_capacity * size)))
3571 return;
3573 *elements = new_elements;
3574 *capacity = new_capacity;
3577 static void opentype_cmap_read_table(const struct dwrite_fonttable *table, UINT16 cmap_index, UINT32 *count,
3578 size_t *capacity, DWRITE_UNICODE_RANGE **ranges)
3580 const BYTE *tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
3581 struct cmap_encoding_record *record;
3582 DWORD table_offset;
3583 WORD format;
3584 int j;
3586 record = (struct cmap_encoding_record *)(tables + cmap_index * sizeof(*record));
3588 if (!(table_offset = table_read_be_dword(table, record, FIELD_OFFSET(struct cmap_encoding_record, offset))))
3589 return;
3591 format = table_read_be_word(table, NULL, table_offset);
3592 switch (format)
3594 case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
3596 UINT16 segment_count = table_read_be_word(table, NULL, table_offset +
3597 FIELD_OFFSET(struct cmap_segmented_mapping_0, segCountX2)) / 2;
3598 DWORD start_code_offset = table_offset + sizeof(struct cmap_segmented_mapping_0) +
3599 sizeof(WORD) * segment_count;
3601 for (j = 0; j < segment_count; ++j) {
3602 WORD endcode = table_read_be_word(table, NULL, table_offset +
3603 FIELD_OFFSET(struct cmap_segmented_mapping_0, endCode) + j * sizeof(WORD));
3604 WORD first;
3606 if (endcode == 0xffff)
3607 break;
3609 first = table_read_be_word(table, NULL, start_code_offset + j * sizeof(WORD));
3611 array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
3612 (*ranges)[*count].first = first;
3613 (*ranges)[*count].last = endcode;
3614 (*count)++;
3616 break;
3618 case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
3620 DWORD num_groups = table_read_be_dword(table, NULL, table_offset +
3621 FIELD_OFFSET(struct cmap_segmented_coverage, nGroups));
3623 for (j = 0; j < num_groups; ++j) {
3624 DWORD group_offset = table_offset + FIELD_OFFSET(struct cmap_segmented_coverage, groups) +
3625 j * sizeof(struct cmap_segmented_coverage_group);
3626 DWORD first = table_read_be_dword(table, NULL, group_offset +
3627 FIELD_OFFSET(struct cmap_segmented_coverage_group, startCharCode));
3628 DWORD last = table_read_be_dword(table, NULL, group_offset +
3629 FIELD_OFFSET(struct cmap_segmented_coverage_group, endCharCode));
3631 array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
3632 (*ranges)[*count].first = first;
3633 (*ranges)[*count].last = last;
3634 (*count)++;
3636 break;
3638 default:
3639 ok(0, "%u table format %#x unhandled.\n", cmap_index, format);
3643 static UINT32 opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *table, DWRITE_UNICODE_RANGE **ranges)
3645 int index_full = -1, index_bmp = -1;
3646 unsigned int i, count = 0;
3647 size_t capacity = 0;
3648 const BYTE *tables;
3649 WORD num_tables;
3651 *ranges = NULL;
3653 num_tables = table_read_be_word(table, 0, FIELD_OFFSET(struct cmap_header, num_tables));
3654 tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
3656 for (i = 0; i < num_tables; ++i)
3658 struct cmap_encoding_record *record = (struct cmap_encoding_record *)(tables + i * sizeof(*record));
3659 WORD platform, encoding;
3661 platform = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, platformID));
3662 encoding = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, encodingID));
3664 if (platform == OPENTYPE_CMAP_TABLE_PLATFORM_WIN)
3666 if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL)
3668 index_full = i;
3669 break;
3671 else if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP)
3672 index_bmp = i;
3676 if (index_full != -1)
3677 opentype_cmap_read_table(table, index_full, &count, &capacity, ranges);
3678 else if (index_bmp != -1)
3679 opentype_cmap_read_table(table, index_bmp, &count, &capacity, ranges);
3681 return count;
3684 static UINT32 fontface_get_expected_unicode_ranges(IDWriteFontFace1 *fontface, DWRITE_UNICODE_RANGE **out)
3686 struct dwrite_fonttable cmap;
3687 DWRITE_UNICODE_RANGE *ranges;
3688 UINT32 i, j, count;
3689 BOOL exists;
3690 HRESULT hr;
3692 *out = NULL;
3694 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_CMAP_TAG, (const void **)&cmap.data,
3695 &cmap.size, &cmap.context, &exists);
3696 if (FAILED(hr) || !exists)
3697 return 0;
3699 count = opentype_cmap_get_unicode_ranges(&cmap, &ranges);
3700 IDWriteFontFace1_ReleaseFontTable(fontface, cmap.context);
3702 *out = heap_alloc(count * sizeof(**out));
3704 /* Eliminate duplicates and merge ranges together. */
3705 for (i = 0, j = 0; i < count; ++i) {
3706 if (j) {
3707 DWRITE_UNICODE_RANGE *prev = &(*out)[j-1];
3708 /* Merge adjacent ranges. */
3709 if (ranges[i].first == prev->last + 1) {
3710 prev->last = ranges[i].last;
3711 continue;
3714 (*out)[j++] = ranges[i];
3717 heap_free(ranges);
3719 return j;
3722 static void test_GetUnicodeRanges(void)
3724 IDWriteFontCollection *syscollection;
3725 DWRITE_UNICODE_RANGE *ranges, r;
3726 IDWriteFontFile *ffile = NULL;
3727 IDWriteFontFace1 *fontface1;
3728 IDWriteFontFace *fontface;
3729 IDWriteFactory *factory;
3730 UINT32 count, i;
3731 HRESULT hr;
3732 HRSRC font;
3733 ULONG ref;
3735 factory = create_factory();
3737 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3738 ok(hr == S_OK, "got 0x%08x\n", hr);
3740 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3741 ok(font != NULL, "Failed to find font resource\n");
3743 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile);
3744 ok(hr == S_OK, "got 0x%08x\n", hr);
3746 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3747 ok(hr == S_OK, "got 0x%08x\n", hr);
3748 IDWriteFontFile_Release(ffile);
3750 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3751 IDWriteFontFace_Release(fontface);
3752 if (hr != S_OK) {
3753 win_skip("GetUnicodeRanges() is not supported.\n");
3754 IDWriteFactory_Release(factory);
3755 return;
3758 count = 0;
3759 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
3760 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3761 ok(count > 0, "got %u\n", count);
3763 count = 1;
3764 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count);
3765 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3766 ok(count == 0, "got %u\n", count);
3768 count = 0;
3769 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count);
3770 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3771 ok(count > 1, "got %u\n", count);
3773 ranges = heap_alloc(count*sizeof(DWRITE_UNICODE_RANGE));
3774 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
3775 ok(hr == S_OK, "got 0x%08x\n", hr);
3777 ranges[0].first = ranges[0].last = 0;
3778 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count);
3779 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3780 ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last);
3782 heap_free(ranges);
3784 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3785 ok(hr == S_OK, "got 0x%08x\n", hr);
3787 IDWriteFontFace1_Release(fontface1);
3789 if (strcmp(winetest_platform, "wine")) {
3791 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
3792 ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
3794 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
3796 for (i = 0; i < count; i++) {
3797 WCHAR familynameW[256], facenameW[128];
3798 IDWriteLocalizedStrings *names;
3799 IDWriteFontFamily *family;
3800 UINT32 j, k, fontcount;
3801 IDWriteFont *font;
3803 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
3804 ok(hr == S_OK, "Failed to get font family, hr %#x.\n", hr);
3806 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
3807 ok(hr == S_OK, "Failed to get family names, hr %#x.\n", hr);
3809 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
3810 IDWriteLocalizedStrings_Release(names);
3812 fontcount = IDWriteFontFamily_GetFontCount(family);
3813 for (j = 0; j < fontcount; j++) {
3814 DWRITE_UNICODE_RANGE *expected_ranges = NULL;
3815 UINT32 range_count, expected_count;
3817 hr = IDWriteFontFamily_GetFont(family, j, &font);
3818 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
3820 hr = IDWriteFont_CreateFontFace(font, &fontface);
3821 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
3823 hr = IDWriteFont_GetFaceNames(font, &names);
3824 ok(hr == S_OK, "Failed to get face names, hr %#x.\n", hr);
3825 IDWriteFont_Release(font);
3827 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
3829 IDWriteLocalizedStrings_Release(names);
3831 if (IDWriteFontFace_IsSymbolFont(fontface))
3833 static int once;
3834 if (!once++)
3835 skip("GetUnicodeRanges() test does not support symbol fonts.\n");
3836 IDWriteFontFace_Release(fontface);
3837 continue;
3840 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
3842 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &range_count);
3843 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
3845 ranges = heap_alloc(range_count * sizeof(*ranges));
3847 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, range_count, ranges, &range_count);
3848 ok(hr == S_OK, "Failed to get ranges, hr %#x.\n", hr);
3850 expected_count = fontface_get_expected_unicode_ranges(fontface1, &expected_ranges);
3851 ok(expected_count == range_count, "%s - %s: unexpected range count %u, expected %u.\n",
3852 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), range_count, expected_count);
3854 if (expected_count == range_count) {
3855 if (memcmp(expected_ranges, ranges, expected_count * sizeof(*ranges))) {
3856 for (k = 0; k < expected_count; ++k) {
3857 BOOL failed = memcmp(&expected_ranges[k], &ranges[k], sizeof(*ranges));
3858 ok(!failed, "%u: %s - %s mismatching range [%#x, %#x] vs [%#x, %#x].\n", k,
3859 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), ranges[k].first, ranges[k].last,
3860 expected_ranges[k].first, expected_ranges[k].last);
3861 if (failed)
3862 break;
3867 heap_free(expected_ranges);
3868 heap_free(ranges);
3870 IDWriteFontFace1_Release(fontface1);
3871 IDWriteFontFace_Release(fontface);
3874 IDWriteFontFamily_Release(family);
3877 IDWriteFontCollection_Release(syscollection);
3879 ref = IDWriteFactory_Release(factory);
3880 ok(ref == 0, "factory not released, %u\n", ref);
3883 static void test_GetFontFromFontFace(void)
3885 IDWriteFontFace *fontface, *fontface2;
3886 IDWriteFontCollection *collection;
3887 IDWriteFont *font, *font2, *font3;
3888 IDWriteFontFamily *family;
3889 IDWriteFactory *factory;
3890 IDWriteFontFile *file;
3891 WCHAR *path;
3892 HRESULT hr;
3893 ULONG ref;
3895 factory = create_factory();
3897 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3898 ok(hr == S_OK, "got 0x%08x\n", hr);
3900 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3901 ok(hr == S_OK, "got 0x%08x\n", hr);
3903 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3904 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3905 ok(hr == S_OK, "got 0x%08x\n", hr);
3907 hr = IDWriteFont_CreateFontFace(font, &fontface);
3908 ok(hr == S_OK, "got 0x%08x\n", hr);
3910 font2 = NULL;
3911 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
3912 ok(hr == S_OK, "got 0x%08x\n", hr);
3913 ok(font2 != font, "got %p, %p\n", font2, font);
3915 font3 = NULL;
3916 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3917 ok(hr == S_OK, "got 0x%08x\n", hr);
3918 ok(font3 != font && font3 != font2, "got %p, %p, %p\n", font3, font2, font);
3920 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
3921 ok(hr == S_OK, "got 0x%08x\n", hr);
3922 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3923 IDWriteFontFace_Release(fontface2);
3925 hr = IDWriteFont_CreateFontFace(font3, &fontface2);
3926 ok(hr == S_OK, "got 0x%08x\n", hr);
3927 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3928 IDWriteFontFace_Release(fontface2);
3929 IDWriteFontFace_Release(fontface);
3930 IDWriteFont_Release(font3);
3931 IDWriteFactory_Release(factory);
3933 /* fontface that wasn't created from this collection */
3934 factory = create_factory();
3935 path = create_testfontfile(test_fontfile);
3937 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3938 ok(hr == S_OK, "got 0x%08x\n",hr);
3940 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3941 ok(hr == S_OK, "got 0x%08x\n", hr);
3942 IDWriteFontFile_Release(file);
3944 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3945 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
3946 ok(font3 == NULL, "got %p\n", font3);
3947 IDWriteFontFace_Release(fontface);
3949 IDWriteFont_Release(font);
3950 IDWriteFont_Release(font2);
3951 IDWriteFontFamily_Release(family);
3952 IDWriteFontCollection_Release(collection);
3953 ref = IDWriteFactory_Release(factory);
3954 ok(ref == 0, "factory not released, %u\n", ref);
3955 DELETE_FONTFILE(path);
3958 static void test_GetFirstMatchingFont(void)
3960 DWRITE_FONT_SIMULATIONS simulations;
3961 IDWriteFontCollection *collection;
3962 IDWriteFontFamily *family;
3963 IDWriteFont *font, *font2;
3964 IDWriteFactory *factory;
3965 HRESULT hr;
3966 ULONG ref;
3968 factory = create_factory();
3970 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3971 ok(hr == S_OK, "got 0x%08x\n", hr);
3973 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3974 ok(hr == S_OK, "got 0x%08x\n", hr);
3976 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3977 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3978 ok(hr == S_OK, "got 0x%08x\n", hr);
3980 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3981 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
3982 ok(hr == S_OK, "got 0x%08x\n", hr);
3983 ok(font != font2, "got %p, %p\n", font, font2);
3984 IDWriteFont_Release(font);
3985 IDWriteFont_Release(font2);
3987 /* out-of-range font props are allowed */
3988 hr = IDWriteFontFamily_GetFirstMatchingFont(family, 1000, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3989 ok(hr == S_OK, "got 0x%08x\n", hr);
3990 IDWriteFont_Release(font);
3992 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, 10, DWRITE_FONT_STYLE_NORMAL, &font);
3993 ok(hr == S_OK, "got 0x%08x\n", hr);
3994 IDWriteFont_Release(font);
3996 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3997 10, &font);
3998 ok(hr == S_OK, "got 0x%08x\n", hr);
3999 IDWriteFont_Release(font);
4001 IDWriteFontFamily_Release(family);
4003 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
4004 simulations = IDWriteFont_GetSimulations(font);
4005 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "%d\n", simulations);
4006 IDWriteFont_Release(font);
4008 IDWriteFontCollection_Release(collection);
4009 ref = IDWriteFactory_Release(factory);
4010 ok(ref == 0, "factory not released, %u\n", ref);
4013 static void test_GetMatchingFonts(void)
4015 IDWriteFontCollection *collection;
4016 IDWriteFontFamily *family;
4017 IDWriteFactory *factory;
4018 IDWriteFontList *fontlist, *fontlist2;
4019 IDWriteFontList1 *fontlist1;
4020 IDWriteFontList2 *fontlist3;
4021 HRESULT hr;
4022 ULONG ref;
4024 factory = create_factory();
4026 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4027 ok(hr == S_OK, "got 0x%08x\n", hr);
4029 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4030 ok(hr == S_OK, "got 0x%08x\n", hr);
4032 /* out-of-range font props are allowed */
4033 hr = IDWriteFontFamily_GetMatchingFonts(family, 1000, DWRITE_FONT_STRETCH_NORMAL,
4034 DWRITE_FONT_STYLE_NORMAL, &fontlist);
4035 ok(hr == S_OK, "got 0x%08x\n", hr);
4036 IDWriteFontList_Release(fontlist);
4038 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, 10,
4039 DWRITE_FONT_STYLE_NORMAL, &fontlist);
4040 ok(hr == S_OK, "got 0x%08x\n", hr);
4041 IDWriteFontList_Release(fontlist);
4043 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
4044 10, &fontlist);
4045 ok(hr == S_OK, "got 0x%08x\n", hr);
4046 IDWriteFontList_Release(fontlist);
4048 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
4049 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
4050 ok(hr == S_OK, "got 0x%08x\n", hr);
4052 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
4053 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
4054 ok(hr == S_OK, "got 0x%08x\n", hr);
4055 ok(fontlist != fontlist2, "got %p, %p\n", fontlist, fontlist2);
4056 IDWriteFontList_Release(fontlist2);
4058 hr = IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList1, (void**)&fontlist1);
4059 if (hr == S_OK) {
4060 IDWriteFontFaceReference *ref, *ref1;
4061 IDWriteFont3 *font;
4062 UINT32 count;
4064 count = IDWriteFontList1_GetFontCount(fontlist1);
4065 ok(count > 0, "got %u\n", count);
4067 font = (void*)0xdeadbeef;
4068 hr = IDWriteFontList1_GetFont(fontlist1, ~0u, &font);
4069 ok(hr == E_FAIL, "got 0x%08x\n", hr);
4070 ok(font == NULL, "got %p\n", font);
4072 font = (void*)0xdeadbeef;
4073 hr = IDWriteFontList1_GetFont(fontlist1, count, &font);
4074 ok(hr == E_FAIL, "got 0x%08x\n", hr);
4075 ok(font == NULL, "got %p\n", font);
4077 hr = IDWriteFontList1_GetFont(fontlist1, 0, &font);
4078 ok(hr == S_OK, "got 0x%08x\n", hr);
4079 IDWriteFont3_Release(font);
4081 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref);
4082 ok(hr == S_OK, "got 0x%08x\n", hr);
4084 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref1);
4085 ok(hr == S_OK, "got 0x%08x\n", hr);
4086 ok(ref != ref1, "got %p, %p\n", ref, ref1);
4088 IDWriteFontFaceReference_Release(ref1);
4089 IDWriteFontFaceReference_Release(ref);
4090 IDWriteFontList1_Release(fontlist1);
4092 else
4093 win_skip("IDWriteFontList1 is not supported.\n");
4095 if (SUCCEEDED(IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList2, (void **)&fontlist3)))
4097 IDWriteFontSet1 *fontset, *fontset2;
4099 hr = IDWriteFontList2_GetFontSet(fontlist3, &fontset);
4100 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
4102 hr = IDWriteFontList2_GetFontSet(fontlist3, &fontset2);
4103 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
4104 ok(fontset != fontset2, "Unexpected instance.\n");
4106 IDWriteFontSet1_Release(fontset2);
4107 IDWriteFontSet1_Release(fontset);
4109 IDWriteFontList2_Release(fontlist3);
4111 else
4112 win_skip("IDWriteFontList2 is not supported.\n");
4114 IDWriteFontList_Release(fontlist);
4115 IDWriteFontFamily_Release(family);
4117 IDWriteFontCollection_Release(collection);
4118 ref = IDWriteFactory_Release(factory);
4119 ok(ref == 0, "factory not released, %u\n", ref);
4122 static void test_GetInformationalStrings(void)
4124 IDWriteLocalizedStrings *strings, *strings2;
4125 IDWriteFontCollection *collection;
4126 IDWriteFontFace3 *fontface3;
4127 IDWriteFontFace *fontface;
4128 IDWriteFontFamily *family;
4129 IDWriteFactory *factory;
4130 IDWriteFont *font;
4131 BOOL exists;
4132 HRESULT hr;
4133 ULONG ref;
4135 factory = create_factory();
4137 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4138 ok(hr == S_OK, "got 0x%08x\n", hr);
4140 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4141 ok(hr == S_OK, "got 0x%08x\n", hr);
4143 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4144 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4145 ok(hr == S_OK, "got 0x%08x\n", hr);
4147 exists = TRUE;
4148 strings = (void*)0xdeadbeef;
4149 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1, &strings, &exists);
4150 ok(hr == S_OK, "got 0x%08x\n", hr);
4151 ok(exists == FALSE, "got %d\n", exists);
4152 ok(strings == NULL, "got %p\n", strings);
4154 exists = TRUE;
4155 strings = NULL;
4156 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists);
4157 ok(hr == S_OK, "got 0x%08x\n", hr);
4158 ok(exists == FALSE, "got %d\n", exists);
4160 exists = FALSE;
4161 strings = NULL;
4162 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
4163 ok(hr == S_OK, "got 0x%08x\n", hr);
4164 ok(exists == TRUE, "got %d\n", exists);
4166 /* strings instance is not reused */
4167 strings2 = NULL;
4168 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings2, &exists);
4169 ok(hr == S_OK, "got 0x%08x\n", hr);
4170 ok(strings2 != strings, "got %p, %p\n", strings2, strings);
4172 IDWriteLocalizedStrings_Release(strings);
4173 IDWriteLocalizedStrings_Release(strings2);
4175 hr = IDWriteFont_CreateFontFace(font, &fontface);
4176 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
4178 if (SUCCEEDED(hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
4180 hr = IDWriteFontFace3_GetInformationalStrings(fontface3, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES,
4181 &strings, &exists);
4182 ok(hr == S_OK, "Failed to get info strings, hr %#x.\n", hr);
4183 IDWriteLocalizedStrings_Release(strings);
4185 IDWriteFontFace3_Release(fontface3);
4187 else
4188 win_skip("IDWriteFontFace3::GetInformationalStrings() is not supported.\n");
4190 IDWriteFontFace_Release(fontface);
4192 IDWriteFont_Release(font);
4193 IDWriteFontFamily_Release(family);
4194 IDWriteFontCollection_Release(collection);
4195 ref = IDWriteFactory_Release(factory);
4196 ok(ref == 0, "factory not released, %u\n", ref);
4199 static void test_GetGdiInterop(void)
4201 IDWriteGdiInterop *interop, *interop2;
4202 IDWriteFactory *factory, *factory2;
4203 IDWriteFont *font;
4204 LOGFONTW logfont;
4205 HRESULT hr;
4206 ULONG ref;
4208 factory = create_factory();
4210 interop = NULL;
4211 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4212 ok(hr == S_OK, "got 0x%08x\n", hr);
4214 interop2 = NULL;
4215 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
4216 ok(hr == S_OK, "got 0x%08x\n", hr);
4217 ok(interop == interop2, "got %p, %p\n", interop, interop2);
4218 IDWriteGdiInterop_Release(interop2);
4220 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory2);
4221 ok(hr == S_OK, "got 0x%08x\n", hr);
4223 /* each factory gets its own interop */
4224 interop2 = NULL;
4225 hr = IDWriteFactory_GetGdiInterop(factory2, &interop2);
4226 ok(hr == S_OK, "got 0x%08x\n", hr);
4227 ok(interop != interop2, "got %p, %p\n", interop, interop2);
4229 /* release factory - interop still works */
4230 IDWriteFactory_Release(factory2);
4232 memset(&logfont, 0, sizeof(logfont));
4233 logfont.lfHeight = 12;
4234 logfont.lfWidth = 12;
4235 logfont.lfWeight = FW_NORMAL;
4236 logfont.lfItalic = 1;
4237 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4239 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop2, &logfont, &font);
4240 ok(hr == S_OK, "got 0x%08x\n", hr);
4241 IDWriteFont_Release(font);
4243 IDWriteGdiInterop_Release(interop2);
4244 IDWriteGdiInterop_Release(interop);
4245 ref = IDWriteFactory_Release(factory);
4246 ok(ref == 0, "factory not released, %u\n", ref);
4249 static void *map_font_file(const WCHAR *filename, DWORD *file_size)
4251 HANDLE file, mapping;
4252 void *ptr;
4254 file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
4255 if (file == INVALID_HANDLE_VALUE) return NULL;
4257 *file_size = GetFileSize(file, NULL);
4259 mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
4260 if (!mapping)
4262 CloseHandle(file);
4263 return NULL;
4266 ptr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
4268 CloseHandle(file);
4269 CloseHandle(mapping);
4270 return ptr;
4273 struct font_realization_info
4275 DWORD size;
4276 DWORD flags;
4277 DWORD cache_num;
4278 DWORD instance_id;
4279 DWORD file_count;
4280 WORD face_index;
4281 WORD simulations;
4284 static void test_CreateFontFaceFromHdc(void)
4286 IDWriteFontFileStream *stream, *stream2;
4287 void *font_data, *fragment_context;
4288 struct font_realization_info info;
4289 const void *refkey, *fragment;
4290 IDWriteFontFileLoader *loader;
4291 DWORD data_size, num_fonts;
4292 IDWriteGdiInterop *interop;
4293 IDWriteFontFace *fontface;
4294 IDWriteFactory *factory;
4295 UINT64 size, writetime;
4296 IDWriteFontFile *file;
4297 HFONT hfont, oldhfont;
4298 UINT32 count, dummy;
4299 LOGFONTW logfont;
4300 HANDLE resource;
4301 IUnknown *unk;
4302 LOGFONTA lf;
4303 WCHAR *path;
4304 HRESULT hr;
4305 ULONG ref;
4306 BOOL ret;
4307 HDC hdc;
4309 factory = create_factory();
4311 pGetFontRealizationInfo = (void *)GetProcAddress(GetModuleHandleA("gdi32"), "GetFontRealizationInfo");
4313 interop = NULL;
4314 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4315 ok(hr == S_OK, "got 0x%08x\n", hr);
4317 /* Invalid HDC. */
4318 fontface = (void*)0xdeadbeef;
4319 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, NULL, &fontface);
4320 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4321 ok(fontface == NULL, "got %p\n", fontface);
4323 fontface = (void *)0xdeadbeef;
4324 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, (HDC)0xdeadbeef, &fontface);
4325 ok(hr == E_FAIL, "got 0x%08x\n", hr);
4326 ok(fontface == NULL, "got %p\n", fontface);
4328 memset(&logfont, 0, sizeof(logfont));
4329 logfont.lfHeight = 12;
4330 logfont.lfWidth = 12;
4331 logfont.lfWeight = FW_NORMAL;
4332 logfont.lfItalic = 1;
4333 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4335 hfont = CreateFontIndirectW(&logfont);
4336 hdc = CreateCompatibleDC(0);
4337 oldhfont = SelectObject(hdc, hfont);
4339 fontface = NULL;
4340 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4341 ok(hr == S_OK, "Failed to create font face, hr %#x.\n", hr);
4343 count = 1;
4344 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
4345 ok(hr == S_OK, "Failed to get font files, hr %#x.\n", hr);
4347 hr = IDWriteFontFile_GetLoader(file, &loader);
4348 ok(hr == S_OK, "Failed to get file loader, hr %#x.\n", hr);
4350 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void **)&unk);
4351 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Vista */, "Expected local loader, hr %#x.\n", hr);
4352 if (unk)
4353 IUnknown_Release(unk);
4355 IDWriteFontFileLoader_Release(loader);
4356 IDWriteFontFile_Release(file);
4358 IDWriteFontFace_Release(fontface);
4359 DeleteObject(SelectObject(hdc, oldhfont));
4361 /* Select bitmap font MS Sans Serif, format that's not supported by DirectWrite. */
4362 memset(&lf, 0, sizeof(lf));
4363 lf.lfHeight = -12;
4364 strcpy(lf.lfFaceName, "MS Sans Serif");
4366 hfont = CreateFontIndirectA(&lf);
4367 oldhfont = SelectObject(hdc, hfont);
4369 fontface = (void *)0xdeadbeef;
4370 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4371 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* Vista */, "got 0x%08x\n", hr);
4372 ok(fontface == NULL, "got %p\n", fontface);
4374 DeleteObject(SelectObject(hdc, oldhfont));
4376 /* Memory resource font */
4377 path = create_testfontfile(test_fontfile);
4379 data_size = 0;
4380 font_data = map_font_file(path, &data_size);
4382 num_fonts = 0;
4383 resource = AddFontMemResourceEx(font_data, data_size, NULL, &num_fonts);
4384 ok(resource != NULL, "Failed to add memory resource font, %d.\n", GetLastError());
4385 ok(num_fonts == 1, "Unexpected number of fonts.\n");
4387 memset(&lf, 0, sizeof(lf));
4388 lf.lfHeight = -12;
4389 strcpy(lf.lfFaceName, "wine_test");
4391 hfont = CreateFontIndirectA(&lf);
4392 ok(hfont != NULL, "Failed to create a font.\n");
4393 oldhfont = SelectObject(hdc, hfont);
4395 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
4396 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
4398 count = 1;
4399 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
4400 ok(hr == S_OK, "Failed to get font files, hr %#x.\n", hr);
4402 hr = IDWriteFontFile_GetLoader(file, &loader);
4403 ok(hr == S_OK, "Failed to get file loader, hr %#x.\n", hr);
4405 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
4406 ok(hr == DWRITE_E_ALREADYREGISTERED, "Unexpected hr %#x.\n", hr);
4408 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&unk);
4409 ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
4411 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void **)&unk);
4412 ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
4414 count = 0;
4415 hr = IDWriteFontFile_GetReferenceKey(file, &refkey, &count);
4416 ok(hr == S_OK, "Failed to get ref key, hr %#x.\n", hr);
4417 ok(count > 0, "Unexpected key length %u.\n", count);
4419 if (pGetFontRealizationInfo)
4421 info.size = sizeof(info);
4422 ret = pGetFontRealizationInfo(hdc, &info);
4423 ok(ret, "Failed to get realization info.\n");
4424 ok(count == sizeof(info.instance_id), "Unexpected key size.\n");
4425 ok(*(DWORD *)refkey == info.instance_id, "Unexpected stream key.\n");
4427 else
4428 win_skip("GetFontRealizationInfo() is not available.\n");
4430 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refkey, count, &stream);
4431 ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr);
4433 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, refkey, count, &stream2);
4434 ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr);
4435 ok(stream2 != stream, "Unexpected stream instance.\n");
4436 IDWriteFontFileStream_Release(stream2);
4438 dummy = 1;
4439 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, &dummy, count, &stream2);
4440 ok(hr == S_OK, "Failed to create file stream, hr %#x.\n", hr);
4442 writetime = 1;
4443 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
4444 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
4445 ok(writetime == 1, "Unexpected write time.\n");
4447 IDWriteFontFileStream_Release(stream2);
4449 hr = IDWriteFontFileStream_GetFileSize(stream, &size);
4450 ok(hr == S_OK, "Failed to get stream size, hr %#x.\n", hr);
4451 ok(size == data_size, "Unexpected stream size.\n");
4453 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4454 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
4456 fragment_context = NULL;
4457 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, size, &fragment_context);
4458 ok(hr == S_OK, "Failed to read fragment, hr %#x.\n", hr);
4459 ok(fragment_context != NULL, "Unexpected context %p.\n", fragment_context);
4460 ok(fragment == fragment_context, "Unexpected data pointer %p, context %p.\n", fragment, fragment_context);
4461 IDWriteFontFileStream_ReleaseFileFragment(stream, fragment_context);
4463 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, size + 1, &fragment_context);
4464 ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
4466 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, size - 1, size / 2, &fragment_context);
4467 ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
4469 IDWriteFontFileStream_Release(stream);
4471 IDWriteFontFileLoader_Release(loader);
4472 IDWriteFontFile_Release(file);
4474 IDWriteFontFace_Release(fontface);
4476 ret = RemoveFontMemResourceEx(resource);
4477 ok(ret, "Failed to remove memory resource font, %d.\n", GetLastError());
4479 UnmapViewOfFile(font_data);
4481 DELETE_FONTFILE(path);
4483 DeleteObject(SelectObject(hdc, oldhfont));
4484 DeleteDC(hdc);
4485 IDWriteGdiInterop_Release(interop);
4486 ref = IDWriteFactory_Release(factory);
4487 ok(ref == 0, "factory not released, %u\n", ref);
4490 static void test_GetSimulations(void)
4492 DWRITE_FONT_SIMULATIONS simulations;
4493 IDWriteGdiInterop *interop;
4494 IDWriteFontFace *fontface;
4495 IDWriteFactory *factory;
4496 IDWriteFont *font;
4497 LOGFONTW logfont;
4498 HRESULT hr;
4499 ULONG ref;
4501 factory = create_factory();
4503 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4504 ok(hr == S_OK, "got 0x%08x\n", hr);
4506 memset(&logfont, 0, sizeof(logfont));
4507 logfont.lfHeight = 12;
4508 logfont.lfWidth = 12;
4509 logfont.lfWeight = FW_NORMAL;
4510 logfont.lfItalic = 1;
4511 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4513 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4514 ok(hr == S_OK, "got 0x%08x\n", hr);
4516 simulations = IDWriteFont_GetSimulations(font);
4517 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
4518 hr = IDWriteFont_CreateFontFace(font, &fontface);
4519 ok(hr == S_OK, "got 0x%08x\n", hr);
4520 simulations = IDWriteFontFace_GetSimulations(fontface);
4521 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
4522 IDWriteFontFace_Release(fontface);
4523 IDWriteFont_Release(font);
4525 memset(&logfont, 0, sizeof(logfont));
4526 logfont.lfHeight = 12;
4527 logfont.lfWidth = 12;
4528 logfont.lfWeight = FW_NORMAL;
4529 logfont.lfItalic = 0;
4530 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4532 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4533 ok(hr == S_OK, "got 0x%08x\n", hr);
4535 simulations = IDWriteFont_GetSimulations(font);
4536 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
4537 hr = IDWriteFont_CreateFontFace(font, &fontface);
4538 ok(hr == S_OK, "got 0x%08x\n", hr);
4539 simulations = IDWriteFontFace_GetSimulations(fontface);
4540 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
4541 IDWriteFontFace_Release(fontface);
4542 IDWriteFont_Release(font);
4544 IDWriteGdiInterop_Release(interop);
4545 ref = IDWriteFactory_Release(factory);
4546 ok(ref == 0, "factory not released, %u\n", ref);
4549 static void test_GetFaceNames(void)
4551 IDWriteLocalizedStrings *strings, *strings2, *strings3;
4552 IDWriteFontFace3 *fontface3;
4553 IDWriteGdiInterop *interop;
4554 IDWriteFontFace *fontface;
4555 IDWriteFactory *factory;
4556 UINT32 count, index;
4557 IDWriteFont *font;
4558 LOGFONTW logfont;
4559 WCHAR buffW[255];
4560 BOOL exists;
4561 HRESULT hr;
4562 ULONG ref;
4564 factory = create_factory();
4566 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4567 ok(hr == S_OK, "got 0x%08x\n", hr);
4569 memset(&logfont, 0, sizeof(logfont));
4570 logfont.lfHeight = 12;
4571 logfont.lfWidth = 12;
4572 logfont.lfWeight = FW_NORMAL;
4573 logfont.lfItalic = 1;
4574 lstrcpyW(logfont.lfFaceName, L"Tahoma");
4576 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
4577 ok(hr == S_OK, "got 0x%08x\n", hr);
4579 hr = IDWriteFont_GetFaceNames(font, &strings);
4580 ok(hr == S_OK, "got 0x%08x\n", hr);
4582 hr = IDWriteFont_GetFaceNames(font, &strings2);
4583 ok(hr == S_OK, "got 0x%08x\n", hr);
4584 ok(strings != strings2, "got %p, %p\n", strings2, strings);
4585 IDWriteLocalizedStrings_Release(strings2);
4587 count = IDWriteLocalizedStrings_GetCount(strings);
4588 ok(count == 1, "got %d\n", count);
4590 index = 1;
4591 exists = FALSE;
4592 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-Us", &index, &exists);
4593 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
4594 ok(index == 0 && exists, "got %d, %d\n", index, exists);
4596 count = 0;
4597 hr = IDWriteLocalizedStrings_GetLocaleNameLength(strings, 1, &count);
4598 ok(hr == E_FAIL, "got 0x%08x\n", hr);
4599 ok(count == ~0, "got %d\n", count);
4601 /* for simulated faces names are also simulated */
4602 buffW[0] = 0;
4603 hr = IDWriteLocalizedStrings_GetLocaleName(strings, 0, buffW, ARRAY_SIZE(buffW));
4604 ok(hr == S_OK, "got 0x%08x\n", hr);
4605 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
4607 buffW[0] = 0;
4608 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
4609 ok(hr == S_OK, "got 0x%08x\n", hr);
4610 ok(!lstrcmpW(buffW, L"Oblique"), "got %s\n", wine_dbgstr_w(buffW));
4611 IDWriteLocalizedStrings_Release(strings);
4613 hr = IDWriteFont_CreateFontFace(font, &fontface);
4614 ok(hr == S_OK, "Failed to create a font face, hr %#x.\n", hr);
4616 if (SUCCEEDED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3)))
4618 hr = IDWriteFontFace3_GetFaceNames(fontface3, &strings2);
4619 ok(hr == S_OK, "Failed to get face names, hr %#x.\n", hr);
4621 hr = IDWriteFontFace3_GetFaceNames(fontface3, &strings3);
4622 ok(hr == S_OK, "Failed to get face names, hr %#x.\n", hr);
4623 ok(strings2 != strings3, "Unexpected instance.\n");
4624 IDWriteLocalizedStrings_Release(strings3);
4626 buffW[0] = 0;
4627 hr = IDWriteLocalizedStrings_GetString(strings2, 0, buffW, ARRAY_SIZE(buffW));
4628 ok(hr == S_OK, "Failed to get a string, hr %#x.\n", hr);
4629 ok(!lstrcmpW(buffW, L"Oblique"), "Unexpected name %s.\n", wine_dbgstr_w(buffW));
4630 IDWriteLocalizedStrings_Release(strings2);
4632 IDWriteFontFace3_Release(fontface3);
4634 else
4635 win_skip("GetFaceNames() is not supported.\n");
4637 IDWriteFontFace_Release(fontface);
4639 IDWriteFont_Release(font);
4640 IDWriteGdiInterop_Release(interop);
4641 ref = IDWriteFactory_Release(factory);
4642 ok(ref == 0, "factory not released, %u\n", ref);
4645 struct local_refkey
4647 FILETIME writetime;
4648 WCHAR name[1];
4651 static void test_TryGetFontTable(void)
4653 IDWriteLocalFontFileLoader *localloader;
4654 WIN32_FILE_ATTRIBUTE_DATA info;
4655 const struct local_refkey *key;
4656 IDWriteFontFileLoader *loader;
4657 const void *table, *table2;
4658 IDWriteFontFace *fontface;
4659 void *context, *context2;
4660 IDWriteFactory *factory;
4661 IDWriteFontFile *file;
4662 WCHAR buffW[MAX_PATH];
4663 BOOL exists, ret;
4664 UINT32 size, len;
4665 WCHAR *path;
4666 HRESULT hr;
4667 ULONG ref;
4669 path = create_testfontfile(test_fontfile);
4671 factory = create_factory();
4673 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4674 ok(hr == S_OK, "got 0x%08x\n",hr);
4676 key = NULL;
4677 size = 0;
4678 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4679 ok(hr == S_OK, "got 0x%08x\n", hr);
4680 ok(size != 0, "got %u\n", size);
4682 ret = GetFileAttributesExW(path, GetFileExInfoStandard, &info);
4683 ok(ret, "got %d\n", ret);
4684 ok(!memcmp(&info.ftLastWriteTime, &key->writetime, sizeof(key->writetime)), "got wrong write time\n");
4686 hr = IDWriteFontFile_GetLoader(file, &loader);
4687 ok(hr == S_OK, "got 0x%08x\n", hr);
4688 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4689 IDWriteFontFileLoader_Release(loader);
4691 hr = IDWriteLocalFontFileLoader_GetFilePathLengthFromKey(localloader, key, size, &len);
4692 ok(hr == S_OK, "got 0x%08x\n", hr);
4693 ok(lstrlenW(key->name) == len, "path length %d\n", len);
4695 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, size, buffW, ARRAY_SIZE(buffW));
4696 ok(hr == S_OK, "got 0x%08x\n", hr);
4697 ok(!lstrcmpW(buffW, key->name), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(key->name));
4698 IDWriteLocalFontFileLoader_Release(localloader);
4700 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, 0, &fontface);
4701 ok(hr == S_OK, "got 0x%08x\n",hr);
4703 exists = FALSE;
4704 context = (void*)0xdeadbeef;
4705 table = NULL;
4706 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table, &size, &context, &exists);
4707 ok(hr == S_OK, "got 0x%08x\n",hr);
4708 ok(exists == TRUE, "got %d\n", exists);
4709 ok(context == NULL && table != NULL, "cmap: context %p, table %p\n", context, table);
4711 exists = FALSE;
4712 context2 = (void*)0xdeadbeef;
4713 table2 = NULL;
4714 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table2, &size, &context2, &exists);
4715 ok(hr == S_OK, "got 0x%08x\n",hr);
4716 ok(exists == TRUE, "got %d\n", exists);
4717 ok(context2 == context && table2 == table, "cmap: context2 %p, table2 %p\n", context2, table2);
4719 IDWriteFontFace_ReleaseFontTable(fontface, context2);
4720 IDWriteFontFace_ReleaseFontTable(fontface, context);
4722 /* table does not exist */
4723 exists = TRUE;
4724 context = (void*)0xdeadbeef;
4725 table = (void*)0xdeadbeef;
4726 hr = IDWriteFontFace_TryGetFontTable(fontface, 0xabababab, &table, &size, &context, &exists);
4727 ok(hr == S_OK, "got 0x%08x\n", hr);
4728 ok(exists == FALSE, "got %d\n", exists);
4729 ok(context == NULL && table == NULL, "got context %p, table pointer %p\n", context, table);
4731 IDWriteFontFace_Release(fontface);
4732 IDWriteFontFile_Release(file);
4733 ref = IDWriteFactory_Release(factory);
4734 ok(ref == 0, "factory not released, %u\n", ref);
4735 DELETE_FONTFILE(path);
4738 static void test_ConvertFontToLOGFONT(void)
4740 IDWriteFactory *factory, *factory2;
4741 IDWriteFontCollection *collection;
4742 IDWriteGdiInterop *interop;
4743 IDWriteFontFamily *family;
4744 IDWriteFont *font;
4745 LOGFONTW logfont;
4746 UINT32 i, count;
4747 BOOL system;
4748 HRESULT hr;
4749 ULONG ref;
4751 factory = create_factory();
4752 factory2 = create_factory();
4754 interop = NULL;
4755 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
4756 ok(hr == S_OK, "got 0x%08x\n", hr);
4758 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection, FALSE);
4759 ok(hr == S_OK, "got 0x%08x\n", hr);
4761 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
4762 ok(hr == S_OK, "got 0x%08x\n", hr);
4764 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4765 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4766 ok(hr == S_OK, "got 0x%08x\n", hr);
4768 if (0) { /* crashes on native */
4769 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, NULL, NULL);
4770 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, NULL);
4771 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, NULL, &system);
4774 memset(&logfont, 0xcc, sizeof(logfont));
4775 system = TRUE;
4776 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, &system);
4777 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4778 ok(!system, "got %d\n", system);
4779 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
4781 count = IDWriteFontCollection_GetFontFamilyCount(collection);
4782 for (i = 0; i < count; i++) {
4783 WCHAR nameW[128], familynameW[64], facenameW[64];
4784 IDWriteLocalizedStrings *names;
4785 DWRITE_FONT_SIMULATIONS sim;
4786 IDWriteFontFamily *family;
4787 UINT32 font_count, j;
4788 IDWriteFont *font;
4789 LOGFONTW lf;
4791 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
4792 ok(hr == S_OK, "got 0x%08x\n", hr);
4794 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
4795 ok(hr == S_OK, "got 0x%08x\n", hr);
4797 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
4798 IDWriteLocalizedStrings_Release(names);
4800 font_count = IDWriteFontFamily_GetFontCount(family);
4802 for (j = 0; j < font_count; ++j)
4804 IDWriteFontFace *fontface;
4805 BOOL has_variations;
4807 hr = IDWriteFontFamily_GetFont(family, j, &font);
4808 ok(hr == S_OK, "got 0x%08x\n", hr);
4810 hr = IDWriteFont_GetFaceNames(font, &names);
4811 ok(hr == S_OK, "got 0x%08x\n", hr);
4813 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
4814 IDWriteLocalizedStrings_Release(names);
4816 lstrcpyW(nameW, familynameW);
4817 lstrcatW(nameW, L" ");
4818 lstrcatW(nameW, facenameW);
4820 hr = IDWriteFont_CreateFontFace(font, &fontface);
4821 ok(hr == S_OK, "got 0x%08x\n", hr);
4823 has_variations = has_face_variations(fontface);
4824 IDWriteFontFace_Release(fontface);
4826 if (has_variations)
4828 static int once;
4829 if (!once++)
4830 skip("ConvertFontToLOGFONT() test does not support variable fonts.\n");
4831 IDWriteFont_Release(font);
4832 continue;
4835 system = FALSE;
4836 memset(&logfont, 0xcc, sizeof(logfont));
4837 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, &logfont, &system);
4838 ok(hr == S_OK, "got 0x%08x\n", hr);
4839 ok(system, "got %d\n", system);
4841 sim = IDWriteFont_GetSimulations(font);
4843 get_logfont_from_font(font, &lf);
4844 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
4845 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
4846 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
4847 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
4848 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
4849 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
4850 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
4852 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
4853 logfont.lfOutPrecision);
4854 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
4855 logfont.lfClipPrecision);
4856 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
4857 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
4858 logfont.lfPitchAndFamily);
4860 IDWriteFont_Release(font);
4863 IDWriteFontFamily_Release(family);
4866 IDWriteFactory_Release(factory2);
4868 IDWriteFontCollection_Release(collection);
4869 IDWriteFontFamily_Release(family);
4870 IDWriteFont_Release(font);
4871 IDWriteGdiInterop_Release(interop);
4872 ref = IDWriteFactory_Release(factory);
4873 ok(ref == 0, "factory not released, %u\n", ref);
4876 static void test_CreateStreamFromKey(void)
4878 IDWriteLocalFontFileLoader *localloader;
4879 IDWriteFontFileStream *stream, *stream2;
4880 IDWriteFontFileLoader *loader;
4881 IDWriteFactory *factory;
4882 IDWriteFontFile *file;
4883 UINT64 writetime;
4884 WCHAR *path;
4885 void *key;
4886 UINT32 size;
4887 HRESULT hr;
4888 ULONG ref;
4890 factory = create_factory();
4892 path = create_testfontfile(test_fontfile);
4894 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4895 ok(hr == S_OK, "got 0x%08x\n",hr);
4897 key = NULL;
4898 size = 0;
4899 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4900 ok(hr == S_OK, "got 0x%08x\n", hr);
4901 ok(size != 0, "got %u\n", size);
4903 hr = IDWriteFontFile_GetLoader(file, &loader);
4904 ok(hr == S_OK, "got 0x%08x\n", hr);
4905 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4906 IDWriteFontFileLoader_Release(loader);
4908 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4909 ok(hr == S_OK, "got 0x%08x\n", hr);
4910 EXPECT_REF(stream, 1);
4912 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2);
4913 ok(hr == S_OK, "got 0x%08x\n", hr);
4914 ok(stream == stream2 || broken(stream != stream2) /* Win7 SP0 */, "got %p, %p\n", stream, stream2);
4915 if (stream == stream2)
4916 EXPECT_REF(stream, 2);
4917 IDWriteFontFileStream_Release(stream);
4918 IDWriteFontFileStream_Release(stream2);
4920 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4921 ok(hr == S_OK, "got 0x%08x\n", hr);
4922 EXPECT_REF(stream, 1);
4924 writetime = 0;
4925 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4926 ok(hr == S_OK, "got 0x%08x\n", hr);
4927 ok(writetime != 0, "got %s\n", wine_dbgstr_longlong(writetime));
4929 IDWriteFontFileStream_Release(stream);
4930 IDWriteFontFile_Release(file);
4932 IDWriteLocalFontFileLoader_Release(localloader);
4933 ref = IDWriteFactory_Release(factory);
4934 ok(ref == 0, "factory not released, %u\n", ref);
4935 DELETE_FONTFILE(path);
4938 static void test_ReadFileFragment(void)
4940 IDWriteLocalFontFileLoader *localloader;
4941 IDWriteFontFileStream *stream;
4942 IDWriteFontFileLoader *loader;
4943 IDWriteFactory *factory;
4944 IDWriteFontFile *file;
4945 const void *fragment, *fragment2;
4946 void *key, *context, *context2;
4947 UINT64 filesize;
4948 UINT32 size;
4949 WCHAR *path;
4950 HRESULT hr;
4951 ULONG ref;
4953 factory = create_factory();
4955 path = create_testfontfile(test_fontfile);
4957 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4958 ok(hr == S_OK, "got 0x%08x\n",hr);
4960 key = NULL;
4961 size = 0;
4962 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4963 ok(hr == S_OK, "got 0x%08x\n", hr);
4964 ok(size != 0, "got %u\n", size);
4966 hr = IDWriteFontFile_GetLoader(file, &loader);
4967 ok(hr == S_OK, "got 0x%08x\n", hr);
4968 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4969 IDWriteFontFileLoader_Release(loader);
4971 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4972 ok(hr == S_OK, "got 0x%08x\n", hr);
4974 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
4975 ok(hr == S_OK, "got 0x%08x\n", hr);
4977 /* reading past the end of the stream */
4978 fragment = (void*)0xdeadbeef;
4979 context = (void*)0xdeadbeef;
4980 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize+1, &context);
4981 ok(hr == E_FAIL, "got 0x%08x\n", hr);
4982 ok(context == NULL, "got %p\n", context);
4983 ok(fragment == NULL, "got %p\n", fragment);
4985 fragment = (void*)0xdeadbeef;
4986 context = (void*)0xdeadbeef;
4987 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
4988 ok(hr == S_OK, "got 0x%08x\n", hr);
4989 ok(context == NULL, "got %p\n", context);
4990 ok(fragment != NULL, "got %p\n", fragment);
4992 fragment2 = (void*)0xdeadbeef;
4993 context2 = (void*)0xdeadbeef;
4994 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment2, 0, filesize, &context2);
4995 ok(hr == S_OK, "got 0x%08x\n", hr);
4996 ok(context2 == NULL, "got %p\n", context2);
4997 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
4999 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
5000 IDWriteFontFileStream_ReleaseFileFragment(stream, context2);
5002 /* fragment is released, try again */
5003 fragment = (void*)0xdeadbeef;
5004 context = (void*)0xdeadbeef;
5005 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
5006 ok(hr == S_OK, "got 0x%08x\n", hr);
5007 ok(context == NULL, "got %p\n", context);
5008 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
5009 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
5011 IDWriteFontFile_Release(file);
5012 IDWriteFontFileStream_Release(stream);
5013 IDWriteLocalFontFileLoader_Release(localloader);
5014 ref = IDWriteFactory_Release(factory);
5015 ok(ref == 0, "factory not released, %u\n", ref);
5016 DELETE_FONTFILE(path);
5019 static void test_GetDesignGlyphMetrics(void)
5021 DWRITE_GLYPH_METRICS metrics[2];
5022 IDWriteFontFace *fontface;
5023 IDWriteFactory *factory;
5024 IDWriteFontFile *file;
5025 UINT16 indices[2];
5026 UINT32 codepoint;
5027 WCHAR *path;
5028 HRESULT hr;
5029 ULONG ref;
5031 factory = create_factory();
5033 path = create_testfontfile(test_fontfile);
5035 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5036 ok(hr == S_OK, "got 0x%08x\n",hr);
5038 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
5039 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5040 ok(hr == S_OK, "got 0x%08x\n",hr);
5041 IDWriteFontFile_Release(file);
5043 codepoint = 'A';
5044 indices[0] = 0;
5045 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &indices[0]);
5046 ok(hr == S_OK, "got 0x%08x\n", hr);
5047 ok(indices[0] > 0, "got %u\n", indices[0]);
5049 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 0, metrics, FALSE);
5050 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
5052 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 1, metrics, FALSE);
5053 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
5055 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 0, metrics, FALSE);
5056 ok(hr == S_OK, "got 0x%08x\n",hr);
5058 /* missing glyphs are ignored */
5059 indices[1] = 1;
5060 memset(metrics, 0xcc, sizeof(metrics));
5061 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 2, metrics, FALSE);
5062 ok(hr == S_OK, "got 0x%08x\n",hr);
5063 ok(metrics[0].advanceWidth == 1000, "got %d\n", metrics[0].advanceWidth);
5064 ok(metrics[1].advanceWidth == 0, "got %d\n", metrics[1].advanceWidth);
5066 IDWriteFontFace_Release(fontface);
5067 ref = IDWriteFactory_Release(factory);
5068 ok(ref == 0, "factory not released, %u\n", ref);
5069 DELETE_FONTFILE(path);
5072 static BOOL get_expected_is_monospaced(IDWriteFontFace1 *fontface, const DWRITE_PANOSE *panose)
5074 BOOL exists, is_monospaced = FALSE;
5075 const TT_POST *tt_post;
5076 void *post_context;
5077 UINT32 size;
5078 HRESULT hr;
5080 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_POST_TAG, (const void **)&tt_post, &size,
5081 &post_context, &exists);
5082 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5084 if (tt_post)
5086 is_monospaced = !!tt_post->fixed_pitch;
5087 IDWriteFontFace1_ReleaseFontTable(fontface, post_context);
5090 if (!is_monospaced)
5091 is_monospaced |= panose->text.proportion == DWRITE_PANOSE_PROPORTION_MONOSPACED;
5093 return is_monospaced;
5096 static void test_IsMonospacedFont(void)
5098 IDWriteFontCollection *collection;
5099 IDWriteFactory1 *factory;
5100 UINT32 count, i;
5101 HRESULT hr;
5102 ULONG ref;
5104 factory = create_factory_iid(&IID_IDWriteFactory1);
5106 if (!factory)
5108 win_skip("IsMonospacedFont() is not supported.\n");
5109 return;
5112 hr = IDWriteFactory1_GetSystemFontCollection(factory, &collection, FALSE);
5113 ok(hr == S_OK, "Failed to get font collection, hr %#x.\n", hr);
5115 count = IDWriteFontCollection_GetFontFamilyCount(collection);
5116 for (i = 0; i < count; ++i)
5118 IDWriteLocalizedStrings *names;
5119 IDWriteFontFamily *family;
5120 UINT32 font_count, j;
5121 WCHAR nameW[256];
5123 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
5124 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
5126 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
5127 ok(hr == S_OK, "Failed to get names, hr %#x.\n", hr);
5128 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
5129 IDWriteLocalizedStrings_Release(names);
5131 font_count = IDWriteFontFamily_GetFontCount(family);
5133 for (j = 0; j < font_count; ++j)
5135 BOOL is_monospaced_font, is_monospaced_face, is_monospaced_expected;
5136 IDWriteFontFace1 *fontface1;
5137 IDWriteFontFace *fontface;
5138 DWRITE_PANOSE panose;
5139 IDWriteFont1 *font1;
5140 IDWriteFont *font;
5142 hr = IDWriteFontFamily_GetFont(family, j, &font);
5143 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
5145 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
5146 ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
5147 IDWriteFont_Release(font);
5149 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
5150 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
5152 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
5153 ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
5154 IDWriteFontFace_Release(fontface);
5156 is_monospaced_font = IDWriteFont1_IsMonospacedFont(font1);
5157 is_monospaced_face = IDWriteFontFace1_IsMonospacedFont(fontface1);
5158 ok(is_monospaced_font == is_monospaced_face, "Unexpected monospaced flag.\n");
5160 IDWriteFont1_GetPanose(font1, &panose);
5162 is_monospaced_expected = get_expected_is_monospaced(fontface1, &panose);
5163 ok(is_monospaced_expected == is_monospaced_face, "Unexpected is_monospaced flag %d for %s, font %d.\n",
5164 is_monospaced_face, wine_dbgstr_w(nameW), j);
5166 IDWriteFontFace1_Release(fontface1);
5167 IDWriteFont1_Release(font1);
5170 IDWriteFontFamily_Release(family);
5173 IDWriteFontCollection_Release(collection);
5174 ref = IDWriteFactory1_Release(factory);
5175 ok(ref == 0, "factory not released, %u\n", ref);
5178 static void test_GetDesignGlyphAdvances(void)
5180 IDWriteFontFace1 *fontface1;
5181 IDWriteFontFace *fontface;
5182 IDWriteFactory *factory;
5183 IDWriteFontFile *file;
5184 WCHAR *path;
5185 HRESULT hr;
5186 ULONG ref;
5188 factory = create_factory();
5190 path = create_testfontfile(test_fontfile);
5192 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5193 ok(hr == S_OK, "got 0x%08x\n", hr);
5195 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
5196 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5197 ok(hr == S_OK, "got 0x%08x\n", hr);
5198 IDWriteFontFile_Release(file);
5200 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5201 if (hr == S_OK) {
5202 UINT32 codepoint;
5203 UINT16 index;
5204 INT32 advance;
5206 codepoint = 'A';
5207 index = 0;
5208 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &index);
5209 ok(hr == S_OK, "got 0x%08x\n", hr);
5210 ok(index > 0, "got %u\n", index);
5212 advance = 0;
5213 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, FALSE);
5214 ok(hr == S_OK, "got 0x%08x\n", hr);
5215 ok(advance == 1000, "got %i\n", advance);
5217 advance = 0;
5218 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, TRUE);
5219 ok(hr == S_OK, "got 0x%08x\n", hr);
5220 todo_wine
5221 ok(advance == 2048, "got %i\n", advance);
5223 IDWriteFontFace1_Release(fontface1);
5225 else
5226 win_skip("GetDesignGlyphAdvances() is not supported.\n");
5228 IDWriteFontFace_Release(fontface);
5229 ref = IDWriteFactory_Release(factory);
5230 ok(ref == 0, "factory not released, %u\n", ref);
5231 DELETE_FONTFILE(path);
5234 static void test_GetGlyphRunOutline(void)
5236 DWRITE_GLYPH_OFFSET offsets[2];
5237 IDWriteFactory *factory;
5238 IDWriteFontFile *file;
5239 IDWriteFontFace *face;
5240 UINT32 codepoint;
5241 FLOAT advances[2];
5242 UINT16 glyphs[2];
5243 WCHAR *path;
5244 HRESULT hr;
5245 ULONG ref;
5247 path = create_testfontfile(test_fontfile);
5248 factory = create_factory();
5250 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5251 ok(hr == S_OK, "got 0x%08x\n",hr);
5253 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
5254 ok(hr == S_OK, "got 0x%08x\n", hr);
5255 IDWriteFontFile_Release(file);
5257 codepoint = 'A';
5258 glyphs[0] = 0;
5259 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5260 ok(hr == S_OK, "got 0x%08x\n", hr);
5261 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5262 glyphs[1] = glyphs[0];
5264 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, glyphs, advances, offsets, 1, FALSE, FALSE, NULL);
5265 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5267 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, NULL, NULL, offsets, 1, FALSE, FALSE, &test_geomsink);
5268 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5270 advances[0] = 1.0;
5271 advances[1] = 0.0;
5273 offsets[0].advanceOffset = 1.0;
5274 offsets[0].ascenderOffset = 1.0;
5275 offsets[1].advanceOffset = 0.0;
5276 offsets[1].ascenderOffset = 0.0;
5278 /* default advances, no offsets */
5279 memset(g_startpoints, 0, sizeof(g_startpoints));
5280 g_startpoint_count = 0;
5281 SET_EXPECT(setfillmode);
5282 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, FALSE, &test_geomsink);
5283 ok(hr == S_OK, "got 0x%08x\n", hr);
5284 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5285 if (g_startpoint_count == 2) {
5286 /* glyph advance of 500 is applied */
5287 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);
5288 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);
5290 CHECK_CALLED(setfillmode);
5292 /* default advances, no offsets, RTL */
5293 memset(g_startpoints, 0, sizeof(g_startpoints));
5294 g_startpoint_count = 0;
5295 SET_EXPECT(setfillmode);
5296 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, TRUE, &test_geomsink);
5297 ok(hr == S_OK, "got 0x%08x\n", hr);
5298 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5299 if (g_startpoint_count == 2) {
5300 /* advance is -500 now */
5301 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);
5302 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);
5304 CHECK_CALLED(setfillmode);
5306 /* default advances, additional offsets */
5307 memset(g_startpoints, 0, sizeof(g_startpoints));
5308 g_startpoint_count = 0;
5309 SET_EXPECT(setfillmode);
5310 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, FALSE, &test_geomsink);
5311 ok(hr == S_OK, "got 0x%08x\n", hr);
5312 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5313 if (g_startpoint_count == 2) {
5314 /* offsets applied to first contour */
5315 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);
5316 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);
5318 CHECK_CALLED(setfillmode);
5320 /* default advances, additional offsets, RTL */
5321 memset(g_startpoints, 0, sizeof(g_startpoints));
5322 g_startpoint_count = 0;
5323 SET_EXPECT(setfillmode);
5324 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, TRUE, &test_geomsink);
5325 ok(hr == S_OK, "got 0x%08x\n", hr);
5326 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5327 if (g_startpoint_count == 2) {
5328 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);
5329 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);
5331 CHECK_CALLED(setfillmode);
5333 /* custom advances and offsets, offset turns total advance value to zero */
5334 memset(g_startpoints, 0, sizeof(g_startpoints));
5335 g_startpoint_count = 0;
5336 SET_EXPECT(setfillmode);
5337 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, advances, offsets, 2, FALSE, FALSE, &test_geomsink);
5338 ok(hr == S_OK, "got 0x%08x\n", hr);
5339 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
5340 if (g_startpoint_count == 2) {
5341 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);
5342 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);
5344 CHECK_CALLED(setfillmode);
5346 /* 0 glyph count */
5347 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 0, FALSE, FALSE, &test_geomsink2);
5348 ok(hr == S_OK, "got 0x%08x\n", hr);
5350 /* Glyph with open figure, single contour point. */
5351 codepoint = 'B';
5352 glyphs[0] = 0;
5353 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5354 ok(hr == S_OK, "got 0x%08x\n", hr);
5355 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5357 SET_EXPECT(setfillmode);
5358 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
5359 ok(hr == S_OK, "got 0x%08x\n", hr);
5360 CHECK_CALLED(setfillmode);
5362 IDWriteFactory_Release(factory);
5363 IDWriteFontFace_Release(face);
5364 DELETE_FONTFILE(path);
5366 /* space glyph */
5367 factory = create_factory();
5368 face = create_fontface(factory);
5370 codepoint = ' ';
5371 glyphs[0] = 0;
5372 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
5373 ok(hr == S_OK, "got 0x%08x\n", hr);
5374 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
5376 SET_EXPECT(setfillmode);
5377 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
5378 ok(hr == S_OK, "got 0x%08x\n", hr);
5379 CHECK_CALLED(setfillmode);
5381 IDWriteFontFace_Release(face);
5382 ref = IDWriteFactory_Release(factory);
5383 ok(ref == 0, "factory not released, %u\n", ref);
5386 static void test_GetEudcFontCollection(void)
5388 IDWriteFontCollection *coll, *coll2;
5389 IDWriteFactory1 *factory;
5390 HRESULT hr;
5391 ULONG ref;
5393 factory = create_factory_iid(&IID_IDWriteFactory1);
5394 if (!factory) {
5395 win_skip("GetEudcFontCollection() is not supported.\n");
5396 return;
5399 EXPECT_REF(factory, 1);
5400 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll, FALSE);
5401 ok(hr == S_OK, "got 0x%08x\n", hr);
5402 EXPECT_REF(factory, 2);
5403 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll2, FALSE);
5404 ok(hr == S_OK, "got 0x%08x\n", hr);
5405 EXPECT_REF(factory, 2);
5406 ok(coll == coll2, "got %p, %p\n", coll, coll2);
5407 IDWriteFontCollection_Release(coll);
5408 IDWriteFontCollection_Release(coll2);
5410 ref = IDWriteFactory1_Release(factory);
5411 ok(ref == 0, "factory not released, %u\n", ref);
5414 static void test_GetCaretMetrics(void)
5416 DWRITE_FONT_METRICS1 metrics;
5417 IDWriteFontFace1 *fontface1;
5418 DWRITE_CARET_METRICS caret;
5419 IDWriteFontFace *fontface;
5420 IDWriteFactory *factory;
5421 IDWriteFontFile *file;
5422 IDWriteFont *font;
5423 WCHAR *path;
5424 HRESULT hr;
5425 ULONG ref;
5427 path = create_testfontfile(test_fontfile);
5428 factory = create_factory();
5430 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5431 ok(hr == S_OK, "got 0x%08x\n", hr);
5433 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5434 ok(hr == S_OK, "got 0x%08x\n", hr);
5435 IDWriteFontFile_Release(file);
5437 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5438 IDWriteFontFace_Release(fontface);
5439 if (hr != S_OK) {
5440 win_skip("GetCaretMetrics() is not supported.\n");
5441 ref = IDWriteFactory_Release(factory);
5442 ok(ref == 0, "factory not released, %u\n", ref);
5443 DELETE_FONTFILE(path);
5444 return;
5447 memset(&caret, 0xcc, sizeof(caret));
5448 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5449 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
5450 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
5451 ok(caret.offset == 0, "got %d\n", caret.offset);
5452 IDWriteFontFace1_Release(fontface1);
5453 IDWriteFactory_Release(factory);
5455 /* now with Tahoma Normal */
5456 factory = create_factory();
5457 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5458 hr = IDWriteFont_CreateFontFace(font, &fontface);
5459 ok(hr == S_OK, "got 0x%08x\n", hr);
5460 IDWriteFont_Release(font);
5461 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5462 ok(hr == S_OK, "got 0x%08x\n", hr);
5463 IDWriteFontFace_Release(fontface);
5465 memset(&caret, 0xcc, sizeof(caret));
5466 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5467 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
5468 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
5469 ok(caret.offset == 0, "got %d\n", caret.offset);
5470 IDWriteFontFace1_Release(fontface1);
5472 /* simulated italic */
5473 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
5474 hr = IDWriteFont_CreateFontFace(font, &fontface);
5475 ok(hr == S_OK, "got 0x%08x\n", hr);
5476 IDWriteFont_Release(font);
5477 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5478 ok(hr == S_OK, "got 0x%08x\n", hr);
5479 IDWriteFontFace_Release(fontface);
5481 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
5483 memset(&caret, 0xcc, sizeof(caret));
5484 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
5485 ok(caret.slopeRise == metrics.designUnitsPerEm, "got %d\n", caret.slopeRise);
5486 ok(caret.slopeRun > 0, "got %d\n", caret.slopeRun);
5487 ok(caret.offset == 0, "got %d\n", caret.offset);
5488 IDWriteFontFace1_Release(fontface1);
5490 ref = IDWriteFactory_Release(factory);
5491 ok(ref == 0, "factory not released, %u\n", ref);
5492 DELETE_FONTFILE(path);
5495 static void test_GetGlyphCount(void)
5497 IDWriteFontFace *fontface;
5498 IDWriteFactory *factory;
5499 IDWriteFontFile *file;
5500 UINT16 count;
5501 WCHAR *path;
5502 HRESULT hr;
5503 ULONG ref;
5505 path = create_testfontfile(test_fontfile);
5506 factory = create_factory();
5508 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5509 ok(hr == S_OK, "got 0x%08x\n", hr);
5511 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5512 ok(hr == S_OK, "got 0x%08x\n", hr);
5513 IDWriteFontFile_Release(file);
5515 count = IDWriteFontFace_GetGlyphCount(fontface);
5516 ok(count == 8, "got %u\n", count);
5518 IDWriteFontFace_Release(fontface);
5519 ref = IDWriteFactory_Release(factory);
5520 ok(ref == 0, "factory not released, %u\n", ref);
5521 DELETE_FONTFILE(path);
5524 static void test_GetKerningPairAdjustments(void)
5526 IDWriteFontFace1 *fontface1;
5527 IDWriteFontFace *fontface;
5528 IDWriteFactory *factory;
5529 IDWriteFontFile *file;
5530 WCHAR *path;
5531 HRESULT hr;
5532 ULONG ref;
5534 path = create_testfontfile(test_fontfile);
5535 factory = create_factory();
5537 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
5538 ok(hr == S_OK, "got 0x%08x\n", hr);
5540 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
5541 ok(hr == S_OK, "got 0x%08x\n", hr);
5542 IDWriteFontFile_Release(file);
5544 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5545 if (hr == S_OK) {
5546 INT32 adjustments[1];
5548 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 0, NULL, NULL);
5549 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
5551 if (0) /* crashes on native */
5552 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, NULL);
5554 adjustments[0] = 1;
5555 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, adjustments);
5556 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5557 ok(adjustments[0] == 0, "got %d\n", adjustments[0]);
5559 IDWriteFontFace1_Release(fontface1);
5561 else
5562 win_skip("GetKerningPairAdjustments() is not supported.\n");
5564 IDWriteFontFace_Release(fontface);
5565 ref = IDWriteFactory_Release(factory);
5566 ok(ref == 0, "factory not released, %u\n", ref);
5567 DELETE_FONTFILE(path);
5570 static void test_CreateRenderingParams(void)
5572 IDWriteRenderingParams2 *params2;
5573 IDWriteRenderingParams1 *params1;
5574 IDWriteRenderingParams *params;
5575 DWRITE_RENDERING_MODE mode;
5576 IDWriteFactory3 *factory3;
5577 IDWriteFactory *factory;
5578 HRESULT hr;
5579 ULONG ref;
5581 factory = create_factory();
5583 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
5584 DWRITE_RENDERING_MODE_DEFAULT, &params);
5585 ok(hr == S_OK, "got 0x%08x\n", hr);
5587 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams1, (void**)&params1);
5588 if (hr == S_OK) {
5589 FLOAT enhcontrast;
5591 /* test what enhanced contrast setting set by default to */
5592 enhcontrast = IDWriteRenderingParams1_GetGrayscaleEnhancedContrast(params1);
5593 ok(enhcontrast == 1.0, "got %.2f\n", enhcontrast);
5594 IDWriteRenderingParams1_Release(params1);
5596 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
5597 if (hr == S_OK) {
5598 DWRITE_GRID_FIT_MODE gridfit;
5600 /* default gridfit mode */
5601 gridfit = IDWriteRenderingParams2_GetGridFitMode(params2);
5602 ok(gridfit == DWRITE_GRID_FIT_MODE_DEFAULT, "got %d\n", gridfit);
5604 IDWriteRenderingParams2_Release(params2);
5606 else
5607 win_skip("IDWriteRenderingParams2 not supported.\n");
5609 else
5610 win_skip("IDWriteRenderingParams1 not supported.\n");
5612 IDWriteRenderingParams_Release(params);
5614 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
5615 ok(hr == S_OK, "got 0x%08x\n", hr);
5617 mode = IDWriteRenderingParams_GetRenderingMode(params);
5618 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
5619 IDWriteRenderingParams_Release(params);
5621 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
5622 if (hr == S_OK) {
5623 IDWriteRenderingParams3 *params3;
5625 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
5626 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_DEFAULT, &params3);
5627 ok(hr == S_OK, "got 0x%08x\n", hr);
5629 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
5630 ok(hr == S_OK, "got 0x%08x\n", hr);
5632 mode = IDWriteRenderingParams_GetRenderingMode(params);
5633 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
5635 IDWriteRenderingParams_Release(params);
5636 IDWriteRenderingParams3_Release(params3);
5637 IDWriteFactory3_Release(factory3);
5639 else
5640 win_skip("IDWriteRenderingParams3 not supported.\n");
5642 ref = IDWriteFactory_Release(factory);
5643 ok(ref == 0, "factory not released, %u\n", ref);
5646 static void test_CreateGlyphRunAnalysis(void)
5648 static const DWRITE_RENDERING_MODE rendermodes[] = {
5649 DWRITE_RENDERING_MODE_ALIASED,
5650 DWRITE_RENDERING_MODE_GDI_CLASSIC,
5651 DWRITE_RENDERING_MODE_GDI_NATURAL,
5652 DWRITE_RENDERING_MODE_NATURAL,
5653 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
5656 IDWriteGlyphRunAnalysis *analysis, *analysis2;
5657 IDWriteRenderingParams *params;
5658 IDWriteFactory3 *factory3;
5659 IDWriteFactory2 *factory2;
5660 IDWriteFactory *factory;
5661 DWRITE_GLYPH_RUN run;
5662 IDWriteFontFace *face;
5663 UINT16 glyph, glyphs[10];
5664 FLOAT advances[2];
5665 HRESULT hr;
5666 UINT32 ch;
5667 RECT rect, rect2;
5668 DWRITE_GLYPH_OFFSET offsets[2];
5669 DWRITE_GLYPH_METRICS metrics;
5670 DWRITE_FONT_METRICS fm;
5671 DWRITE_MATRIX m;
5672 ULONG size;
5673 BYTE *bits;
5674 ULONG ref;
5675 int i;
5677 factory = create_factory();
5678 face = create_fontface(factory);
5680 ch = 'A';
5681 glyph = 0;
5682 hr = IDWriteFontFace_GetGlyphIndices(face, &ch, 1, &glyph);
5683 ok(hr == S_OK, "got 0x%08x\n", hr);
5684 ok(glyph > 0, "got %u\n", glyph);
5686 hr = IDWriteFontFace_GetDesignGlyphMetrics(face, &glyph, 1, &metrics, FALSE);
5687 ok(hr == S_OK, "got 0x%08x\n", hr);
5688 advances[0] = metrics.advanceWidth;
5690 offsets[0].advanceOffset = 0.0;
5691 offsets[0].ascenderOffset = 0.0;
5693 run.fontFace = face;
5694 run.fontEmSize = 24.0;
5695 run.glyphCount = 1;
5696 run.glyphIndices = &glyph;
5697 run.glyphAdvances = advances;
5698 run.glyphOffsets = offsets;
5699 run.isSideways = FALSE;
5700 run.bidiLevel = 0;
5702 /* zero ppdip */
5703 analysis = (void*)0xdeadbeef;
5704 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 0.0, NULL,
5705 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5706 0.0, 0.0, &analysis);
5707 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5708 ok(analysis == NULL, "got %p\n", analysis);
5710 /* negative ppdip */
5711 analysis = (void*)0xdeadbeef;
5712 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, -1.0, NULL,
5713 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5714 0.0, 0.0, &analysis);
5715 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5716 ok(analysis == NULL, "got %p\n", analysis);
5718 /* default mode is not allowed */
5719 analysis = (void*)0xdeadbeef;
5720 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5721 DWRITE_RENDERING_MODE_DEFAULT, DWRITE_MEASURING_MODE_NATURAL,
5722 0.0, 0.0, &analysis);
5723 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5724 ok(analysis == NULL, "got %p\n", analysis);
5726 /* outline too */
5727 analysis = (void*)0xdeadbeef;
5728 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5729 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_MEASURING_MODE_NATURAL,
5730 0.0, 0.0, &analysis);
5731 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5732 ok(analysis == NULL, "got %p\n", analysis);
5734 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5735 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5736 0.0, 0.0, &analysis);
5737 ok(hr == S_OK, "got 0x%08x\n", hr);
5739 /* invalid texture type */
5740 memset(&rect, 0xcc, sizeof(rect));
5741 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &rect);
5742 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5743 ok(rect.left == 0 && rect.right == 0 &&
5744 rect.top == 0 && rect.bottom == 0, "unexpected rect\n");
5746 /* check how origin affects bounds */
5747 SetRectEmpty(&rect);
5748 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5749 ok(hr == S_OK, "got 0x%08x\n", hr);
5750 ok(!IsRectEmpty(&rect), "got empty rect\n");
5751 IDWriteGlyphRunAnalysis_Release(analysis);
5753 /* doubled ppdip */
5754 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5755 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5756 0.0, 0.0, &analysis);
5757 ok(hr == S_OK, "got 0x%08x\n", hr);
5758 SetRectEmpty(&rect2);
5759 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5760 ok(hr == S_OK, "got 0x%08x\n", hr);
5761 ok(rect.right - rect.left < rect2.right - rect2.left, "expected wider rect\n");
5762 ok(rect.bottom - rect.top < rect2.bottom - rect2.top, "expected taller rect\n");
5763 IDWriteGlyphRunAnalysis_Release(analysis);
5765 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5766 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5767 10.0, -5.0, &analysis);
5768 ok(hr == S_OK, "got 0x%08x\n", hr);
5770 SetRectEmpty(&rect2);
5771 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5772 ok(hr == S_OK, "got 0x%08x\n", hr);
5773 ok(!IsRectEmpty(&rect2), "got empty rect\n");
5774 IDWriteGlyphRunAnalysis_Release(analysis);
5776 ok(!EqualRect(&rect, &rect2), "got equal bounds\n");
5777 OffsetRect(&rect, 10, -5);
5778 ok(EqualRect(&rect, &rect2), "got different bounds\n");
5780 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
5781 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5782 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
5783 0.0, 0.0, &analysis);
5784 ok(hr == S_OK, "got 0x%08x\n", hr);
5786 if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
5787 SetRectEmpty(&rect);
5788 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5789 ok(hr == S_OK, "got 0x%08x\n", hr);
5790 ok(!IsRectEmpty(&rect), "got empty rect\n");
5792 SetRect(&rect, 0, 0, 1, 1);
5793 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5794 ok(hr == S_OK, "got 0x%08x\n", hr);
5795 ok(IsRectEmpty(&rect), "unexpected empty rect\n");
5797 else {
5798 SetRect(&rect, 0, 0, 1, 1);
5799 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5800 ok(hr == S_OK, "got 0x%08x\n", hr);
5801 ok(IsRectEmpty(&rect), "got empty rect\n");
5803 SetRectEmpty(&rect);
5804 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5805 ok(hr == S_OK, "got 0x%08x\n", hr);
5806 ok(!IsRectEmpty(&rect), "got empty rect\n");
5809 IDWriteGlyphRunAnalysis_Release(analysis);
5812 IDWriteFontFace_GetMetrics(run.fontFace, &fm);
5814 /* check bbox for a single glyph run */
5815 for (run.fontEmSize = 1.0; run.fontEmSize <= 100.0; run.fontEmSize += 1.0) {
5816 DWRITE_GLYPH_METRICS gm;
5817 LONG bboxX, bboxY;
5819 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5820 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5821 0.0, 0.0, &analysis);
5822 ok(hr == S_OK, "got 0x%08x\n", hr);
5824 SetRectEmpty(&rect);
5825 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5826 ok(hr == S_OK, "got 0x%08x\n", hr);
5828 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
5829 DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
5830 ok(hr == S_OK, "got 0x%08x\n", hr);
5832 /* metrics are in design units */
5833 bboxX = (int)floorf((gm.advanceWidth - gm.leftSideBearing - gm.rightSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
5834 bboxY = (int)floorf((gm.advanceHeight - gm.topSideBearing - gm.bottomSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
5836 rect.right -= rect.left;
5837 rect.bottom -= rect.top;
5838 ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %d, from metrics %d\n", run.fontEmSize, rect.right, bboxX);
5839 ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %d, from metrics %d\n", run.fontEmSize, rect.bottom, bboxY);
5841 IDWriteGlyphRunAnalysis_Release(analysis);
5844 /* without offsets */
5845 run.fontFace = face;
5846 run.fontEmSize = 24.0;
5847 run.glyphCount = 1;
5848 run.glyphIndices = &glyph;
5849 run.glyphAdvances = advances;
5850 run.glyphOffsets = NULL;
5851 run.isSideways = FALSE;
5852 run.bidiLevel = 0;
5854 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5855 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5856 0.0, 0.0, &analysis);
5857 ok(hr == S_OK, "got 0x%08x\n", hr);
5859 SetRectEmpty(&rect);
5860 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5861 ok(hr == S_OK, "got 0x%08x\n", hr);
5862 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5864 IDWriteGlyphRunAnalysis_Release(analysis);
5866 /* without explicit advances */
5867 run.fontFace = face;
5868 run.fontEmSize = 24.0;
5869 run.glyphCount = 1;
5870 run.glyphIndices = &glyph;
5871 run.glyphAdvances = NULL;
5872 run.glyphOffsets = NULL;
5873 run.isSideways = FALSE;
5874 run.bidiLevel = 0;
5876 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5877 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5878 0.0, 0.0, &analysis);
5879 ok(hr == S_OK, "got 0x%08x\n", hr);
5881 SetRectEmpty(&rect);
5882 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5883 ok(hr == S_OK, "got 0x%08x\n", hr);
5884 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5886 IDWriteGlyphRunAnalysis_Release(analysis);
5888 /* test that advances are scaled according to ppdip too */
5889 glyphs[0] = glyphs[1] = glyph;
5890 advances[0] = advances[1] = 100.0f;
5891 run.fontFace = face;
5892 run.fontEmSize = 24.0;
5893 run.glyphCount = 2;
5894 run.glyphIndices = glyphs;
5895 run.glyphAdvances = advances;
5896 run.glyphOffsets = NULL;
5897 run.isSideways = FALSE;
5898 run.bidiLevel = 0;
5900 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5901 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5902 0.0, 0.0, &analysis);
5903 ok(hr == S_OK, "got 0x%08x\n", hr);
5905 SetRectEmpty(&rect2);
5906 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5907 ok(hr == S_OK, "got 0x%08x\n", hr);
5908 ok(!IsRectEmpty(&rect2), "got empty bounds\n");
5909 ok(!EqualRect(&rect, &rect2), "got wrong rect2\n");
5910 ok((rect2.right - rect.left) > advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
5911 IDWriteGlyphRunAnalysis_Release(analysis);
5913 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5914 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5915 0.0, 0.0, &analysis);
5916 ok(hr == S_OK, "got 0x%08x\n", hr);
5918 SetRectEmpty(&rect);
5919 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5920 ok(hr == S_OK, "got 0x%08x\n", hr);
5921 ok((rect.right - rect.left) > 2 * advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
5922 IDWriteGlyphRunAnalysis_Release(analysis);
5924 /* with scaling transform */
5925 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5926 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5927 0.0, 0.0, &analysis);
5928 ok(hr == S_OK, "got 0x%08x\n", hr);
5930 SetRectEmpty(&rect);
5931 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5932 ok(hr == S_OK, "got 0x%08x\n", hr);
5933 ok(!IsRectEmpty(&rect), "got rect width %d\n", rect.right - rect.left);
5934 IDWriteGlyphRunAnalysis_Release(analysis);
5936 memset(&m, 0, sizeof(m));
5937 m.m11 = 2.0;
5938 m.m22 = 1.0;
5939 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5940 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5941 0.0, 0.0, &analysis);
5942 ok(hr == S_OK, "got 0x%08x\n", hr);
5944 SetRectEmpty(&rect2);
5945 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5946 ok(hr == S_OK, "got 0x%08x\n", hr);
5947 ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %d\n", rect2.right - rect2.left);
5949 /* instances are not reused for same runs */
5950 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5951 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5952 0.0, 0.0, &analysis2);
5953 ok(hr == S_OK, "got 0x%08x\n", hr);
5954 ok(analysis2 != analysis, "got %p, previous instance %p\n", analysis2, analysis);
5955 IDWriteGlyphRunAnalysis_Release(analysis2);
5957 IDWriteGlyphRunAnalysis_Release(analysis);
5959 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void **)&factory2) == S_OK) {
5960 FLOAT gamma, contrast, cleartype_level;
5962 /* Invalid antialias mode. */
5963 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5964 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
5965 0.0f, 0.0f, &analysis);
5966 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5968 /* Invalid grid fit mode. */
5969 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5970 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5971 0.0f, 0.0f, &analysis);
5972 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5974 /* Invalid rendering mode. */
5975 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_OUTLINE,
5976 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5977 0.0f, 0.0f, &analysis);
5978 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5980 /* Invalid measuring mode. */
5981 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5982 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5983 0.0f, 0.0f, &analysis);
5984 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5986 /* Win8 does not accept default grid fitting mode. */
5987 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
5988 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5989 0.0f, 0.0f, &analysis);
5990 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Win8 */, "Failed to create analysis, hr %#x.\n", hr);
5991 if (hr == S_OK)
5992 IDWriteGlyphRunAnalysis_Release(analysis);
5994 /* Natural mode, grayscale antialiased. */
5995 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
5996 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5997 0.0f, 0.0f, &analysis);
5998 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
6000 SetRect(&rect, 0, 1, 0, 1);
6001 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
6002 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
6003 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
6005 SetRectEmpty(&rect);
6006 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
6007 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
6008 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
6010 size = (rect.right - rect.left) * (rect.bottom - rect.top);
6011 bits = HeapAlloc(GetProcessHeap(), 0, size);
6013 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
6014 ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
6016 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
6017 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
6019 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
6020 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
6022 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
6023 todo_wine
6024 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
6026 HeapFree(GetProcessHeap(), 0, bits);
6028 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.1f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
6029 DWRITE_RENDERING_MODE_NATURAL, &params);
6030 ok(hr == S_OK, "Failed to create custom parameters, hr %#x.\n", hr);
6032 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &cleartype_level);
6033 ok(hr == S_OK, "Failed to get alpha blend params, hr %#x.\n", hr);
6034 todo_wine
6035 ok(cleartype_level == 0.0f, "Unexpected cleartype level %f.\n", cleartype_level);
6037 IDWriteRenderingParams_Release(params);
6038 IDWriteGlyphRunAnalysis_Release(analysis);
6040 IDWriteFactory2_Release(factory2);
6043 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3) == S_OK) {
6045 /* Invalid antialias mode. */
6046 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6047 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
6048 0.0f, 0.0f, &analysis);
6049 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6051 /* Invalid grid fit mode. */
6052 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6053 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6054 0.0f, 0.0f, &analysis);
6055 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6057 /* Invalid rendering mode. */
6058 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_OUTLINE,
6059 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6060 0.0f, 0.0f, &analysis);
6061 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6063 /* Invalid measuring mode. */
6064 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
6065 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED,
6066 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, 0.0f, 0.0f, &analysis);
6067 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6069 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
6070 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6071 0.0f, 0.0f, &analysis);
6072 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
6073 IDWriteGlyphRunAnalysis_Release(analysis);
6075 /* Natural mode, grayscale antialiased. */
6076 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
6077 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
6078 0.0f, 0.0f, &analysis);
6079 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
6081 SetRect(&rect, 0, 1, 0, 1);
6082 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
6083 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
6084 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
6086 SetRectEmpty(&rect);
6087 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
6088 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
6089 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
6091 size = (rect.right - rect.left) * (rect.bottom - rect.top);
6092 bits = HeapAlloc(GetProcessHeap(), 0, size);
6094 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
6095 ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
6097 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
6098 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
6100 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
6101 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
6103 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
6104 todo_wine
6105 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
6107 HeapFree(GetProcessHeap(), 0, bits);
6109 IDWriteGlyphRunAnalysis_Release(analysis);
6111 IDWriteFactory3_Release(factory3);
6114 IDWriteFontFace_Release(face);
6115 ref = IDWriteFactory_Release(factory);
6116 ok(ref == 0, "factory not released, %u\n", ref);
6119 #define round(x) ((int)floor((x) + 0.5))
6121 struct VDMX_Header
6123 WORD version;
6124 WORD numRecs;
6125 WORD numRatios;
6128 struct VDMX_Ratio
6130 BYTE bCharSet;
6131 BYTE xRatio;
6132 BYTE yStartRatio;
6133 BYTE yEndRatio;
6136 struct VDMX_group
6138 WORD recs;
6139 BYTE startsz;
6140 BYTE endsz;
6143 struct VDMX_vTable
6145 WORD yPelHeight;
6146 SHORT yMax;
6147 SHORT yMin;
6150 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
6152 WORD num_ratios, i, group_offset = 0;
6153 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
6154 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
6156 num_ratios = GET_BE_WORD(hdr->numRatios);
6158 for (i = 0; i < num_ratios; i++)
6160 if (!ratios[i].bCharSet) continue;
6162 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
6163 ratios[i].yEndRatio == 0) ||
6164 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
6165 ratios[i].yEndRatio >= dev_y_ratio))
6167 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
6168 break;
6171 if (group_offset)
6172 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
6173 return NULL;
6176 static BOOL get_vdmx_size(const struct VDMX_group *group, int emsize, int *a, int *d)
6178 WORD recs, i;
6179 const struct VDMX_vTable *tables;
6181 if (!group) return FALSE;
6183 recs = GET_BE_WORD(group->recs);
6184 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
6186 tables = (const struct VDMX_vTable *)(group + 1);
6187 for (i = 0; i < recs; i++)
6189 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
6190 if (ppem > emsize)
6192 /* FIXME: Supposed to interpolate */
6193 trace("FIXME interpolate %d\n", emsize);
6194 return FALSE;
6197 if (ppem == emsize)
6199 *a = (SHORT)GET_BE_WORD(tables[i].yMax);
6200 *d = -(SHORT)GET_BE_WORD(tables[i].yMin);
6201 return TRUE;
6204 return FALSE;
6207 static void test_metrics_cmp(FLOAT emsize, const DWRITE_FONT_METRICS *metrics, const DWRITE_FONT_METRICS1 *expected)
6209 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
6210 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
6211 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
6212 emsize, metrics->ascent, expected->ascent);
6213 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
6214 emsize, metrics->descent, expected->descent);
6215 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
6216 emsize, metrics->lineGap, expected->lineGap);
6217 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
6218 emsize, metrics->capHeight, expected->capHeight);
6219 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
6220 emsize, metrics->xHeight, expected->xHeight);
6221 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
6222 emsize, metrics->underlinePosition, expected->underlinePosition);
6223 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
6224 emsize, metrics->underlineThickness, expected->underlineThickness);
6225 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
6226 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
6227 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
6228 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
6231 static void test_metrics1_cmp(FLOAT emsize, const DWRITE_FONT_METRICS1 *metrics, const DWRITE_FONT_METRICS1 *expected)
6233 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
6234 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
6235 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
6236 emsize, metrics->ascent, expected->ascent);
6237 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
6238 emsize, metrics->descent, expected->descent);
6239 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
6240 emsize, metrics->lineGap, expected->lineGap);
6241 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
6242 emsize, metrics->capHeight, expected->capHeight);
6243 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
6244 emsize, metrics->xHeight, expected->xHeight);
6245 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
6246 emsize, metrics->underlinePosition, expected->underlinePosition);
6247 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
6248 emsize, metrics->underlineThickness, expected->underlineThickness);
6249 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
6250 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
6251 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
6252 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
6253 ok(metrics->glyphBoxLeft == expected->glyphBoxLeft, "%.2f box left: got %d expect %d\n",
6254 emsize, metrics->glyphBoxLeft, expected->glyphBoxLeft);
6255 if (0) { /* this is not consistent */
6256 ok(metrics->glyphBoxTop == expected->glyphBoxTop, "%.2f box top: got %d expect %d\n",
6257 emsize, metrics->glyphBoxTop, expected->glyphBoxTop);
6258 ok(metrics->glyphBoxRight == expected->glyphBoxRight, "%.2f box right: got %d expect %d\n",
6259 emsize, metrics->glyphBoxRight, expected->glyphBoxRight);
6261 ok(metrics->glyphBoxBottom == expected->glyphBoxBottom, "%.2f box bottom: got %d expect %d\n",
6262 emsize, metrics->glyphBoxBottom, expected->glyphBoxBottom);
6263 ok(metrics->subscriptPositionX == expected->subscriptPositionX, "%.2f subX: got %d expect %d\n",
6264 emsize, metrics->subscriptPositionX, expected->subscriptPositionX);
6265 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subY: got %d expect %d\n",
6266 emsize, metrics->subscriptPositionY, expected->subscriptPositionY);
6267 ok(metrics->subscriptSizeX == expected->subscriptSizeX, "%.2f subsizeX: got %d expect %d\n",
6268 emsize, metrics->subscriptSizeX, expected->subscriptSizeX);
6269 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subsizeY: got %d expect %d\n",
6270 emsize, metrics->subscriptSizeY, expected->subscriptSizeY);
6271 ok(metrics->superscriptPositionX == expected->superscriptPositionX, "%.2f supX: got %d expect %d\n",
6272 emsize, metrics->superscriptPositionX, expected->superscriptPositionX);
6273 if (0)
6274 ok(metrics->superscriptPositionY == expected->superscriptPositionY, "%.2f supY: got %d expect %d\n",
6275 emsize, metrics->superscriptPositionY, expected->superscriptPositionY);
6276 ok(metrics->superscriptSizeX == expected->superscriptSizeX, "%.2f supsizeX: got %d expect %d\n",
6277 emsize, metrics->superscriptSizeX, expected->superscriptSizeX);
6278 ok(metrics->superscriptSizeY == expected->superscriptSizeY, "%.2f supsizeY: got %d expect %d\n",
6279 emsize, metrics->superscriptSizeY, expected->superscriptSizeY);
6280 ok(metrics->hasTypographicMetrics == expected->hasTypographicMetrics, "%.2f hastypo: got %d expect %d\n",
6281 emsize, metrics->hasTypographicMetrics, expected->hasTypographicMetrics);
6284 struct compatmetrics_test {
6285 DWRITE_MATRIX m;
6286 FLOAT ppdip;
6287 FLOAT emsize;
6290 static struct compatmetrics_test compatmetrics_tests[] = {
6291 { { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0, 5.0 },
6292 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 1.0, 5.0 },
6293 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 2.0, 5.0 },
6294 { { 0.0, 0.0, 0.0, 3.0, 0.0, 0.0 }, 2.0, 5.0 },
6295 { { 0.0, 0.0, 0.0, -3.0, 0.0, 0.0 }, 2.0, 5.0 },
6296 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 2.0, 5.0 },
6297 { { 1.0, 0.0, 0.0, 1.0, 5.0, 0.0 }, 2.0, 5.0 },
6298 { { 1.0, 0.0, 0.0, 1.0, 0.0, 5.0 }, 2.0, 5.0 },
6301 static void get_expected_metrics(IDWriteFontFace *fontface, struct compatmetrics_test *ptr,
6302 DWRITE_FONT_METRICS *expected)
6304 HRESULT hr;
6306 memset(expected, 0, sizeof(*expected));
6307 hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, ptr->ppdip * fabsf(ptr->m.m22) * ptr->emsize, 1.0, NULL, expected);
6308 ok(hr == S_OK, "got %08x\n", hr);
6311 static void test_gdicompat_metrics(IDWriteFontFace *face)
6313 IDWriteFontFace1 *fontface1 = NULL;
6314 HRESULT hr;
6315 DWRITE_FONT_METRICS design_metrics, comp_metrics;
6316 DWRITE_FONT_METRICS1 design_metrics1, expected;
6317 FLOAT emsize, scale;
6318 int ascent, descent;
6319 const struct VDMX_Header *vdmx;
6320 UINT32 vdmx_len;
6321 void *vdmx_ctx;
6322 BOOL exists;
6323 const struct VDMX_group *vdmx_group = NULL;
6324 int i;
6326 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace1, (void**)&fontface1);
6327 if (hr != S_OK)
6328 win_skip("gdi compatible DWRITE_FONT_METRICS1 are not supported.\n");
6330 if (fontface1) {
6331 IDWriteFontFace1_GetMetrics(fontface1, &design_metrics1);
6332 memcpy(&design_metrics, &design_metrics1, sizeof(design_metrics));
6334 else
6335 IDWriteFontFace_GetMetrics(face, &design_metrics);
6337 hr = IDWriteFontFace_TryGetFontTable(face, MS_VDMX_TAG, (const void **)&vdmx,
6338 &vdmx_len, &vdmx_ctx, &exists);
6339 if (hr != S_OK || !exists)
6340 vdmx = NULL;
6341 else
6342 vdmx_group = find_vdmx_group(vdmx);
6344 /* negative emsize */
6345 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6346 memset(&expected, 0, sizeof(expected));
6347 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, -10.0, 1.0, NULL, &comp_metrics);
6348 ok(hr == E_INVALIDARG, "got %08x\n", hr);
6349 test_metrics_cmp(0.0, &comp_metrics, &expected);
6351 /* zero emsize */
6352 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6353 memset(&expected, 0, sizeof(expected));
6354 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 0.0, 1.0, NULL, &comp_metrics);
6355 ok(hr == E_INVALIDARG, "got %08x\n", hr);
6356 test_metrics_cmp(0.0, &comp_metrics, &expected);
6358 /* zero pixels per dip */
6359 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6360 memset(&expected, 0, sizeof(expected));
6361 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, 0.0, NULL, &comp_metrics);
6362 ok(hr == E_INVALIDARG, "got %08x\n", hr);
6363 test_metrics_cmp(5.0, &comp_metrics, &expected);
6365 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
6366 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, -1.0, NULL, &comp_metrics);
6367 ok(hr == E_INVALIDARG, "got %08x\n", hr);
6368 test_metrics_cmp(5.0, &comp_metrics, &expected);
6370 for (i = 0; i < ARRAY_SIZE(compatmetrics_tests); i++) {
6371 struct compatmetrics_test *ptr = &compatmetrics_tests[i];
6373 get_expected_metrics(face, ptr, (DWRITE_FONT_METRICS*)&expected);
6374 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, ptr->emsize, ptr->ppdip, &ptr->m, &comp_metrics);
6375 ok(hr == S_OK, "got %08x\n", hr);
6376 test_metrics_cmp(ptr->emsize, &comp_metrics, &expected);
6379 for (emsize = 5; emsize <= design_metrics.designUnitsPerEm; emsize++)
6381 DWRITE_FONT_METRICS1 comp_metrics1, expected;
6383 if (fontface1) {
6384 hr = IDWriteFontFace1_GetGdiCompatibleMetrics(fontface1, emsize, 1.0, NULL, &comp_metrics1);
6385 ok(hr == S_OK, "got %08x\n", hr);
6387 else {
6388 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, emsize, 1.0, NULL, &comp_metrics);
6389 ok(hr == S_OK, "got %08x\n", hr);
6392 scale = emsize / design_metrics.designUnitsPerEm;
6393 if (!get_vdmx_size(vdmx_group, emsize, &ascent, &descent))
6395 ascent = round(design_metrics.ascent * scale);
6396 descent = round(design_metrics.descent * scale);
6399 expected.designUnitsPerEm = design_metrics.designUnitsPerEm;
6400 expected.ascent = round(ascent / scale );
6401 expected.descent = round(descent / scale );
6402 expected.lineGap = round(round(design_metrics.lineGap * scale) / scale);
6403 expected.capHeight = round(round(design_metrics.capHeight * scale) / scale);
6404 expected.xHeight = round(round(design_metrics.xHeight * scale) / scale);
6405 expected.underlinePosition = round(round(design_metrics.underlinePosition * scale) / scale);
6406 expected.underlineThickness = round(round(design_metrics.underlineThickness * scale) / scale);
6407 expected.strikethroughPosition = round(round(design_metrics.strikethroughPosition * scale) / scale);
6408 expected.strikethroughThickness = round(round(design_metrics.strikethroughThickness * scale) / scale);
6410 if (fontface1) {
6411 expected.glyphBoxLeft = round(round(design_metrics1.glyphBoxLeft * scale) / scale);
6413 if (0) { /* those two fail on Tahoma and Win7 */
6414 expected.glyphBoxTop = round(round(design_metrics1.glyphBoxTop * scale) / scale);
6415 expected.glyphBoxRight = round(round(design_metrics1.glyphBoxRight * scale) / scale);
6417 expected.glyphBoxBottom = round(round(design_metrics1.glyphBoxBottom * scale) / scale);
6418 expected.subscriptPositionX = round(round(design_metrics1.subscriptPositionX * scale) / scale);
6419 expected.subscriptPositionY = round(round(design_metrics1.subscriptPositionY * scale) / scale);
6420 expected.subscriptSizeX = round(round(design_metrics1.subscriptSizeX * scale) / scale);
6421 expected.subscriptSizeY = round(round(design_metrics1.subscriptSizeY * scale) / scale);
6422 expected.superscriptPositionX = round(round(design_metrics1.superscriptPositionX * scale) / scale);
6423 if (0) /* this fails for 3 emsizes, Tahoma from [5, 2048] range */ {
6424 expected.superscriptPositionY = round(round(design_metrics1.superscriptPositionY * scale) / scale);
6426 expected.superscriptSizeX = round(round(design_metrics1.superscriptSizeX * scale) / scale);
6427 expected.superscriptSizeY = round(round(design_metrics1.superscriptSizeY * scale) / scale);
6428 expected.hasTypographicMetrics = design_metrics1.hasTypographicMetrics;
6430 test_metrics1_cmp(emsize, &comp_metrics1, &expected);
6432 else
6433 test_metrics_cmp(emsize, &comp_metrics, &expected);
6437 if (fontface1)
6438 IDWriteFontFace1_Release(fontface1);
6439 if (vdmx) IDWriteFontFace_ReleaseFontTable(face, vdmx_ctx);
6442 static void test_GetGdiCompatibleMetrics(void)
6444 IDWriteFactory *factory;
6445 IDWriteFont *font;
6446 IDWriteFontFace *fontface;
6447 HRESULT hr;
6448 ULONG ref;
6450 factory = create_factory();
6452 font = get_font(factory, L"Tahoma", DWRITE_FONT_STYLE_NORMAL);
6453 hr = IDWriteFont_CreateFontFace(font, &fontface);
6454 ok(hr == S_OK, "got 0x%08x\n", hr);
6455 IDWriteFont_Release(font);
6456 test_gdicompat_metrics(fontface);
6457 IDWriteFontFace_Release(fontface);
6459 font = get_font(factory, L"Arial", DWRITE_FONT_STYLE_NORMAL);
6460 if (!font)
6461 skip("Skipping tests with Arial\n");
6462 else
6464 hr = IDWriteFont_CreateFontFace(font, &fontface);
6465 ok(hr == S_OK, "got 0x%08x\n", hr);
6466 IDWriteFont_Release(font);
6468 test_gdicompat_metrics(fontface);
6469 IDWriteFontFace_Release(fontface);
6472 ref = IDWriteFactory_Release(factory);
6473 ok(ref == 0, "factory not released, %u\n", ref);
6476 static void get_expected_panose(IDWriteFont1 *font, DWRITE_PANOSE *panose)
6478 IDWriteFontFace *fontface;
6479 const TT_OS2_V2 *tt_os2;
6480 void *os2_context;
6481 UINT32 size;
6482 BOOL exists;
6483 HRESULT hr;
6485 memset(panose, 0, sizeof(*panose));
6487 hr = IDWriteFont1_CreateFontFace(font, &fontface);
6488 ok(hr == S_OK, "got 0x%08x\n", hr);
6490 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
6491 ok(hr == S_OK, "got 0x%08x\n", hr);
6493 if (tt_os2) {
6494 memcpy(panose, &tt_os2->panose, sizeof(*panose));
6495 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
6498 IDWriteFontFace_Release(fontface);
6501 static void test_GetPanose(void)
6503 IDWriteFontCollection *syscollection;
6504 IDWriteFactory *factory;
6505 IDWriteFont1 *font1;
6506 IDWriteFont *font;
6507 UINT count, i;
6508 HRESULT hr;
6509 ULONG ref;
6511 factory = create_factory();
6512 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6514 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
6515 IDWriteFont_Release(font);
6517 if (FAILED(hr)) {
6518 ref = IDWriteFactory_Release(factory);
6519 ok(ref == 0, "factory not released, %u\n", ref);
6520 win_skip("GetPanose() is not supported.\n");
6521 return;
6523 IDWriteFont1_Release(font1);
6525 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
6526 ok(hr == S_OK, "got 0x%08x\n", hr);
6527 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
6529 for (i = 0; i < count; i++) {
6530 DWRITE_PANOSE panose, expected_panose;
6531 IDWriteLocalizedStrings *names;
6532 IDWriteFontFace3 *fontface3;
6533 IDWriteFontFace *fontface;
6534 IDWriteFontFamily *family;
6535 IDWriteFont1 *font1;
6536 IDWriteFont *font;
6537 WCHAR nameW[256];
6539 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
6540 ok(hr == S_OK, "got 0x%08x\n", hr);
6542 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
6543 DWRITE_FONT_STYLE_NORMAL, &font);
6544 ok(hr == S_OK, "got 0x%08x\n", hr);
6546 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
6547 ok(hr == S_OK, "got 0x%08x\n", hr);
6548 IDWriteFont_Release(font);
6550 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
6551 ok(hr == S_OK, "got 0x%08x\n", hr);
6553 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
6555 IDWriteLocalizedStrings_Release(names);
6557 IDWriteFont1_GetPanose(font1, &panose);
6558 get_expected_panose(font1, &expected_panose);
6560 ok(panose.values[0] == expected_panose.values[0], "%s: values[0] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6561 panose.values[0], expected_panose.values[0]);
6562 ok(panose.values[1] == expected_panose.values[1], "%s: values[1] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6563 panose.values[1], expected_panose.values[1]);
6564 ok(panose.values[2] == expected_panose.values[2], "%s: values[2] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6565 panose.values[2], expected_panose.values[2]);
6566 ok(panose.values[3] == expected_panose.values[3], "%s: values[3] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6567 panose.values[3], expected_panose.values[3]);
6568 ok(panose.values[4] == expected_panose.values[4], "%s: values[4] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6569 panose.values[4], expected_panose.values[4]);
6570 ok(panose.values[5] == expected_panose.values[5], "%s: values[5] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6571 panose.values[5], expected_panose.values[5]);
6572 ok(panose.values[6] == expected_panose.values[6], "%s: values[6] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6573 panose.values[6], expected_panose.values[6]);
6574 ok(panose.values[7] == expected_panose.values[7], "%s: values[7] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6575 panose.values[7], expected_panose.values[7]);
6576 ok(panose.values[8] == expected_panose.values[8], "%s: values[8] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6577 panose.values[8], expected_panose.values[8]);
6578 ok(panose.values[9] == expected_panose.values[9], "%s: values[9] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
6579 panose.values[9], expected_panose.values[9]);
6581 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
6582 ok(hr == S_OK, "Failed to create a font face, %#x.\n", hr);
6583 if (IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3) == S_OK) {
6584 ok(!memcmp(&panose, &expected_panose, sizeof(panose)), "%s: Unexpected panose from font face.\n",
6585 wine_dbgstr_w(nameW));
6586 IDWriteFontFace3_Release(fontface3);
6588 IDWriteFontFace_Release(fontface);
6590 IDWriteFont1_Release(font1);
6591 IDWriteFontFamily_Release(family);
6594 IDWriteFontCollection_Release(syscollection);
6595 ref = IDWriteFactory_Release(factory);
6596 ok(ref == 0, "factory not released, %u\n", ref);
6599 static INT32 get_gdi_font_advance(HDC hdc, FLOAT emsize)
6601 LOGFONTW logfont;
6602 HFONT hfont;
6603 BOOL ret;
6604 ABC abc;
6606 memset(&logfont, 0, sizeof(logfont));
6607 logfont.lfHeight = (LONG)-emsize;
6608 logfont.lfWeight = FW_NORMAL;
6609 logfont.lfQuality = CLEARTYPE_QUALITY;
6610 lstrcpyW(logfont.lfFaceName, L"Tahoma");
6612 hfont = CreateFontIndirectW(&logfont);
6613 SelectObject(hdc, hfont);
6615 ret = GetCharABCWidthsW(hdc, 'A', 'A', &abc);
6616 ok(ret, "got %d\n", ret);
6618 DeleteObject(hfont);
6620 return abc.abcA + abc.abcB + abc.abcC;
6623 static void test_GetGdiCompatibleGlyphAdvances(void)
6625 IDWriteFontFace1 *fontface1;
6626 IDWriteFontFace *fontface;
6627 IDWriteFactory *factory;
6628 IDWriteFont *font;
6629 HRESULT hr;
6630 HDC hdc;
6631 UINT32 codepoint;
6632 UINT16 glyph;
6633 FLOAT emsize;
6634 DWRITE_FONT_METRICS1 fm;
6635 INT32 advance;
6636 ULONG ref;
6638 factory = create_factory();
6639 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6641 hr = IDWriteFont_CreateFontFace(font, &fontface);
6642 ok(hr == S_OK, "got 0x%08x\n", hr);
6643 IDWriteFont_Release(font);
6645 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
6646 IDWriteFontFace_Release(fontface);
6648 if (hr != S_OK) {
6649 ref = IDWriteFactory_Release(factory);
6650 ok(ref == 0, "factory not released, %u\n", ref);
6651 win_skip("GetGdiCompatibleGlyphAdvances() is not supported\n");
6652 return;
6655 codepoint = 'A';
6656 glyph = 0;
6657 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &glyph);
6658 ok(hr == S_OK, "got 0x%08x\n", hr);
6659 ok(glyph > 0, "got %u\n", glyph);
6661 /* zero emsize */
6662 advance = 1;
6663 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 0.0,
6664 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6665 ok(hr == S_OK, "got 0x%08x\n", hr);
6666 ok(advance == 0, "got %d\n", advance);
6668 /* negative emsize */
6669 advance = 1;
6670 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, -1.0,
6671 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6672 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6673 ok(advance == 0, "got %d\n", advance);
6675 /* zero ppdip */
6676 advance = 1;
6677 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
6678 0.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6679 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6680 ok(advance == 0, "got %d\n", advance);
6682 /* negative ppdip */
6683 advance = 1;
6684 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
6685 -1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6686 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6687 ok(advance == 0, "got %d\n", advance);
6689 IDWriteFontFace1_GetMetrics(fontface1, &fm);
6691 hdc = CreateCompatibleDC(0);
6693 for (emsize = 1.0; emsize <= fm.designUnitsPerEm; emsize += 1.0) {
6694 INT32 gdi_advance;
6696 gdi_advance = get_gdi_font_advance(hdc, emsize);
6697 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emsize,
6698 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
6699 ok(hr == S_OK, "got 0x%08x\n", hr);
6701 /* advance is in design units */
6702 advance = (int)floorf(emsize * advance / fm.designUnitsPerEm + 0.5f);
6703 ok((advance - gdi_advance) <= 2, "%.0f: got advance %d, expected %d\n", emsize, advance, gdi_advance);
6706 DeleteObject(hdc);
6708 IDWriteFontFace1_Release(fontface1);
6709 ref = IDWriteFactory_Release(factory);
6710 ok(ref == 0, "factory not released, %u\n", ref);
6713 static WORD get_gasp_flags(IDWriteFontFace *fontface, FLOAT emsize, FLOAT ppdip)
6715 WORD num_recs, version;
6716 const WORD *ptr;
6717 WORD flags = 0;
6718 UINT32 size;
6719 BOOL exists;
6720 void *ctxt;
6721 HRESULT hr;
6723 emsize *= ppdip;
6725 exists = FALSE;
6726 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GASP_TAG,
6727 (const void**)&ptr, &size, &ctxt, &exists);
6728 ok(hr == S_OK, "got 0x%08x\n", hr);
6730 if (!exists)
6731 goto done;
6733 version = GET_BE_WORD( *ptr++ );
6734 num_recs = GET_BE_WORD( *ptr++ );
6735 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
6736 ok(0, "unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
6737 goto done;
6740 while (num_recs--)
6742 flags = GET_BE_WORD( *(ptr + 1) );
6743 if (emsize <= GET_BE_WORD( *ptr )) break;
6744 ptr += 2;
6747 done:
6748 IDWriteFontFace_ReleaseFontTable(fontface, ctxt);
6749 return flags;
6752 #define GASP_GRIDFIT 0x0001
6753 #define GASP_DOGRAY 0x0002
6754 #define GASP_SYMMETRIC_GRIDFIT 0x0004
6755 #define GASP_SYMMETRIC_SMOOTHING 0x0008
6757 static BOOL g_is_vista;
6758 static DWRITE_RENDERING_MODE get_expected_rendering_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
6759 DWRITE_OUTLINE_THRESHOLD threshold)
6761 static const FLOAT aa_threshold = 100.0f;
6762 static const FLOAT a_threshold = 350.0f;
6763 static const FLOAT naturalemsize = 20.0f;
6764 FLOAT v;
6766 /* outline threshold */
6767 if (g_is_vista)
6768 v = mode == DWRITE_MEASURING_MODE_NATURAL ? aa_threshold : a_threshold;
6769 else
6770 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
6772 if (emsize >= v)
6773 return DWRITE_RENDERING_MODE_OUTLINE;
6775 switch (mode)
6777 case DWRITE_MEASURING_MODE_NATURAL:
6778 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (emsize <= naturalemsize))
6779 return DWRITE_RENDERING_MODE_NATURAL;
6780 else
6781 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
6782 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
6783 return DWRITE_RENDERING_MODE_GDI_CLASSIC;
6784 case DWRITE_MEASURING_MODE_GDI_NATURAL:
6785 return DWRITE_RENDERING_MODE_GDI_NATURAL;
6786 default:
6790 /* should be unreachable */
6791 return DWRITE_RENDERING_MODE_DEFAULT;
6794 static DWRITE_GRID_FIT_MODE get_expected_gridfit_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
6795 DWRITE_OUTLINE_THRESHOLD threshold)
6797 static const FLOAT aa_threshold = 100.0f;
6798 static const FLOAT a_threshold = 350.0f;
6799 FLOAT v;
6801 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
6802 if (emsize >= v)
6803 return DWRITE_GRID_FIT_MODE_DISABLED;
6805 if (mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
6806 return DWRITE_GRID_FIT_MODE_ENABLED;
6808 return (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
6811 struct recommendedmode_test
6813 DWRITE_MEASURING_MODE measuring;
6814 DWRITE_OUTLINE_THRESHOLD threshold;
6817 static const struct recommendedmode_test recmode_tests[] = {
6818 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6819 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6820 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6823 static const struct recommendedmode_test recmode_tests1[] = {
6824 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6825 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6826 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
6827 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6828 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6829 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
6832 static void test_GetRecommendedRenderingMode(void)
6834 IDWriteRenderingParams *params;
6835 IDWriteFontFace3 *fontface3;
6836 IDWriteFontFace2 *fontface2;
6837 IDWriteFontFace1 *fontface1;
6838 IDWriteFontFace *fontface;
6839 DWRITE_RENDERING_MODE mode;
6840 IDWriteFactory *factory;
6841 FLOAT emsize;
6842 HRESULT hr;
6843 ULONG ref;
6845 factory = create_factory();
6846 fontface = create_fontface(factory);
6848 fontface1 = NULL;
6849 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
6850 if (hr != S_OK)
6851 win_skip("IDWriteFontFace1::GetRecommendedRenderingMode() is not supported.\n");
6853 fontface2 = NULL;
6854 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6855 if (hr != S_OK)
6856 win_skip("IDWriteFontFace2::GetRecommendedRenderingMode() is not supported.\n");
6858 fontface3 = NULL;
6859 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
6860 if (hr != S_OK)
6861 win_skip("IDWriteFontFace3::GetRecommendedRenderingMode() is not supported.\n");
6863 if (0) /* crashes on native */
6864 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6865 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, NULL);
6867 mode = 10;
6868 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6869 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode);
6870 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6871 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
6873 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
6874 ok(hr == S_OK, "got 0x%08x\n", hr);
6876 /* detect old dwrite version, that is using higher threshold value */
6877 g_is_vista = fontface1 == NULL;
6879 for (emsize = 1.0; emsize < 500.0; emsize += 1.0) {
6880 DWRITE_RENDERING_MODE expected;
6881 FLOAT ppdip;
6882 WORD gasp;
6883 int i;
6885 for (i = 0; i < ARRAY_SIZE(recmode_tests); i++) {
6886 ppdip = 1.0f;
6887 mode = 10;
6888 gasp = get_gasp_flags(fontface, emsize, ppdip);
6889 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6890 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6891 ok(hr == S_OK, "got 0x%08x\n", hr);
6892 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6894 /* some ppdip variants */
6895 ppdip = 0.5f;
6896 mode = 10;
6897 gasp = get_gasp_flags(fontface, emsize, ppdip);
6898 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6899 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6900 ok(hr == S_OK, "got 0x%08x\n", hr);
6901 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6903 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6904 Win8 and Win10 handle this as expected. */
6905 if (emsize > 20.0f) {
6906 ppdip = 1.5f;
6907 mode = 10;
6908 gasp = get_gasp_flags(fontface, emsize, ppdip);
6909 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6910 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6911 ok(hr == S_OK, "got 0x%08x\n", hr);
6912 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6914 ppdip = 2.0f;
6915 mode = 10;
6916 gasp = get_gasp_flags(fontface, emsize, ppdip);
6917 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6918 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6919 ok(hr == S_OK, "got 0x%08x\n", hr);
6920 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6924 /* IDWriteFontFace1 offers another variant of this method */
6925 if (fontface1) {
6926 for (i = 0; i < ARRAY_SIZE(recmode_tests1); i++) {
6927 FLOAT dpi;
6929 ppdip = 1.0f;
6930 dpi = 96.0f * ppdip;
6931 mode = 10;
6932 gasp = get_gasp_flags(fontface, emsize, ppdip);
6933 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6934 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6935 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6936 ok(hr == S_OK, "got 0x%08x\n", hr);
6937 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6939 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6940 Win8 and Win10 handle this as expected. */
6941 if (emsize > 20.0f) {
6942 ppdip = 2.0f;
6943 dpi = 96.0f * ppdip;
6944 mode = 10;
6945 gasp = get_gasp_flags(fontface, emsize, ppdip);
6946 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6947 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6948 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6949 ok(hr == S_OK, "got 0x%08x\n", hr);
6950 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6952 ppdip = 0.5f;
6953 dpi = 96.0f * ppdip;
6954 mode = 10;
6955 gasp = get_gasp_flags(fontface, emsize, ppdip);
6956 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6957 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6958 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6959 ok(hr == S_OK, "got 0x%08x\n", hr);
6960 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6962 /* try different dpis for X and Y direction */
6963 ppdip = 1.0f;
6964 dpi = 96.0f * ppdip;
6965 mode = 10;
6966 gasp = get_gasp_flags(fontface, emsize, ppdip);
6967 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6968 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6969 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6970 ok(hr == S_OK, "got 0x%08x\n", hr);
6971 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6973 ppdip = 1.0f;
6974 dpi = 96.0f * ppdip;
6975 mode = 10;
6976 gasp = get_gasp_flags(fontface, emsize, ppdip);
6977 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6978 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
6979 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6980 ok(hr == S_OK, "got 0x%08x\n", hr);
6981 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6983 ppdip = 2.0f;
6984 dpi = 96.0f * ppdip;
6985 mode = 10;
6986 gasp = get_gasp_flags(fontface, emsize, ppdip);
6987 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6988 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6989 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6990 ok(hr == S_OK, "got 0x%08x\n", hr);
6991 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6993 ppdip = 2.0f;
6994 dpi = 96.0f * ppdip;
6995 mode = 10;
6996 gasp = get_gasp_flags(fontface, emsize, ppdip);
6997 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6998 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
6999 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
7000 ok(hr == S_OK, "got 0x%08x\n", hr);
7001 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
7006 /* IDWriteFontFace2 - another one */
7007 if (fontface2) {
7008 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
7010 gasp = get_gasp_flags(fontface, emsize, 1.0f);
7011 for (i = 0; i < ARRAY_SIZE(recmode_tests1); i++) {
7012 mode = 10;
7013 expected = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7014 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7015 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, emsize, 96.0f, 96.0f,
7016 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode, &gridfit);
7017 ok(hr == S_OK, "got 0x%08x\n", hr);
7018 ok(mode == expected, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode, gasp, expected);
7019 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
7020 gasp, expected_gridfit);
7024 /* IDWriteFontFace3 - and another one */
7025 if (fontface3) {
7026 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
7027 DWRITE_RENDERING_MODE1 mode1, expected1;
7029 gasp = get_gasp_flags(fontface, emsize, 1.0f);
7030 for (i = 0; i < ARRAY_SIZE(recmode_tests1); i++) {
7031 mode1 = 10;
7032 expected1 = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7033 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
7034 hr = IDWriteFontFace3_GetRecommendedRenderingMode(fontface3, emsize, 96.0f, 96.0f,
7035 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode1, &gridfit);
7036 ok(hr == S_OK, "got 0x%08x\n", hr);
7037 ok(mode1 == expected1, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode1, gasp, expected1);
7038 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
7039 gasp, expected_gridfit);
7044 IDWriteRenderingParams_Release(params);
7046 /* test how parameters override returned modes */
7047 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
7048 DWRITE_RENDERING_MODE_GDI_CLASSIC, &params);
7049 ok(hr == S_OK, "got 0x%08x\n", hr);
7051 mode = 10;
7052 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode);
7053 ok(hr == S_OK, "got 0x%08x\n", hr);
7054 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7056 IDWriteRenderingParams_Release(params);
7058 if (fontface2) {
7059 IDWriteRenderingParams2 *params2;
7060 IDWriteFactory2 *factory2;
7061 DWRITE_GRID_FIT_MODE gridfit;
7063 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
7064 ok(hr == S_OK, "got 0x%08x\n", hr);
7066 hr = IDWriteFactory2_CreateCustomRenderingParams(factory2, 1.0, 0.0, 0.0, 0.5, DWRITE_PIXEL_GEOMETRY_FLAT,
7067 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_GRID_FIT_MODE_ENABLED, &params2);
7068 ok(hr == S_OK, "got 0x%08x\n", hr);
7070 mode = 10;
7071 gridfit = 10;
7072 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
7073 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7074 NULL, &mode, &gridfit);
7075 ok(hr == S_OK, "got 0x%08x\n", hr);
7076 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7077 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7079 mode = 10;
7080 gridfit = 10;
7081 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
7082 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7083 (IDWriteRenderingParams*)params2, &mode, &gridfit);
7084 ok(hr == S_OK, "got 0x%08x\n", hr);
7085 ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode);
7086 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7088 IDWriteRenderingParams2_Release(params2);
7089 IDWriteFactory2_Release(factory2);
7092 if (fontface3) {
7093 IDWriteRenderingParams3 *params3;
7094 IDWriteRenderingParams2 *params2;
7095 IDWriteRenderingParams *params;
7096 IDWriteFactory3 *factory3;
7097 DWRITE_GRID_FIT_MODE gridfit;
7098 DWRITE_RENDERING_MODE1 mode1;
7100 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
7101 ok(hr == S_OK, "got 0x%08x\n", hr);
7103 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 0.5f, DWRITE_PIXEL_GEOMETRY_FLAT,
7104 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_ENABLED, &params3);
7105 ok(hr == S_OK, "got 0x%08x\n", hr);
7107 mode1 = IDWriteRenderingParams3_GetRenderingMode1(params3);
7108 ok(mode1 == DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, "got %d\n", mode1);
7110 mode = IDWriteRenderingParams3_GetRenderingMode(params3);
7111 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7113 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
7114 ok(hr == S_OK, "got 0x%08x\n", hr);
7115 ok(params == (IDWriteRenderingParams*)params3, "got %p, %p\n", params3, params);
7116 mode = IDWriteRenderingParams_GetRenderingMode(params);
7117 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7118 IDWriteRenderingParams_Release(params);
7120 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams2, (void**)&params2);
7121 ok(hr == S_OK, "got 0x%08x\n", hr);
7122 ok(params2 == (IDWriteRenderingParams2*)params3, "got %p, %p\n", params3, params2);
7123 mode = IDWriteRenderingParams2_GetRenderingMode(params2);
7124 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7125 IDWriteRenderingParams2_Release(params2);
7127 mode = 10;
7128 gridfit = 10;
7129 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
7130 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7131 NULL, &mode, &gridfit);
7132 ok(hr == S_OK, "got 0x%08x\n", hr);
7133 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
7134 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7136 mode = 10;
7137 gridfit = 10;
7138 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
7139 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7140 (IDWriteRenderingParams*)params3, &mode, &gridfit);
7141 ok(hr == S_OK, "got 0x%08x\n", hr);
7142 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
7143 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
7145 IDWriteRenderingParams3_Release(params3);
7146 IDWriteFactory3_Release(factory3);
7149 if (fontface3)
7150 IDWriteFontFace3_Release(fontface3);
7151 if (fontface2)
7152 IDWriteFontFace2_Release(fontface2);
7153 if (fontface1)
7154 IDWriteFontFace1_Release(fontface1);
7155 IDWriteFontFace_Release(fontface);
7156 ref = IDWriteFactory_Release(factory);
7157 ok(ref == 0, "factory not released, %u\n", ref);
7160 static inline BOOL float_eq(FLOAT left, FLOAT right)
7162 int x = *(int *)&left;
7163 int y = *(int *)&right;
7165 if (x < 0)
7166 x = INT_MIN - x;
7167 if (y < 0)
7168 y = INT_MIN - y;
7170 return abs(x - y) <= 8;
7173 static void test_GetAlphaBlendParams(void)
7175 static const DWRITE_RENDERING_MODE rendermodes[] = {
7176 DWRITE_RENDERING_MODE_ALIASED,
7177 DWRITE_RENDERING_MODE_GDI_CLASSIC,
7178 DWRITE_RENDERING_MODE_GDI_NATURAL,
7179 DWRITE_RENDERING_MODE_NATURAL,
7180 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
7183 IDWriteGlyphRunAnalysis *analysis;
7184 FLOAT gamma, contrast, ctlevel;
7185 IDWriteRenderingParams *params;
7186 DWRITE_GLYPH_METRICS metrics;
7187 DWRITE_GLYPH_OFFSET offset;
7188 IDWriteFontFace *fontface;
7189 IDWriteFactory *factory;
7190 DWRITE_GLYPH_RUN run;
7191 FLOAT advance, expected_gdi_gamma;
7192 UINT value = 0;
7193 UINT16 glyph;
7194 UINT32 ch, i;
7195 HRESULT hr;
7196 ULONG ref;
7197 BOOL ret;
7199 factory = create_factory();
7200 fontface = create_fontface(factory);
7202 ch = 'A';
7203 glyph = 0;
7204 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
7205 ok(hr == S_OK, "got 0x%08x\n", hr);
7206 ok(glyph > 0, "got %u\n", glyph);
7208 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
7209 ok(hr == S_OK, "got 0x%08x\n", hr);
7210 advance = metrics.advanceWidth;
7212 offset.advanceOffset = 0.0;
7213 offset.ascenderOffset = 0.0;
7215 run.fontFace = fontface;
7216 run.fontEmSize = 24.0;
7217 run.glyphCount = 1;
7218 run.glyphIndices = &glyph;
7219 run.glyphAdvances = &advance;
7220 run.glyphOffsets = &offset;
7221 run.isSideways = FALSE;
7222 run.bidiLevel = 0;
7224 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.9, 0.3, 0.1, DWRITE_PIXEL_GEOMETRY_RGB,
7225 DWRITE_RENDERING_MODE_DEFAULT, &params);
7226 ok(hr == S_OK, "got 0x%08x\n", hr);
7228 value = 0;
7229 ret = SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
7230 ok(ret, "got %d\n", ret);
7231 expected_gdi_gamma = (FLOAT)(value / 1000.0);
7233 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
7234 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7235 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
7236 0.0, 0.0, &analysis);
7237 ok(hr == S_OK, "got 0x%08x\n", hr);
7239 gamma = contrast = ctlevel = -1.0;
7240 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, NULL, &gamma, &contrast, &ctlevel);
7241 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7242 ok(gamma == -1.0, "got %.2f\n", gamma);
7243 ok(contrast == -1.0, "got %.2f\n", contrast);
7244 ok(ctlevel == -1.0, "got %.2f\n", ctlevel);
7246 gamma = contrast = ctlevel = -1.0;
7247 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &ctlevel);
7248 ok(hr == S_OK, "got 0x%08x\n", hr);
7250 if (rendermodes[i] == DWRITE_RENDERING_MODE_GDI_CLASSIC || rendermodes[i] == DWRITE_RENDERING_MODE_GDI_NATURAL) {
7251 ok(float_eq(gamma, expected_gdi_gamma), "got %.2f, expected %.2f\n", gamma, expected_gdi_gamma);
7252 ok(contrast == 0.0f, "got %.2f\n", contrast);
7253 ok(ctlevel == 1.0f, "got %.2f\n", ctlevel);
7255 else {
7256 ok(gamma == 0.9f, "got %.2f\n", gamma);
7257 ok(contrast == 0.3f, "got %.2f\n", contrast);
7258 ok(ctlevel == 0.1f, "got %.2f\n", ctlevel);
7261 IDWriteGlyphRunAnalysis_Release(analysis);
7264 IDWriteRenderingParams_Release(params);
7265 IDWriteFontFace_Release(fontface);
7266 ref = IDWriteFactory_Release(factory);
7267 ok(ref == 0, "factory not released, %u\n", ref);
7270 static void test_CreateAlphaTexture(void)
7272 IDWriteGlyphRunAnalysis *analysis;
7273 DWRITE_GLYPH_METRICS metrics;
7274 DWRITE_GLYPH_OFFSET offset;
7275 IDWriteFontFace *fontface;
7276 IDWriteFactory *factory;
7277 DWRITE_GLYPH_RUN run;
7278 UINT32 ch, size;
7279 BYTE buff[1024];
7280 RECT bounds, r;
7281 FLOAT advance;
7282 UINT16 glyph;
7283 HRESULT hr;
7284 ULONG ref;
7286 factory = create_factory();
7287 fontface = create_fontface(factory);
7289 ch = 'A';
7290 glyph = 0;
7291 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
7292 ok(hr == S_OK, "got 0x%08x\n", hr);
7293 ok(glyph > 0, "got %u\n", glyph);
7295 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
7296 ok(hr == S_OK, "got 0x%08x\n", hr);
7297 advance = metrics.advanceWidth;
7299 offset.advanceOffset = 0.0;
7300 offset.ascenderOffset = 0.0;
7302 run.fontFace = fontface;
7303 run.fontEmSize = 24.0;
7304 run.glyphCount = 1;
7305 run.glyphIndices = &glyph;
7306 run.glyphAdvances = &advance;
7307 run.glyphOffsets = &offset;
7308 run.isSideways = FALSE;
7309 run.bidiLevel = 0;
7311 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7312 DWRITE_RENDERING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
7313 0.0, 0.0, &analysis);
7314 ok(hr == S_OK, "got 0x%08x\n", hr);
7316 SetRectEmpty(&bounds);
7317 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
7318 ok(hr == S_OK, "got 0x%08x\n", hr);
7319 ok(!IsRectEmpty(&bounds), "got empty rect\n");
7320 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top)*3;
7321 ok(sizeof(buff) >= size, "required %u\n", size);
7323 /* invalid type value */
7324 memset(buff, 0xcf, sizeof(buff));
7325 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &bounds, buff, sizeof(buff));
7326 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7327 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7329 memset(buff, 0xcf, sizeof(buff));
7330 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, 2);
7331 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
7332 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7334 /* vista version allows texture type mismatch, mark it broken for now */
7335 memset(buff, 0xcf, sizeof(buff));
7336 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, sizeof(buff));
7337 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
7338 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
7340 memset(buff, 0xcf, sizeof(buff));
7341 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, size-1);
7342 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
7343 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7345 IDWriteGlyphRunAnalysis_Release(analysis);
7347 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
7348 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
7349 0.0, 0.0, &analysis);
7350 ok(hr == S_OK, "got 0x%08x\n", hr);
7352 SetRectEmpty(&bounds);
7353 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
7354 ok(hr == S_OK, "got 0x%08x\n", hr);
7355 ok(!IsRectEmpty(&bounds), "got empty rect\n");
7356 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
7357 ok(sizeof(buff) >= size, "required %u\n", size);
7359 memset(buff, 0xcf, sizeof(buff));
7360 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, sizeof(buff));
7361 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7362 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7364 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, NULL, sizeof(buff));
7365 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7367 memset(buff, 0xcf, sizeof(buff));
7368 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, 0);
7369 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7370 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7372 /* buffer size is not enough */
7373 memset(buff, 0xcf, sizeof(buff));
7374 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, size-1);
7375 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
7376 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7378 /* request texture for rectangle that doesn't intersect */
7379 memset(buff, 0xcf, sizeof(buff));
7380 r = bounds;
7381 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7382 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
7383 ok(hr == S_OK, "got 0x%08x\n", hr);
7384 ok(buff[0] == 0, "got %1x\n", buff[0]);
7386 memset(buff, 0xcf, sizeof(buff));
7387 r = bounds;
7388 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7389 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
7390 ok(hr == S_OK, "got 0x%08x\n", hr);
7391 ok(buff[0] == 0, "got %1x\n", buff[0]);
7393 /* request texture for rectangle that doesn't intersect, small buffer */
7394 memset(buff, 0xcf, sizeof(buff));
7395 r = bounds;
7396 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
7397 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, size-1);
7398 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
7399 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
7401 /* vista version allows texture type mismatch, mark it broken for now */
7402 memset(buff, 0xcf, sizeof(buff));
7403 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, sizeof(buff));
7404 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
7405 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
7407 IDWriteGlyphRunAnalysis_Release(analysis);
7408 IDWriteFontFace_Release(fontface);
7409 ref = IDWriteFactory_Release(factory);
7410 ok(ref == 0, "factory not released, %u\n", ref);
7413 static BOOL get_expected_is_symbol(IDWriteFontFace *fontface)
7415 BOOL exists, is_symbol = FALSE;
7416 struct dwrite_fonttable cmap;
7417 const TT_OS2_V2 *tt_os2;
7418 const BYTE *tables;
7419 void *os2_context;
7420 WORD num_tables;
7421 unsigned int i;
7422 UINT32 size;
7423 HRESULT hr;
7425 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
7426 ok(hr == S_OK, "Failed to get OS/2 table, hr %#x.\n", hr);
7428 if (tt_os2)
7430 is_symbol = tt_os2->panose.bFamilyType == PAN_FAMILY_PICTORIAL;
7431 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
7434 if (is_symbol)
7435 return is_symbol;
7437 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, (const void **)&cmap.data,
7438 &cmap.size, &cmap.context, &exists);
7439 if (FAILED(hr) || !exists)
7440 return is_symbol;
7442 num_tables = table_read_be_word(&cmap, 0, FIELD_OFFSET(struct cmap_header, num_tables));
7443 tables = cmap.data + FIELD_OFFSET(struct cmap_header, tables);
7445 for (i = 0; i < num_tables; ++i)
7447 struct cmap_encoding_record *record = (struct cmap_encoding_record *)(tables + i * sizeof(*record));
7448 WORD platform, encoding;
7450 platform = table_read_be_word(&cmap, record, FIELD_OFFSET(struct cmap_encoding_record, platformID));
7451 encoding = table_read_be_word(&cmap, record, FIELD_OFFSET(struct cmap_encoding_record, encodingID));
7453 if (platform == OPENTYPE_CMAP_TABLE_PLATFORM_WIN && encoding == OPENTYPE_CMAP_TABLE_ENCODING_SYMBOL)
7455 is_symbol = TRUE;
7456 break;
7460 IDWriteFontFace_ReleaseFontTable(fontface, cmap.context);
7462 return is_symbol;
7465 static void test_IsSymbolFont(void)
7467 IDWriteFontCollection *collection;
7468 IDWriteFontFace *fontface;
7469 IDWriteFactory *factory;
7470 IDWriteFont *font;
7471 UINT32 count, i;
7472 HRESULT hr;
7473 ULONG ref;
7475 factory = create_factory();
7477 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
7478 ok(hr == S_OK, "got 0x%08x\n", hr);
7480 count = IDWriteFontCollection_GetFontFamilyCount(collection);
7481 for (i = 0; i < count; ++i)
7483 IDWriteLocalizedStrings *names;
7484 IDWriteFontFamily *family;
7485 UINT32 font_count, j;
7486 WCHAR nameW[256];
7488 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
7489 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
7491 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7492 ok(hr == S_OK, "Failed to get names, hr %#x.\n", hr);
7493 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
7494 IDWriteLocalizedStrings_Release(names);
7496 font_count = IDWriteFontFamily_GetFontCount(family);
7498 for (j = 0; j < font_count; ++j)
7500 BOOL is_symbol_font, is_symbol_face, is_symbol_expected;
7502 hr = IDWriteFontFamily_GetFont(family, j, &font);
7503 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
7505 hr = IDWriteFont_CreateFontFace(font, &fontface);
7506 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
7508 is_symbol_font = IDWriteFont_IsSymbolFont(font);
7509 is_symbol_face = IDWriteFontFace_IsSymbolFont(fontface);
7510 ok(is_symbol_font == is_symbol_face, "Unexpected symbol flag.\n");
7512 is_symbol_expected = get_expected_is_symbol(fontface);
7513 ok(is_symbol_expected == is_symbol_face, "Unexpected is_symbol flag %d for %s, font %d.\n",
7514 is_symbol_face, wine_dbgstr_w(nameW), j);
7516 IDWriteFontFace_Release(fontface);
7517 IDWriteFont_Release(font);
7520 IDWriteFontFamily_Release(family);
7523 IDWriteFontCollection_Release(collection);
7525 ref = IDWriteFactory_Release(factory);
7526 ok(ref == 0, "factory not released, %u\n", ref);
7529 struct CPAL_Header_0
7531 USHORT version;
7532 USHORT numPaletteEntries;
7533 USHORT numPalette;
7534 USHORT numColorRecords;
7535 ULONG offsetFirstColorRecord;
7536 USHORT colorRecordIndices[1];
7539 static void test_GetPaletteEntries(void)
7541 IDWriteFontFace2 *fontface2;
7542 IDWriteFontFace *fontface;
7543 IDWriteFactory *factory;
7544 IDWriteFont *font;
7545 DWRITE_COLOR_F color;
7546 UINT32 palettecount, entrycount, size, colorrecords;
7547 void *ctxt;
7548 const struct CPAL_Header_0 *cpal_header;
7549 HRESULT hr;
7550 BOOL exists;
7551 ULONG ref;
7553 factory = create_factory();
7555 /* Tahoma, no color support */
7556 fontface = create_fontface(factory);
7557 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7558 IDWriteFontFace_Release(fontface);
7559 if (hr != S_OK) {
7560 ref = IDWriteFactory_Release(factory);
7561 ok(ref == 0, "factory not released, %u\n", ref);
7562 win_skip("GetPaletteEntries() is not supported.\n");
7563 return;
7566 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 1, &color);
7567 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
7568 IDWriteFontFace2_Release(fontface2);
7570 /* Segoe UI Emoji, with color support */
7571 font = get_font(factory, L"Segoe UI Emoji", DWRITE_FONT_STYLE_NORMAL);
7572 if (!font) {
7573 ref = IDWriteFactory_Release(factory);
7574 ok(ref == 0, "factory not released, %u\n", ref);
7575 skip("Segoe UI Emoji font not found.\n");
7576 return;
7579 hr = IDWriteFont_CreateFontFace(font, &fontface);
7580 ok(hr == S_OK, "got 0x%08x\n", hr);
7581 IDWriteFont_Release(font);
7583 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7584 ok(hr == S_OK, "got 0x%08x\n", hr);
7585 IDWriteFontFace_Release(fontface);
7587 palettecount = IDWriteFontFace2_GetColorPaletteCount(fontface2);
7588 ok(palettecount >= 1, "got %u\n", palettecount);
7590 entrycount = IDWriteFontFace2_GetPaletteEntryCount(fontface2);
7591 ok(entrycount >= 1, "got %u\n", entrycount);
7593 exists = FALSE;
7594 hr = IDWriteFontFace2_TryGetFontTable(fontface2, MS_CPAL_TAG, (const void**)&cpal_header, &size, &ctxt, &exists);
7595 ok(hr == S_OK, "got 0x%08x\n", hr);
7596 ok(exists, "got %d\n", exists);
7597 colorrecords = GET_BE_WORD(cpal_header->numColorRecords);
7598 ok(colorrecords >= 1, "got %u\n", colorrecords);
7600 /* invalid palette index */
7601 color.r = color.g = color.b = color.a = 123.0;
7602 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, palettecount, 0, 1, &color);
7603 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
7604 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
7605 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7607 /* invalid entry index */
7608 color.r = color.g = color.b = color.a = 123.0;
7609 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount, 1, &color);
7610 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7611 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
7612 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7614 color.r = color.g = color.b = color.a = 123.0;
7615 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount - 1, 1, &color);
7616 ok(hr == S_OK, "got 0x%08x\n", hr);
7617 ok(color.r != 123.0 && color.g != 123.0 && color.b != 123.0 && color.a != 123.0,
7618 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7620 /* zero return length */
7621 color.r = color.g = color.b = color.a = 123.0;
7622 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 0, &color);
7623 ok(hr == S_OK, "got 0x%08x\n", hr);
7624 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
7625 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
7627 IDWriteFontFace2_Release(fontface2);
7628 ref = IDWriteFactory_Release(factory);
7629 ok(ref == 0, "factory not released, %u\n", ref);
7632 static void test_TranslateColorGlyphRun(void)
7634 IDWriteColorGlyphRunEnumerator1 *layers1;
7635 IDWriteColorGlyphRunEnumerator *layers;
7636 const DWRITE_COLOR_GLYPH_RUN1 *colorrun1;
7637 const DWRITE_COLOR_GLYPH_RUN *colorrun;
7638 IDWriteFontFace2 *fontface2;
7639 IDWriteFontFace *fontface;
7640 IDWriteFactory2 *factory;
7641 DWRITE_GLYPH_RUN run;
7642 UINT32 codepoints[2];
7643 IDWriteFont *font;
7644 UINT16 glyphs[2];
7645 BOOL hasrun;
7646 HRESULT hr;
7647 ULONG ref;
7649 factory = create_factory_iid(&IID_IDWriteFactory2);
7650 if (!factory) {
7651 win_skip("TranslateColorGlyphRun() is not supported.\n");
7652 return;
7655 /* Tahoma, no color support */
7656 fontface = create_fontface((IDWriteFactory *)factory);
7658 codepoints[0] = 'A';
7659 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7660 ok(hr == S_OK, "got 0x%08x\n", hr);
7662 run.fontFace = fontface;
7663 run.fontEmSize = 20.0f;
7664 run.glyphCount = 1;
7665 run.glyphIndices = glyphs;
7666 run.glyphAdvances = NULL;
7667 run.glyphOffsets = NULL;
7668 run.isSideways = FALSE;
7669 run.bidiLevel = 0;
7671 layers = (void*)0xdeadbeef;
7672 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7673 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7674 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
7675 ok(layers == NULL, "got %p\n", layers);
7676 IDWriteFontFace_Release(fontface);
7678 /* Segoe UI Emoji, with color support */
7679 font = get_font((IDWriteFactory *)factory, L"Segoe UI Emoji", DWRITE_FONT_STYLE_NORMAL);
7680 if (!font) {
7681 IDWriteFactory2_Release(factory);
7682 skip("Segoe UI Emoji font not found.\n");
7683 return;
7686 hr = IDWriteFont_CreateFontFace(font, &fontface);
7687 ok(hr == S_OK, "got 0x%08x\n", hr);
7688 IDWriteFont_Release(font);
7690 codepoints[0] = 0x26c4;
7691 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7692 ok(hr == S_OK, "got 0x%08x\n", hr);
7694 run.fontFace = fontface;
7696 layers = NULL;
7697 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7698 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7699 ok(hr == S_OK, "got 0x%08x\n", hr);
7700 ok(layers != NULL, "got %p\n", layers);
7702 hr = IDWriteColorGlyphRunEnumerator_QueryInterface(layers, &IID_IDWriteColorGlyphRunEnumerator1, (void **)&layers1);
7703 if (FAILED(hr))
7705 layers1 = NULL;
7706 win_skip("IDWriteColorGlyphRunEnumerator1 is not supported.\n");
7709 for (;;) {
7710 hasrun = FALSE;
7711 hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &hasrun);
7712 ok(hr == S_OK, "got 0x%08x\n", hr);
7714 if (!hasrun)
7715 break;
7717 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
7718 ok(hr == S_OK, "got 0x%08x\n", hr);
7719 ok(colorrun->glyphRun.fontFace != NULL, "got fontface %p\n", colorrun->glyphRun.fontFace);
7720 ok(colorrun->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun->glyphRun.fontEmSize);
7721 ok(colorrun->glyphRun.glyphCount > 0, "got wrong glyph count %u\n", colorrun->glyphRun.glyphCount);
7722 ok(colorrun->glyphRun.glyphIndices != NULL, "got null glyph indices %p\n", colorrun->glyphRun.glyphIndices);
7723 ok(colorrun->glyphRun.glyphAdvances != NULL, "got null glyph advances %p\n", colorrun->glyphRun.glyphAdvances);
7725 if (layers1)
7727 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7728 ok(hr == S_OK, "Failed to get color runt, hr %#x.\n", hr);
7729 ok(colorrun1->glyphRun.fontFace != NULL, "Unexpected fontface %p.\n", colorrun1->glyphRun.fontFace);
7730 ok(colorrun1->glyphRun.fontEmSize == 20.0f, "Unexpected font size %f.\n", colorrun1->glyphRun.fontEmSize);
7731 ok(colorrun1->glyphRun.glyphCount > 0, "Unexpected glyph count %u\n", colorrun1->glyphRun.glyphCount);
7732 ok(colorrun1->glyphRun.glyphIndices != NULL, "Unexpected indices array.\n");
7733 ok(colorrun1->glyphRun.glyphAdvances != NULL, "Unexpected advances array.\n");
7737 /* iterated all way through */
7738 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
7739 ok(hr == E_NOT_VALID_STATE, "got 0x%08x\n", hr);
7741 if (layers1)
7743 hr = IDWriteColorGlyphRunEnumerator1_GetCurrentRun(layers1, &colorrun1);
7744 ok(hr == E_NOT_VALID_STATE, "Unexpected hr %#x.\n", hr);
7747 IDWriteColorGlyphRunEnumerator_Release(layers);
7748 if (layers1)
7749 IDWriteColorGlyphRunEnumerator1_Release(layers1);
7751 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
7752 ok(hr == S_OK, "got 0x%08x\n", hr);
7754 /* invalid palette index */
7755 layers = (void*)0xdeadbeef;
7756 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7757 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2),
7758 &layers);
7759 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
7760 ok(layers == NULL, "got %p\n", layers);
7762 layers = NULL;
7763 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7764 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2) - 1,
7765 &layers);
7766 ok(hr == S_OK, "got 0x%08x\n", hr);
7767 IDWriteColorGlyphRunEnumerator_Release(layers);
7769 /* color font, glyph without color info */
7770 codepoints[0] = 'A';
7771 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
7772 ok(hr == S_OK, "got 0x%08x\n", hr);
7774 layers = (void*)0xdeadbeef;
7775 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7776 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7777 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
7778 ok(layers == NULL, "got %p\n", layers);
7780 /* one glyph with, one without */
7781 codepoints[0] = 'A';
7782 codepoints[1] = 0x26c4;
7784 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 2, glyphs);
7785 ok(hr == S_OK, "got 0x%08x\n", hr);
7787 run.glyphCount = 2;
7789 layers = NULL;
7790 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
7791 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
7792 ok(hr == S_OK, "got 0x%08x\n", hr);
7793 ok(layers != NULL, "got %p\n", layers);
7794 IDWriteColorGlyphRunEnumerator_Release(layers);
7796 IDWriteFontFace2_Release(fontface2);
7797 IDWriteFontFace_Release(fontface);
7798 ref = IDWriteFactory2_Release(factory);
7799 ok(ref == 0, "factory not released, %u\n", ref);
7802 static void test_HasCharacter(void)
7804 IDWriteFactory3 *factory3;
7805 IDWriteFactory *factory;
7806 IDWriteFont3 *font3;
7807 IDWriteFont *font;
7808 HRESULT hr;
7809 ULONG ref;
7810 BOOL ret;
7812 factory = create_factory();
7814 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
7815 ok(font != NULL, "failed to create font\n");
7817 /* Win8 is broken, QI claims to support IDWriteFont3, but in fact it does not */
7818 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
7819 if (hr == S_OK) {
7820 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
7821 ok(hr == S_OK, "got 0x%08x\n", hr);
7823 ret = IDWriteFont3_HasCharacter(font3, 'A');
7824 ok(ret, "got %d\n", ret);
7826 IDWriteFont3_Release(font3);
7827 IDWriteFactory3_Release(factory3);
7829 else
7830 win_skip("IDWriteFont3 is not supported.\n");
7832 IDWriteFont_Release(font);
7833 ref = IDWriteFactory_Release(factory);
7834 ok(ref == 0, "factory not released, %u\n", ref);
7837 static BOOL has_main_axis_values(const DWRITE_FONT_AXIS_VALUE *values, unsigned int count)
7839 BOOL has_wght = FALSE, has_wdth = FALSE, has_ital = FALSE, has_slnt = FALSE;
7840 unsigned int i;
7842 for (i = 0; i < count; ++i)
7844 if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT)
7845 has_wght = TRUE;
7846 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_WIDTH)
7847 has_wdth = TRUE;
7848 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_ITALIC)
7849 has_ital = TRUE;
7850 else if (values[i].axisTag == DWRITE_FONT_AXIS_TAG_SLANT)
7851 has_slnt = TRUE;
7854 return has_wght && has_wdth && has_ital && has_slnt;
7857 static void test_CreateFontFaceReference(void)
7859 IDWriteFontFaceReference *ref, *ref1, *ref3;
7860 IDWriteFontFace3 *fontface, *fontface1;
7861 DWRITE_FONT_AXIS_VALUE axis_values[16];
7862 IDWriteFontCollection1 *collection;
7863 IDWriteFontFile *file, *file1;
7864 IDWriteFactory3 *factory;
7865 UINT32 index, count, i;
7866 IDWriteFont3 *font3;
7867 ULONG refcount;
7868 WCHAR *path;
7869 HRESULT hr;
7870 BOOL ret;
7872 factory = create_factory_iid(&IID_IDWriteFactory3);
7873 if (!factory) {
7874 win_skip("CreateFontFaceReference() is not supported.\n");
7875 return;
7878 path = create_testfontfile(test_fontfile);
7880 hr = IDWriteFactory3_CreateFontFaceReference(factory, NULL, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
7881 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7883 /* out of range simulation flags */
7884 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, ~0u, &ref);
7885 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7887 /* test file is not a collection, but reference could still be created with non-zero face index */
7888 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref);
7889 ok(hr == S_OK, "got 0x%08x\n", hr);
7891 index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
7892 ok(index == 1, "got %u\n", index);
7894 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
7895 ok(hr == S_OK, "got 0x%08x\n", hr);
7896 IDWriteFontFile_Release(file);
7898 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
7899 todo_wine
7900 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
7902 IDWriteFontFaceReference_Release(ref);
7904 /* path however has to be valid */
7905 hr = IDWriteFactory3_CreateFontFaceReference(factory, L"dummy", NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
7906 todo_wine
7907 ok(hr == DWRITE_E_FILENOTFOUND, "got 0x%08x\n", hr);
7908 if (hr == S_OK)
7909 IDWriteFontFaceReference_Release(ref);
7911 EXPECT_REF(factory, 1);
7912 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
7913 ok(hr == S_OK, "got 0x%08x\n", hr);
7914 EXPECT_REF(factory, 2);
7916 /* new file is returned */
7917 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
7918 ok(hr == S_OK, "got 0x%08x\n", hr);
7920 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
7921 ok(hr == S_OK, "got 0x%08x\n", hr);
7922 ok(file != file1, "got %p, previous file %p\n", file1, file);
7924 IDWriteFontFile_Release(file);
7925 IDWriteFontFile_Release(file1);
7927 /* references are not reused */
7928 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
7929 ok(hr == S_OK, "got 0x%08x\n", hr);
7930 ok(ref1 != ref, "got %p, previous ref %p\n", ref1, ref);
7932 /* created fontfaces are cached */
7933 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
7934 ok(hr == S_OK, "got 0x%08x\n", hr);
7936 hr = IDWriteFontFaceReference_CreateFontFace(ref1, &fontface1);
7937 ok(hr == S_OK, "got 0x%08x\n", hr);
7938 ok(fontface == fontface1, "got %p, expected %p\n", fontface1, fontface);
7939 IDWriteFontFace3_Release(fontface);
7940 IDWriteFontFace3_Release(fontface1);
7942 /* reference equality */
7943 ret = IDWriteFontFaceReference_Equals(ref, ref1);
7944 ok(ret, "got %d\n", ret);
7945 IDWriteFontFaceReference_Release(ref1);
7947 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
7948 ok(hr == S_OK, "got 0x%08x\n", hr);
7949 ret = IDWriteFontFaceReference_Equals(ref, ref1);
7950 ok(!ret, "got %d\n", ret);
7951 IDWriteFontFaceReference_Release(ref1);
7953 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_BOLD, &ref1);
7954 ok(hr == S_OK, "got 0x%08x\n", hr);
7955 ret = IDWriteFontFaceReference_Equals(ref, ref1);
7956 ok(!ret, "got %d\n", ret);
7957 IDWriteFontFaceReference_Release(ref1);
7959 IDWriteFontFaceReference_Release(ref);
7961 /* create reference from a file */
7962 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
7963 ok(hr == S_OK, "got 0x%08x\n", hr);
7965 hr = IDWriteFactory3_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
7966 ok(hr == S_OK, "got 0x%08x\n", hr);
7968 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
7969 ok(hr == S_OK, "got 0x%08x\n", hr);
7970 ok(file != file1, "got %p, previous file %p\n", file1, file);
7972 IDWriteFontFaceReference_Release(ref);
7973 IDWriteFontFile_Release(file);
7974 IDWriteFontFile_Release(file1);
7976 /* References returned from IDWriteFont3/IDWriteFontFace3. */
7977 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
7978 ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
7980 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
7981 for (i = 0; i < count; i++)
7983 IDWriteFontFamily1 *family;
7984 UINT32 font_count, j;
7986 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
7987 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
7989 font_count = IDWriteFontFamily1_GetFontCount(family);
7991 for (j = 0; j < font_count; j++)
7993 IDWriteFontFaceReference1 *ref2;
7995 hr = IDWriteFontFamily1_GetFont(family, j, &font3);
7996 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
7998 hr = IDWriteFont3_GetFontFaceReference(font3, &ref);
7999 ok(hr == S_OK, "Failed to get reference object, hr %#x.\n", hr);
8001 hr = IDWriteFont3_GetFontFaceReference(font3, &ref1);
8002 ok(hr == S_OK, "Failed to get reference object, hr %#x.\n", hr);
8003 ok(ref != ref1, "Unexpected reference object %p, %p.\n", ref1, ref);
8005 hr = IDWriteFont3_CreateFontFace(font3, &fontface);
8006 ok(hr == S_OK, "Failed to create a fontface, hr %#x.\n", hr);
8008 /* Fonts present regular properties as axis values, for non-variable fonts too.
8009 Normally it would include weight/width/slant/italic, but could also contain optical size axis. */
8010 if (SUCCEEDED(hr = IDWriteFontFaceReference_QueryInterface(ref, &IID_IDWriteFontFaceReference1,
8011 (void **)&ref2)))
8013 UINT32 axis_count = IDWriteFontFaceReference1_GetFontAxisValueCount(ref2);
8014 todo_wine
8015 ok(axis_count >= 4, "Unexpected axis value count.\n");
8017 hr = IDWriteFontFaceReference1_GetFontAxisValues(ref2, axis_values, ARRAY_SIZE(axis_values));
8018 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
8020 todo_wine
8021 ok(has_main_axis_values(axis_values, axis_count), "Unexpected axis returned.\n");
8023 IDWriteFontFaceReference1_Release(ref2);
8026 IDWriteFontFaceReference_Release(ref);
8027 IDWriteFontFaceReference_Release(ref1);
8029 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref);
8030 ok(hr == S_OK, "Failed to get a reference, hr %#x.\n", hr);
8031 EXPECT_REF(fontface, 2);
8033 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref1);
8034 ok(hr == S_OK, "Failed to get a reference, hr %#x.\n", hr);
8035 ok(ref == ref1, "Unexpected reference %p, %p.\n", ref1, ref);
8036 EXPECT_REF(fontface, 3);
8038 hr = IDWriteFontFace3_QueryInterface(fontface, &IID_IDWriteFontFaceReference, (void **)&ref3);
8039 ok(hr == S_OK || broken(FAILED(hr)), "Failed to get interface, hr %#x.\n", hr);
8040 if (SUCCEEDED(hr))
8042 ok(ref == ref3, "Unexpected reference %p.\n", ref3);
8043 IDWriteFontFaceReference_Release(ref3);
8046 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface1);
8047 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
8048 ok(fontface1 == fontface, "Unexpected fontface %p, %p.\n", fontface1, fontface);
8049 IDWriteFontFace3_Release(fontface1);
8051 IDWriteFontFaceReference_Release(ref);
8052 IDWriteFontFaceReference_Release(ref1);
8054 IDWriteFontFace3_Release(fontface);
8055 IDWriteFont3_Release(font3);
8058 IDWriteFontFamily1_Release(family);
8060 IDWriteFontCollection1_Release(collection);
8062 refcount = IDWriteFactory3_Release(factory);
8063 ok(refcount == 0, "factory not released, %u\n", refcount);
8064 DELETE_FONTFILE(path);
8067 static void get_expected_fontsig(IDWriteFont *font, FONTSIGNATURE *fontsig)
8069 void *os2_context;
8070 IDWriteFontFace *fontface;
8071 const TT_OS2_V2 *tt_os2;
8072 UINT32 size;
8073 BOOL exists;
8074 HRESULT hr;
8076 memset(fontsig, 0, sizeof(*fontsig));
8078 hr = IDWriteFont_CreateFontFace(font, &fontface);
8079 ok(hr == S_OK, "got 0x%08x\n", hr);
8081 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_OS2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
8082 ok(hr == S_OK, "got 0x%08x\n", hr);
8084 if (tt_os2) {
8085 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
8086 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
8087 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
8088 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
8090 if (GET_BE_WORD(tt_os2->version) == 0) {
8091 fontsig->fsCsb[0] = 0;
8092 fontsig->fsCsb[1] = 0;
8094 else {
8095 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
8096 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
8099 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
8102 IDWriteFontFace_Release(fontface);
8105 static void test_GetFontSignature(void)
8107 IDWriteFontCollection *syscollection;
8108 IDWriteGdiInterop1 *interop1;
8109 IDWriteGdiInterop *interop;
8110 IDWriteFactory *factory;
8111 FONTSIGNATURE fontsig;
8112 UINT count, i;
8113 HRESULT hr;
8114 ULONG ref;
8116 factory = create_factory();
8118 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
8119 ok(hr == S_OK, "got 0x%08x\n", hr);
8121 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
8122 IDWriteGdiInterop_Release(interop);
8123 if (FAILED(hr)) {
8124 win_skip("GetFontSignature() is not supported.\n");
8125 IDWriteGdiInterop_Release(interop);
8126 IDWriteFactory_Release(factory);
8127 return;
8129 ok(hr == S_OK, "got 0x%08x\n", hr);
8131 hr = IDWriteGdiInterop1_GetFontSignature(interop1, NULL, &fontsig);
8132 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
8134 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8135 ok(hr == S_OK, "got 0x%08x\n", hr);
8136 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8138 for (i = 0; i < count; i++) {
8139 FONTSIGNATURE expected_signature;
8140 IDWriteLocalizedStrings *names;
8141 IDWriteFontFamily *family;
8142 IDWriteFont *font;
8143 WCHAR nameW[256];
8145 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8146 ok(hr == S_OK, "got 0x%08x\n", hr);
8148 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8149 DWRITE_FONT_STYLE_NORMAL, &font);
8150 ok(hr == S_OK, "got 0x%08x\n", hr);
8152 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8153 ok(hr == S_OK, "got 0x%08x\n", hr);
8155 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8157 IDWriteLocalizedStrings_Release(names);
8159 hr = IDWriteGdiInterop1_GetFontSignature(interop1, font, &fontsig);
8160 ok(hr == S_OK, "got 0x%08x\n", hr);
8162 get_expected_fontsig(font, &expected_signature);
8164 ok(fontsig.fsUsb[0] == expected_signature.fsUsb[0], "%s: fsUsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
8165 fontsig.fsUsb[0], expected_signature.fsUsb[0]);
8166 ok(fontsig.fsUsb[1] == expected_signature.fsUsb[1], "%s: fsUsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
8167 fontsig.fsUsb[1], expected_signature.fsUsb[1]);
8168 ok(fontsig.fsUsb[2] == expected_signature.fsUsb[2], "%s: fsUsb[2] %#x, expected %#x\n", wine_dbgstr_w(nameW),
8169 fontsig.fsUsb[2], expected_signature.fsUsb[2]);
8170 ok(fontsig.fsUsb[3] == expected_signature.fsUsb[3], "%s: fsUsb[3] %#x, expected %#x\n", wine_dbgstr_w(nameW),
8171 fontsig.fsUsb[3], expected_signature.fsUsb[3]);
8173 ok(fontsig.fsCsb[0] == expected_signature.fsCsb[0], "%s: fsCsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
8174 fontsig.fsCsb[0], expected_signature.fsCsb[0]);
8175 ok(fontsig.fsCsb[1] == expected_signature.fsCsb[1], "%s: fsCsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
8176 fontsig.fsCsb[1], expected_signature.fsCsb[1]);
8178 IDWriteFont_Release(font);
8179 IDWriteFontFamily_Release(family);
8182 IDWriteGdiInterop1_Release(interop1);
8183 IDWriteFontCollection_Release(syscollection);
8184 ref = IDWriteFactory_Release(factory);
8185 ok(ref == 0, "factory not released, %u\n", ref);
8188 static void test_font_properties(void)
8190 IDWriteFontFace3 *fontface3;
8191 IDWriteFontFace *fontface;
8192 IDWriteFactory *factory;
8193 DWRITE_FONT_STYLE style;
8194 IDWriteFont *font;
8195 HRESULT hr;
8196 ULONG ref;
8198 factory = create_factory();
8200 /* this creates simulated font */
8201 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
8203 style = IDWriteFont_GetStyle(font);
8204 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
8206 hr = IDWriteFont_CreateFontFace(font, &fontface);
8207 ok(hr == S_OK, "got 0x%08x\n", hr);
8209 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
8210 IDWriteFontFace_Release(fontface);
8211 if (hr == S_OK) {
8212 style = IDWriteFontFace3_GetStyle(fontface3);
8213 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
8215 IDWriteFontFace3_Release(fontface3);
8218 IDWriteFont_Release(font);
8219 ref = IDWriteFactory_Release(factory);
8220 ok(ref == 0, "factory not released, %u\n", ref);
8223 static BOOL has_vertical_glyph_variants(IDWriteFontFace1 *fontface)
8225 const OT_FeatureList *featurelist;
8226 const OT_LookupList *lookup_list;
8227 BOOL exists = FALSE, ret = FALSE;
8228 const GSUB_Header *header;
8229 const void *data;
8230 void *context;
8231 UINT32 size;
8232 HRESULT hr;
8233 UINT16 i;
8235 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
8236 ok(hr == S_OK, "got 0x%08x\n", hr);
8238 if (!exists)
8239 return FALSE;
8241 header = data;
8242 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
8243 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
8245 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
8246 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
8247 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
8248 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
8249 const GSUB_SingleSubstFormat2 *subst2;
8250 const OT_LookupTable *lookup_table;
8251 UINT32 offset;
8253 if (lookup_count == 0)
8254 continue;
8256 for (i = 0; i < lookup_count; i++) {
8257 /* check if lookup is empty */
8258 index = GET_BE_WORD(feature->LookupListIndex[i]);
8259 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
8261 type = GET_BE_WORD(lookup_table->LookupType);
8262 ok(type == 1 || type == 7, "got unexpected lookup type %u\n", type);
8264 count = GET_BE_WORD(lookup_table->SubTableCount);
8265 if (count == 0)
8266 continue;
8268 ok(count > 0, "got unexpected subtable count %u\n", count);
8270 offset = GET_BE_WORD(lookup_table->SubTable[0]);
8271 if (type == 7) {
8272 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
8273 if (GET_BE_WORD(ext->SubstFormat) == 1)
8274 offset += GET_BE_DWORD(ext->ExtensionOffset);
8275 else
8276 ok(0, "Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
8279 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
8280 index = GET_BE_WORD(subst2->SubstFormat);
8281 if (index == 1)
8282 ret = TRUE;
8283 else if (index == 2) {
8284 /* SimSun-ExtB has 0 glyph count for this substitution */
8285 if (GET_BE_WORD(subst2->GlyphCount) > 0)
8286 ret = TRUE;
8288 else
8289 ok(0, "unknown Single Substitution Format, %u\n", index);
8291 if (ret)
8292 break;
8297 IDWriteFontFace1_ReleaseFontTable(fontface, context);
8299 return ret;
8302 static void test_HasVerticalGlyphVariants(void)
8304 IDWriteFontCollection *syscollection;
8305 IDWriteFontFace1 *fontface1;
8306 IDWriteFontFace *fontface;
8307 IDWriteFactory *factory;
8308 UINT32 count, i;
8309 HRESULT hr;
8310 ULONG ref;
8312 factory = create_factory();
8313 fontface = create_fontface(factory);
8315 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8316 IDWriteFontFace_Release(fontface);
8317 if (hr != S_OK) {
8318 win_skip("HasVerticalGlyphVariants() is not supported.\n");
8319 IDWriteFactory_Release(factory);
8320 return;
8322 IDWriteFontFace1_Release(fontface1);
8324 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8325 ok(hr == S_OK, "got 0x%08x\n", hr);
8326 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8328 for (i = 0; i < count; i++) {
8329 IDWriteLocalizedStrings *names;
8330 BOOL expected_vert, has_vert;
8331 IDWriteFontFamily *family;
8332 IDWriteFont *font;
8333 WCHAR nameW[256];
8335 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8336 ok(hr == S_OK, "got 0x%08x\n", hr);
8338 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8339 DWRITE_FONT_STYLE_NORMAL, &font);
8340 ok(hr == S_OK, "got 0x%08x\n", hr);
8342 hr = IDWriteFont_CreateFontFace(font, &fontface);
8343 ok(hr == S_OK, "got 0x%08x\n", hr);
8345 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8346 ok(hr == S_OK, "got 0x%08x\n", hr);
8348 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8349 ok(hr == S_OK, "got 0x%08x\n", hr);
8351 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8353 expected_vert = has_vertical_glyph_variants(fontface1);
8354 has_vert = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
8356 ok(expected_vert == has_vert, "%s: expected vertical feature %d, got %d\n",
8357 wine_dbgstr_w(nameW), expected_vert, has_vert);
8359 IDWriteLocalizedStrings_Release(names);
8360 IDWriteFont_Release(font);
8362 IDWriteFontFace1_Release(fontface1);
8363 IDWriteFontFace_Release(fontface);
8364 IDWriteFontFamily_Release(family);
8367 IDWriteFontCollection_Release(syscollection);
8368 ref = IDWriteFactory_Release(factory);
8369 ok(ref == 0, "factory not released, %u\n", ref);
8372 static void test_HasKerningPairs(void)
8374 IDWriteFontCollection *syscollection;
8375 IDWriteFontFace1 *fontface1;
8376 IDWriteFontFace *fontface;
8377 IDWriteFactory *factory;
8378 UINT32 count, i;
8379 HRESULT hr;
8380 ULONG ref;
8382 factory = create_factory();
8383 fontface = create_fontface(factory);
8385 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
8386 IDWriteFontFace_Release(fontface);
8387 if (hr != S_OK) {
8388 win_skip("HasKerningPairs() is not supported.\n");
8389 IDWriteFactory_Release(factory);
8390 return;
8392 IDWriteFontFace1_Release(fontface1);
8394 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8395 ok(hr == S_OK, "got 0x%08x\n", hr);
8396 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8398 for (i = 0; i < count; i++) {
8399 IDWriteLocalizedStrings *names;
8400 BOOL exists, has_kerningpairs;
8401 IDWriteFontFamily *family;
8402 IDWriteFont *font;
8403 WCHAR nameW[256];
8404 const void *data;
8405 void *context;
8406 UINT32 size;
8408 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8409 ok(hr == S_OK, "got 0x%08x\n", hr);
8411 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
8412 DWRITE_FONT_STYLE_NORMAL, &font);
8413 ok(hr == S_OK, "got 0x%08x\n", hr);
8415 hr = IDWriteFont_CreateFontFace(font, &fontface);
8416 ok(hr == S_OK, "got 0x%08x\n", hr);
8418 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
8419 ok(hr == S_OK, "got 0x%08x\n", hr);
8421 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8422 ok(hr == S_OK, "got 0x%08x\n", hr);
8424 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
8426 exists = FALSE;
8427 hr = IDWriteFontFace1_TryGetFontTable(fontface1, MS_KERN_TAG, &data, &size, &context, &exists);
8428 ok(hr == S_OK, "got 0x%08x\n", hr);
8429 IDWriteFontFace1_ReleaseFontTable(fontface1, context);
8431 has_kerningpairs = IDWriteFontFace1_HasKerningPairs(fontface1);
8432 if (!exists)
8433 ok(!has_kerningpairs, "%s: expected %d, got %d\n", wine_dbgstr_w(nameW), exists, has_kerningpairs);
8435 IDWriteLocalizedStrings_Release(names);
8436 IDWriteFont_Release(font);
8438 IDWriteFontFace1_Release(fontface1);
8439 IDWriteFontFace_Release(fontface);
8440 IDWriteFontFamily_Release(family);
8443 IDWriteFontCollection_Release(syscollection);
8444 ref = IDWriteFactory_Release(factory);
8445 ok(ref == 0, "factory not released, %u\n", ref);
8448 static float get_scaled_metric(const DWRITE_GLYPH_RUN *run, float metric, const DWRITE_FONT_METRICS *m)
8450 return run->fontEmSize * metric / m->designUnitsPerEm;
8453 static void get_expected_glyph_origins(D2D1_POINT_2F baseline_origin, const DWRITE_GLYPH_RUN *run,
8454 D2D1_POINT_2F *origins)
8456 DWRITE_GLYPH_METRICS glyph_metrics[2];
8457 DWRITE_FONT_METRICS metrics;
8458 unsigned int i;
8459 HRESULT hr;
8461 IDWriteFontFace_GetMetrics(run->fontFace, &metrics);
8463 hr = IDWriteFontFace_GetDesignGlyphMetrics(run->fontFace, run->glyphIndices, run->glyphCount, glyph_metrics,
8464 run->isSideways);
8465 ok(hr == S_OK, "Failed to get glyph metrics, hr %#x.\n", hr);
8467 if (run->bidiLevel & 1)
8469 float advance;
8471 advance = get_scaled_metric(run, run->isSideways ? glyph_metrics[0].advanceHeight :
8472 glyph_metrics[0].advanceWidth, &metrics);
8474 baseline_origin.x -= advance;
8476 for (i = 0; i < run->glyphCount; ++i)
8478 origins[i] = baseline_origin;
8480 if (run->isSideways)
8482 origins[i].x += get_scaled_metric(run, glyph_metrics[i].verticalOriginY, &metrics);
8483 origins[i].y += metrics.designUnitsPerEm / (4.0f * run->fontEmSize);
8486 origins[i].x -= run->glyphOffsets[i].advanceOffset;
8487 origins[i].y -= run->glyphOffsets[i].ascenderOffset;
8489 baseline_origin.x -= run->glyphAdvances[i];
8492 else
8494 for (i = 0; i < run->glyphCount; ++i)
8496 origins[i] = baseline_origin;
8498 if (run->isSideways)
8500 origins[i].x += get_scaled_metric(run, glyph_metrics[i].verticalOriginY, &metrics);
8501 origins[i].y += metrics.designUnitsPerEm / (4.0f * run->fontEmSize);
8504 origins[i].x += run->glyphOffsets[i].advanceOffset;
8505 origins[i].y -= run->glyphOffsets[i].ascenderOffset;
8507 baseline_origin.x += run->glyphAdvances[i];
8512 static void test_ComputeGlyphOrigins(void)
8514 static const struct origins_test
8516 D2D1_POINT_2F baseline_origin;
8517 float advances[2];
8518 DWRITE_GLYPH_OFFSET offsets[2];
8519 unsigned int bidi_level;
8520 unsigned int sideways;
8522 origins_tests[] =
8524 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } } },
8525 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } } },
8526 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 1 },
8528 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 0, 1 },
8529 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } }, 0, 1 },
8530 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0 } }, 1, 1 },
8531 { { 123.0f, 321.0f }, { 10.0f, 20.0f }, { { 0.3f, 0.5f }, { -0.1f, 0.9f } }, 1, 1 },
8533 IDWriteFactory4 *factory;
8534 DWRITE_GLYPH_RUN run;
8535 HRESULT hr;
8536 D2D1_POINT_2F origins[2], expected_origins[2];
8537 D2D1_POINT_2F baseline_origin;
8538 UINT16 glyphs[2] = { 0 };
8539 FLOAT advances[2];
8540 DWRITE_MATRIX m;
8541 ULONG ref;
8542 unsigned int i, j;
8543 IDWriteFontFace *fontface;
8545 factory = create_factory_iid(&IID_IDWriteFactory4);
8546 if (!factory) {
8547 win_skip("ComputeGlyphOrigins() is not supported.\n");
8548 return;
8551 fontface = create_fontface((IDWriteFactory *)factory);
8553 for (i = 0; i < ARRAY_SIZE(origins_tests); ++i)
8555 run.fontFace = fontface;
8556 run.fontEmSize = 32.0f;
8557 run.glyphCount = 2;
8558 run.glyphIndices = glyphs;
8559 run.glyphAdvances = origins_tests[i].advances;
8560 run.glyphOffsets = origins_tests[i].offsets;
8561 run.isSideways = !!origins_tests[i].sideways;
8562 run.bidiLevel = origins_tests[i].bidi_level;
8564 get_expected_glyph_origins(origins_tests[i].baseline_origin, &run, expected_origins);
8566 memset(origins, 0, sizeof(origins));
8567 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, origins_tests[i].baseline_origin, origins);
8568 ok(hr == S_OK, "%u: failed to compute glyph origins, hr %#x.\n", i, hr);
8569 for (j = 0; j < run.glyphCount; ++j)
8571 todo_wine_if(run.isSideways)
8572 ok(!memcmp(&origins[j], &expected_origins[j], sizeof(origins[j])),
8573 "%u: unexpected origin[%u] (%f, %f) - (%f, %f).\n", i, j, origins[j].x, origins[j].y,
8574 expected_origins[j].x, expected_origins[j].y);
8578 IDWriteFontFace_Release(fontface);
8580 advances[0] = 10.0f;
8581 advances[1] = 20.0f;
8583 run.fontFace = NULL;
8584 run.fontEmSize = 16.0f;
8585 run.glyphCount = 2;
8586 run.glyphIndices = glyphs;
8587 run.glyphAdvances = advances;
8588 run.glyphOffsets = NULL;
8589 run.isSideways = FALSE;
8590 run.bidiLevel = 0;
8592 baseline_origin.x = 123.0f;
8593 baseline_origin.y = 321.0f;
8595 memset(origins, 0, sizeof(origins));
8596 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, baseline_origin, origins);
8597 ok(hr == S_OK, "got 0x%08x\n", hr);
8598 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8599 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8601 memset(origins, 0, sizeof(origins));
8602 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
8603 NULL, origins);
8604 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8605 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8607 /* transform is not applied to returned origins */
8608 m.m11 = 2.0f;
8609 m.m12 = 0.0f;
8610 m.m21 = 0.0f;
8611 m.m22 = 1.0f;
8612 m.dx = 0.0f;
8613 m.dy = 0.0f;
8615 memset(origins, 0, sizeof(origins));
8616 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
8617 &m, origins);
8618 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
8619 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
8621 ref = IDWriteFactory4_Release(factory);
8622 ok(ref == 0, "factory not released, %u\n", ref);
8625 static void test_object_lifetime(void)
8627 IDWriteFontCollection *collection, *collection2;
8628 IDWriteFontList *fontlist, *fontlist2;
8629 IDWriteGdiInterop *interop, *interop2;
8630 IDWriteFontFamily *family, *family2;
8631 IDWriteFontFace *fontface;
8632 IDWriteFont *font, *font2;
8633 IDWriteFactory *factory;
8634 HRESULT hr;
8635 ULONG ref;
8637 factory = create_factory();
8638 EXPECT_REF(factory, 1);
8640 /* system collection takes factory reference */
8641 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
8642 ok(hr == S_OK, "got %#x\n", hr);
8644 EXPECT_REF(collection, 1);
8645 EXPECT_REF(factory, 2);
8647 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection2, FALSE);
8648 ok(hr == S_OK, "got %#x\n", hr);
8649 ok(collection2 == collection, "expected same collection\n");
8651 EXPECT_REF(collection, 2);
8652 EXPECT_REF(factory, 2);
8654 IDWriteFontCollection_Release(collection2);
8656 IDWriteFontCollection_AddRef(collection);
8657 EXPECT_REF(collection, 2);
8658 EXPECT_REF(factory, 2);
8659 IDWriteFontCollection_Release(collection);
8661 EXPECT_REF(collection, 1);
8663 /* family takes collection reference */
8664 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
8665 ok(hr == S_OK, "got %#x\n", hr);
8667 EXPECT_REF(family, 1);
8668 EXPECT_REF(collection, 2);
8669 EXPECT_REF(factory, 2);
8671 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family2);
8672 ok(hr == S_OK, "got %#x\n", hr);
8674 EXPECT_REF(family2, 1);
8675 EXPECT_REF(collection, 3);
8676 EXPECT_REF(factory, 2);
8678 IDWriteFontFamily_Release(family2);
8680 EXPECT_REF(family, 1);
8681 EXPECT_REF(collection, 2);
8682 EXPECT_REF(factory, 2);
8684 /* font takes family reference */
8685 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
8686 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
8687 ok(hr == S_OK, "got %#x\n", hr);
8689 EXPECT_REF(family, 2);
8690 EXPECT_REF(collection, 2);
8691 EXPECT_REF(factory, 2);
8693 hr = IDWriteFont_GetFontFamily(font, &family2);
8694 ok(hr == S_OK, "got %#x\n", hr);
8695 ok(family2 == family, "unexpected family pointer\n");
8696 IDWriteFontFamily_Release(family2);
8698 EXPECT_REF(font, 1);
8699 EXPECT_REF(factory, 2);
8701 /* Fontface takes factory reference and nothing else. */
8702 hr = IDWriteFont_CreateFontFace(font, &fontface);
8703 ok(hr == S_OK, "got %#x\n", hr);
8705 EXPECT_REF(font, 1);
8706 EXPECT_REF_BROKEN(fontface, 1, 2);
8707 EXPECT_REF(family, 2);
8708 EXPECT_REF(collection, 2);
8709 EXPECT_REF_BROKEN(factory, 3, 2);
8711 /* get font from fontface */
8712 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
8713 ok(hr == S_OK, "got %#x\n", hr);
8715 EXPECT_REF(font, 1);
8716 EXPECT_REF(font2, 1);
8717 EXPECT_REF_BROKEN(fontface, 1, 2);
8718 EXPECT_REF(family, 2);
8719 EXPECT_REF(collection, 3);
8720 EXPECT_REF_BROKEN(factory, 3, 2);
8722 IDWriteFont_Release(font2);
8723 IDWriteFontFace_Release(fontface);
8725 EXPECT_REF(font, 1);
8726 EXPECT_REF(family, 2);
8727 EXPECT_REF(collection, 2);
8728 EXPECT_REF(factory, 2);
8730 IDWriteFont_Release(font);
8732 EXPECT_REF(family, 1);
8733 EXPECT_REF(collection, 2);
8734 EXPECT_REF(factory, 2);
8736 /* Matching fonts list takes family reference. */
8737 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
8738 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
8739 ok(hr == S_OK, "got %#x\n", hr);
8741 EXPECT_REF(family, 2);
8742 EXPECT_REF(collection, 2);
8743 EXPECT_REF(factory, 2);
8745 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
8746 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
8747 ok(hr == S_OK, "got %#x\n", hr);
8748 ok(fontlist2 != fontlist, "unexpected font list\n");
8749 IDWriteFontList_Release(fontlist2);
8751 IDWriteFontList_Release(fontlist);
8753 IDWriteFontFamily_Release(family);
8754 EXPECT_REF(collection, 1);
8756 EXPECT_REF(factory, 2);
8757 ref = IDWriteFontCollection_Release(collection);
8758 ok(ref == 0, "collection not released, %u\n", ref);
8759 EXPECT_REF(factory, 1);
8761 /* GDI interop object takes factory reference */
8762 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
8763 ok(hr == S_OK, "got %#x\n", hr);
8764 EXPECT_REF(interop, 1);
8765 EXPECT_REF(factory, 2);
8767 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
8768 ok(hr == S_OK, "got %#x\n", hr);
8769 ok(interop == interop2, "got unexpected interop pointer\n");
8771 EXPECT_REF(interop, 2);
8772 EXPECT_REF(factory, 2);
8774 IDWriteGdiInterop_Release(interop2);
8775 ref = IDWriteGdiInterop_Release(interop);
8776 ok(ref == 0, "interop not released, %u\n", ref);
8778 ref = IDWriteFactory_Release(factory);
8779 ok(ref == 0, "factory not released, %u\n", ref);
8782 struct testowner_object
8784 IUnknown IUnknown_iface;
8785 LONG ref;
8788 static inline struct testowner_object *impl_from_IUnknown(IUnknown *iface)
8790 return CONTAINING_RECORD(iface, struct testowner_object, IUnknown_iface);
8793 static HRESULT WINAPI testowner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
8795 if (IsEqualIID(riid, &IID_IUnknown)) {
8796 *obj = iface;
8797 IUnknown_AddRef(iface);
8798 return S_OK;
8801 *obj = NULL;
8802 return E_NOINTERFACE;
8805 static ULONG WINAPI testowner_AddRef(IUnknown *iface)
8807 struct testowner_object *object = impl_from_IUnknown(iface);
8808 return InterlockedIncrement(&object->ref);
8811 static ULONG WINAPI testowner_Release(IUnknown *iface)
8813 struct testowner_object *object = impl_from_IUnknown(iface);
8814 return InterlockedDecrement(&object->ref);
8817 static const IUnknownVtbl testownervtbl = {
8818 testowner_QueryInterface,
8819 testowner_AddRef,
8820 testowner_Release,
8823 static void testowner_init(struct testowner_object *object)
8825 object->IUnknown_iface.lpVtbl = &testownervtbl;
8826 object->ref = 1;
8829 static void test_inmemory_file_loader(void)
8831 IDWriteFontFileStream *stream, *stream2, *stream3;
8832 IDWriteInMemoryFontFileLoader *loader, *loader2;
8833 IDWriteInMemoryFontFileLoader *inmemory;
8834 IDWriteFontFileLoader *fileloader;
8835 struct testowner_object ownerobject;
8836 const void *key, *data, *frag_start;
8837 UINT64 file_size, size, writetime;
8838 IDWriteFontFile *file, *file2;
8839 IDWriteFontFace *fontface;
8840 void *context, *context2;
8841 IDWriteFactory5 *factory;
8842 UINT32 count, key_size;
8843 DWORD ref_key;
8844 HRESULT hr;
8845 ULONG ref;
8847 factory = create_factory_iid(&IID_IDWriteFactory5);
8848 if (!factory) {
8849 win_skip("CreateInMemoryFontFileLoader() is not supported\n");
8850 return;
8853 EXPECT_REF(factory, 1);
8854 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
8855 ok(hr == S_OK, "got %#x\n", hr);
8856 EXPECT_REF(factory, 1);
8858 testowner_init(&ownerobject);
8859 fontface = create_fontface((IDWriteFactory *)factory);
8861 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader2);
8862 ok(hr == S_OK, "got %#x\n", hr);
8863 ok(loader != loader2, "unexpected pointer\n");
8864 IDWriteInMemoryFontFileLoader_Release(loader2);
8866 inmemory = loader;
8868 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
8869 ok(!count, "Unexpected file count %u.\n", count);
8871 /* Use whole font blob to construct in-memory file. */
8872 count = 1;
8873 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
8874 ok(hr == S_OK, "got %#x\n", hr);
8876 hr = IDWriteFontFile_GetLoader(file, &fileloader);
8877 ok(hr == S_OK, "got %#x\n", hr);
8879 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
8880 ok(hr == S_OK, "got %#x\n", hr);
8882 hr = IDWriteFontFileLoader_CreateStreamFromKey(fileloader, key, key_size, &stream);
8883 ok(hr == S_OK, "got %#x\n", hr);
8884 IDWriteFontFileLoader_Release(fileloader);
8885 IDWriteFontFile_Release(file);
8887 hr = IDWriteFontFileStream_GetFileSize(stream, &file_size);
8888 ok(hr == S_OK, "got %#x\n", hr);
8890 hr = IDWriteFontFileStream_ReadFileFragment(stream, &data, 0, file_size, &context);
8891 ok(hr == S_OK, "got %#x\n", hr);
8893 /* Not registered yet. */
8894 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
8895 file_size, NULL, &file);
8896 ok(hr == E_INVALIDARG, "got %#x\n", hr);
8898 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
8899 ok(count == 1, "Unexpected file count %u.\n", count);
8901 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
8902 ok(hr == S_OK, "got %#x\n", hr);
8903 EXPECT_REF(inmemory, 2);
8905 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
8906 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
8907 file_size, &ownerobject.IUnknown_iface, &file);
8908 ok(hr == S_OK, "got %#x\n", hr);
8909 EXPECT_REF(&ownerobject.IUnknown_iface, 2);
8910 EXPECT_REF(inmemory, 3);
8912 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
8913 ok(count == 2, "Unexpected file count %u.\n", count);
8915 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
8916 file_size, &ownerobject.IUnknown_iface, &file2);
8917 ok(hr == S_OK, "got %#x\n", hr);
8918 ok(file2 != file, "got unexpected file\n");
8919 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
8920 EXPECT_REF(inmemory, 4);
8922 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
8923 ok(count == 3, "Unexpected file count %u.\n", count);
8925 /* Check in-memory reference key format. */
8926 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
8927 ok(hr == S_OK, "got %#x\n", hr);
8929 ok(key && *(DWORD*)key == 1, "got wrong ref key\n");
8930 ok(key_size == 4, "ref key size %u\n", key_size);
8932 hr = IDWriteFontFile_GetReferenceKey(file2, &key, &key_size);
8933 ok(hr == S_OK, "got %#x\n", hr);
8935 ok(key && *(DWORD*)key == 2, "got wrong ref key\n");
8936 ok(key_size == 4, "ref key size %u\n", key_size);
8938 EXPECT_REF(inmemory, 4);
8939 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream2);
8940 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
8941 EXPECT_REF(stream2, 1);
8942 EXPECT_REF(inmemory, 4);
8944 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream3);
8945 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
8947 ok(stream2 != stream3, "Unexpected stream.\n");
8949 IDWriteFontFileStream_Release(stream2);
8950 IDWriteFontFileStream_Release(stream3);
8952 /* Release file at index 1, create new one to see if index is reused. */
8953 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
8954 ref = IDWriteFontFile_Release(file);
8955 ok(ref == 0, "File object not released, %u.\n", ref);
8956 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
8958 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
8959 ok(count == 3, "Unexpected file count %u.\n", count);
8961 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
8962 ref = IDWriteFontFile_Release(file2);
8963 ok(ref == 0, "File object not released, %u.\n", ref);
8964 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
8966 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
8967 ok(count == 3, "Unexpected file count %u.\n", count);
8969 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
8970 ok(hr == S_OK, "got %#x\n", hr);
8971 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
8973 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
8974 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
8975 ok(ref == 0, "loader not released, %u.\n", ref);
8976 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
8978 /* Test reference key for first added file. */
8979 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
8980 ok(hr == S_OK, "Failed to create loader, hr %#x.\n", hr);
8982 inmemory = loader;
8984 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
8985 ok(hr == S_OK, "Failed to register loader, hr %#x.\n", hr);
8987 ref_key = 0;
8988 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
8989 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
8991 /* With owner object. */
8992 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
8993 file_size, &ownerobject.IUnknown_iface, &file);
8994 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#x.\n", hr);
8996 ref_key = 0;
8997 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
8998 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
9000 context2 = (void *)0xdeadbeef;
9001 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
9002 ok(hr == S_OK, "Failed to read a fragment, hr %#x.\n", hr);
9003 ok(context2 == NULL, "Unexpected context %p.\n", context2);
9004 ok(frag_start == data, "Unexpected fragment pointer %p.\n", frag_start);
9006 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
9007 ok(hr == S_OK, "Failed to get file size, hr %#x.\n", hr);
9008 ok(size == file_size, "Unexpected file size.\n");
9010 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
9012 writetime = 1;
9013 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
9014 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
9015 ok(writetime == 0, "Unexpected writetime.\n");
9017 IDWriteFontFileStream_Release(stream2);
9019 /* Without owner object. */
9020 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
9021 file_size, NULL, &file2);
9022 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#x.\n", hr);
9024 ref_key = 1;
9025 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
9026 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
9028 context2 = (void *)0xdeadbeef;
9029 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
9030 ok(hr == S_OK, "Failed to read a fragment, hr %#x.\n", hr);
9031 ok(context2 == NULL, "Unexpected context %p.\n", context2);
9032 ok(frag_start != data, "Unexpected fragment pointer %p.\n", frag_start);
9034 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
9035 ok(hr == S_OK, "Failed to get file size, hr %#x.\n", hr);
9036 ok(size == file_size, "Unexpected file size.\n");
9038 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
9040 writetime = 1;
9041 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
9042 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
9043 ok(writetime == 0, "Unexpected writetime.\n");
9045 IDWriteFontFileStream_Release(stream2);
9046 IDWriteFontFile_Release(file2);
9048 /* Key size validation. */
9049 ref_key = 0;
9050 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, NULL, sizeof(ref_key) - 1, &stream2);
9051 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
9053 ref_key = 0;
9054 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) - 1, &stream2);
9055 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
9057 ref_key = 0;
9058 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) + 1, &stream2);
9059 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
9061 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9062 ok(count == 2, "Unexpected file count %u.\n", count);
9064 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
9065 ok(hr == S_OK, "Failed to get reference key, hr %#x.\n", hr);
9067 ok(key && *(DWORD*)key == 0, "Unexpected reference key.\n");
9068 ok(key_size == 4, "Unexpected key size %u.\n", key_size);
9070 IDWriteFontFile_Release(file);
9072 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
9073 ok(count == 2, "Unexpected file count %u.\n", count);
9075 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
9076 ok(hr == S_OK, "Failed to unregister loader, hr %#x.\n", hr);
9078 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
9079 IDWriteFontFileStream_Release(stream);
9080 IDWriteFontFace_Release(fontface);
9082 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
9083 ok(ref == 0, "loader not released, %u.\n", ref);
9085 ref = IDWriteFactory5_Release(factory);
9086 ok(ref == 0, "factory not released, %u\n", ref);
9089 static BOOL face_has_table(IDWriteFontFace4 *fontface, UINT32 tag)
9091 BOOL exists = FALSE;
9092 const void *data;
9093 void *context;
9094 UINT32 size;
9095 HRESULT hr;
9097 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
9098 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
9099 if (exists)
9100 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9102 return exists;
9105 static DWORD get_sbix_formats(IDWriteFontFace4 *fontface)
9107 UINT32 size, s, num_strikes;
9108 const sbix_header *header;
9109 UINT16 g, num_glyphs;
9110 BOOL exists = FALSE;
9111 const maxp *maxp;
9112 const void *data;
9113 DWORD ret = 0;
9114 void *context;
9115 HRESULT hr;
9117 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
9118 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
9119 ok(exists, "Expected maxp table\n");
9121 if (!exists)
9122 return 0;
9124 maxp = data;
9125 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
9127 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists);
9128 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
9129 ok(exists, "Expected sbix table\n");
9131 header = data;
9132 num_strikes = GET_BE_DWORD(header->numStrikes);
9134 for (s = 0; s < num_strikes; s++) {
9135 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
9137 for (g = 0; g < num_glyphs; g++) {
9138 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
9139 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
9140 sbix_glyph_data *glyph_data;
9141 DWORD format;
9143 if (offset == offset_next)
9144 continue;
9146 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
9147 switch (format = glyph_data->graphicType)
9149 case MS_PNG__TAG:
9150 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
9151 break;
9152 case MS_JPG__TAG:
9153 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
9154 break;
9155 case MS_TIFF_TAG:
9156 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
9157 break;
9158 default:
9159 ok(0, "unexpected format, %#x\n", GET_BE_DWORD(format));
9164 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9166 return ret;
9169 static DWORD get_cblc_formats(IDWriteFontFace4 *fontface)
9171 CBLCBitmapSizeTable *sizes;
9172 UINT32 num_sizes, size, s;
9173 BOOL exists = FALSE;
9174 CBLCHeader *header;
9175 DWORD ret = 0;
9176 void *context;
9177 HRESULT hr;
9179 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&header, &size, &context, &exists);
9180 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
9181 ok(exists, "Expected CBLC table\n");
9183 if (!exists)
9184 return 0;
9186 num_sizes = GET_BE_DWORD(header->numSizes);
9187 sizes = (CBLCBitmapSizeTable *)(header + 1);
9189 for (s = 0; s < num_sizes; s++) {
9190 BYTE bpp = sizes[s].bitDepth;
9192 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
9193 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
9194 else if (bpp == 32)
9195 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
9198 IDWriteFontFace4_ReleaseFontTable(fontface, context);
9200 return ret;
9203 static DWORD get_face_glyph_image_formats(IDWriteFontFace4 *fontface)
9205 DWORD ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
9207 if (face_has_table(fontface, MS_GLYF_TAG))
9208 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
9210 if (face_has_table(fontface, MS_CFF__TAG) ||
9211 face_has_table(fontface, MS_CFF2_TAG))
9212 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
9214 if (face_has_table(fontface, MS_COLR_TAG))
9215 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
9217 if (face_has_table(fontface, MS_SVG__TAG))
9218 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
9220 if (face_has_table(fontface, MS_SBIX_TAG))
9221 ret |= get_sbix_formats(fontface);
9223 if (face_has_table(fontface, MS_CBLC_TAG))
9224 ret |= get_cblc_formats(fontface);
9226 return ret;
9229 static void test_GetGlyphImageFormats(void)
9231 IDWriteFontCollection *syscollection;
9232 IDWriteFactory *factory;
9233 UINT32 i, count;
9234 HRESULT hr;
9235 ULONG ref;
9236 IDWriteFontFace *fontface;
9237 IDWriteFontFace4 *fontface4;
9239 factory = create_factory();
9241 fontface = create_fontface(factory);
9242 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
9243 IDWriteFontFace_Release(fontface);
9244 if (FAILED(hr)) {
9245 win_skip("GetGlyphImageFormats() is not supported\n");
9246 IDWriteFactory_Release(factory);
9247 return;
9249 IDWriteFontFace4_Release(fontface4);
9251 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
9252 ok(hr == S_OK, "got 0x%08x\n", hr);
9253 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
9255 for (i = 0; i < count; i++) {
9256 WCHAR familynameW[256], facenameW[128];
9257 IDWriteLocalizedStrings *names;
9258 IDWriteFontFamily *family;
9259 UINT32 j, fontcount;
9260 IDWriteFont *font;
9262 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
9263 ok(hr == S_OK, "got 0x%08x\n", hr);
9265 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
9266 ok(hr == S_OK, "got 0x%08x\n", hr);
9268 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
9269 IDWriteLocalizedStrings_Release(names);
9271 fontcount = IDWriteFontFamily_GetFontCount(family);
9272 for (j = 0; j < fontcount; j++) {
9273 DWORD formats, expected_formats;
9275 hr = IDWriteFontFamily_GetFont(family, j, &font);
9276 ok(hr == S_OK, "got 0x%08x\n", hr);
9278 hr = IDWriteFont_CreateFontFace(font, &fontface);
9279 ok(hr == S_OK, "got 0x%08x\n", hr);
9281 hr = IDWriteFont_GetFaceNames(font, &names);
9282 ok(hr == S_OK, "got 0x%08x\n", hr);
9284 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
9286 IDWriteLocalizedStrings_Release(names);
9288 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
9290 /* Mask describes font as a whole. */
9291 formats = IDWriteFontFace4_GetGlyphImageFormats(fontface4);
9292 expected_formats = get_face_glyph_image_formats(fontface4);
9293 ok(formats == expected_formats, "%s - %s, expected formats %#x, got formats %#x.\n",
9294 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), expected_formats, formats);
9296 IDWriteFontFace4_Release(fontface4);
9297 IDWriteFontFace_Release(fontface);
9298 IDWriteFont_Release(font);
9301 IDWriteFontFamily_Release(family);
9304 IDWriteFontCollection_Release(syscollection);
9305 ref = IDWriteFactory_Release(factory);
9306 ok(ref == 0, "factory not released, %u\n", ref);
9309 static void test_CreateCustomRenderingParams(void)
9311 static const struct custom_params_test
9313 FLOAT gamma;
9314 FLOAT contrast;
9315 FLOAT cleartype_level;
9316 DWRITE_PIXEL_GEOMETRY geometry;
9317 DWRITE_RENDERING_MODE rendering_mode;
9318 HRESULT hr;
9319 } params_tests[] =
9321 { 0.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9322 { 0.0f, 0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9323 { 0.0f, 0.0f, 0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9324 { -0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9325 { 0.1f, -0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9326 { 0.1f, 0.0f, -0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9327 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
9328 { 0.01f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
9329 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR + 1, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
9330 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_OUTLINE + 1, E_INVALIDARG },
9331 { 0.1f, 0.0f, 2.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_NATURAL },
9333 IDWriteFactory *factory;
9334 unsigned int i;
9335 HRESULT hr;
9336 ULONG ref;
9338 factory = create_factory();
9340 for (i = 0; i < ARRAY_SIZE(params_tests); i++) {
9341 IDWriteRenderingParams *params;
9343 params = (void *)0xdeadbeef;
9344 hr = IDWriteFactory_CreateCustomRenderingParams(factory, params_tests[i].gamma, params_tests[i].contrast,
9345 params_tests[i].cleartype_level, params_tests[i].geometry, params_tests[i].rendering_mode, &params);
9346 ok(hr == params_tests[i].hr, "%u: unexpected hr %#x, expected %#x.\n", i, hr, params_tests[i].hr);
9348 if (hr == S_OK) {
9349 ok(params_tests[i].gamma == IDWriteRenderingParams_GetGamma(params), "%u: unexpected gamma %f, expected %f.\n",
9350 i, IDWriteRenderingParams_GetGamma(params), params_tests[i].gamma);
9351 ok(params_tests[i].contrast == IDWriteRenderingParams_GetEnhancedContrast(params),
9352 "%u: unexpected contrast %f, expected %f.\n",
9353 i, IDWriteRenderingParams_GetEnhancedContrast(params), params_tests[i].contrast);
9354 ok(params_tests[i].cleartype_level == IDWriteRenderingParams_GetClearTypeLevel(params),
9355 "%u: unexpected ClearType level %f, expected %f.\n",
9356 i, IDWriteRenderingParams_GetClearTypeLevel(params), params_tests[i].cleartype_level);
9357 ok(params_tests[i].geometry == IDWriteRenderingParams_GetPixelGeometry(params),
9358 "%u: unexpected pixel geometry %u, expected %u.\n", i, IDWriteRenderingParams_GetPixelGeometry(params),
9359 params_tests[i].geometry);
9360 ok(params_tests[i].rendering_mode == IDWriteRenderingParams_GetRenderingMode(params),
9361 "%u: unexpected rendering mode %u, expected %u.\n", i, IDWriteRenderingParams_GetRenderingMode(params),
9362 params_tests[i].rendering_mode);
9363 IDWriteRenderingParams_Release(params);
9365 else
9366 ok(params == NULL, "%u: expected NULL interface pointer on failure.\n", i);
9369 ref = IDWriteFactory_Release(factory);
9370 ok(ref == 0, "factory not released, %u\n", ref);
9373 static void test_localfontfileloader(void)
9375 IDWriteFontFileLoader *loader, *loader2;
9376 IDWriteFactory *factory, *factory2;
9377 IDWriteFontFile *file, *file2;
9378 WCHAR *path;
9379 HRESULT hr;
9380 ULONG ref;
9382 factory = create_factory();
9383 factory2 = create_factory();
9385 path = create_testfontfile(test_fontfile);
9387 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
9388 ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
9390 hr = IDWriteFactory_CreateFontFileReference(factory2, path, NULL, &file2);
9391 ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
9392 ok(file != file2, "Unexpected file instance.\n");
9394 hr = IDWriteFontFile_GetLoader(file, &loader);
9395 ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
9397 hr = IDWriteFontFile_GetLoader(file2, &loader2);
9398 ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
9399 ok(loader == loader2, "Unexpected loader instance\n");
9401 IDWriteFontFile_Release(file);
9402 IDWriteFontFile_Release(file2);
9403 IDWriteFontFileLoader_Release(loader);
9404 IDWriteFontFileLoader_Release(loader2);
9405 ref = IDWriteFactory_Release(factory);
9406 ok(ref == 0, "factory not released, %u\n", ref);
9407 ref = IDWriteFactory_Release(factory2);
9408 ok(ref == 0, "factory not released, %u\n", ref);
9409 DELETE_FONTFILE(path);
9412 static void test_AnalyzeContainerType(void)
9414 struct WOFFHeader2 woff2_header;
9415 struct WOFFHeader woff_header;
9416 DWRITE_CONTAINER_TYPE type;
9417 IDWriteFactory5 *factory;
9419 factory = create_factory_iid(&IID_IDWriteFactory5);
9420 if (!factory) {
9421 win_skip("AnalyzeContainerType() is not supported.\n");
9422 return;
9425 type = IDWriteFactory5_AnalyzeContainerType(factory, NULL, 0);
9426 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9428 type = IDWriteFactory5_AnalyzeContainerType(factory, (void const *)0xdeadbeef, 0);
9429 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9431 memset(&woff_header, 0xff, sizeof(woff_header));
9432 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9433 woff_header.length = 0;
9434 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header));
9435 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
9437 memset(&woff_header, 0xff, sizeof(woff_header));
9438 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9439 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature));
9440 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
9442 memset(&woff_header, 0xff, sizeof(woff_header));
9443 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
9444 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature) - 1);
9445 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9447 memset(&woff2_header, 0xff, sizeof(woff2_header));
9448 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9449 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header));
9450 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
9452 memset(&woff2_header, 0xff, sizeof(woff2_header));
9453 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9454 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature));
9455 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
9457 memset(&woff2_header, 0xff, sizeof(woff2_header));
9458 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
9459 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature) - 1);
9460 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
9462 IDWriteFactory5_Release(factory);
9465 static void test_fontsetbuilder(void)
9467 IDWriteFontFaceReference *ref, *ref2, *ref3;
9468 IDWriteFontCollection1 *collection;
9469 IDWriteFontFaceReference1 *ref1;
9470 IDWriteFontSetBuilder1 *builder1;
9471 IDWriteFontSetBuilder *builder;
9472 DWRITE_FONT_AXIS_VALUE axis_values[4];
9473 IDWriteFactory3 *factory;
9474 UINT32 count, i, refcount;
9475 IDWriteFontSet *fontset;
9476 IDWriteFontFile *file;
9477 WCHAR *path;
9478 HRESULT hr;
9480 factory = create_factory_iid(&IID_IDWriteFactory3);
9481 if (!factory)
9483 win_skip("IDWriteFontSetBuilder is not supported.\n");
9484 return;
9487 EXPECT_REF(factory, 1);
9488 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
9489 ok(hr == S_OK, "Failed to create font set builder, hr %#x.\n", hr);
9490 EXPECT_REF(factory, 2);
9492 if (SUCCEEDED(hr = IDWriteFontSetBuilder_QueryInterface(builder, &IID_IDWriteFontSetBuilder1, (void **)&builder1)))
9494 path = create_testfontfile(test_fontfile);
9496 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
9497 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9499 hr = IDWriteFontSetBuilder1_AddFontFile(builder1, file);
9500 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9502 hr = IDWriteFontSetBuilder1_CreateFontSet(builder1, &fontset);
9503 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9504 hr = IDWriteFactory3_CreateFontCollectionFromFontSet(factory, fontset, &collection);
9505 todo_wine
9506 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9507 if (SUCCEEDED(hr))
9509 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9510 ok(count == 1, "Unexpected family count %u.\n", count);
9511 IDWriteFontCollection1_Release(collection);
9513 IDWriteFontSet_Release(fontset);
9515 hr = IDWriteFontSetBuilder1_AddFontFile(builder1, file);
9516 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9518 hr = IDWriteFontSetBuilder1_CreateFontSet(builder1, &fontset);
9519 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9521 hr = IDWriteFactory3_CreateFontCollectionFromFontSet(factory, fontset, &collection);
9522 todo_wine
9523 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9524 if (SUCCEEDED(hr))
9526 check_familymodel(collection, DWRITE_FONT_FAMILY_MODEL_WEIGHT_STRETCH_STYLE);
9527 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9528 ok(count == 1, "Unexpected family count %u.\n", count);
9529 IDWriteFontCollection1_Release(collection);
9532 /* No attempt to eliminate duplicates. */
9533 count = IDWriteFontSet_GetFontCount(fontset);
9534 ok(count == 2, "Unexpected font count %u.\n", count);
9536 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref);
9537 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9539 hr = IDWriteFontFaceReference_QueryInterface(ref, &IID_IDWriteFontFaceReference1, (void **)&ref1);
9540 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9542 count = IDWriteFontFaceReference1_GetFontAxisValueCount(ref1);
9543 todo_wine
9544 ok(count == 4, "Unexpected axis count %u.\n", count);
9546 if (count == 4)
9548 hr = IDWriteFontFaceReference1_GetFontAxisValues(ref1, axis_values, ARRAY_SIZE(axis_values));
9549 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
9551 ok(axis_values[0].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT, "Unexpected tag[0] %s.\n",
9552 wine_dbgstr_an((char *)&axis_values[0].axisTag, 4));
9553 ok(axis_values[0].value == 500.0f, "Unexpected value[0] %f.\n", axis_values[0].value);
9554 ok(axis_values[1].axisTag == DWRITE_FONT_AXIS_TAG_WIDTH, "Unexpected tag[1] %s.\n",
9555 wine_dbgstr_an((char *)&axis_values[1].axisTag, 4));
9556 ok(axis_values[1].value == 100.0f, "Unexpected value[1] %f.\n", axis_values[1].value);
9557 ok(axis_values[2].axisTag == DWRITE_FONT_AXIS_TAG_ITALIC, "Unexpected tag[2] %s.\n",
9558 wine_dbgstr_an((char *)&axis_values[2].axisTag, 4));
9559 ok(axis_values[2].value == 0.0f, "Unexpected value[2] %f.\n", axis_values[2].value);
9560 ok(axis_values[3].axisTag == DWRITE_FONT_AXIS_TAG_SLANT, "Unexpected tag[3] %s.\n",
9561 wine_dbgstr_an((char *)&axis_values[3].axisTag, 4));
9562 ok(axis_values[3].value == 0.0f, "Unexpected value[3] %f.\n", axis_values[3].value);
9565 IDWriteFontFaceReference1_Release(ref1);
9567 IDWriteFontFaceReference_Release(ref);
9569 IDWriteFontSet_Release(fontset);
9571 IDWriteFontFile_Release(file);
9572 IDWriteFontSetBuilder1_Release(builder1);
9574 else
9575 win_skip("IDWriteFontSetBuilder1 is not available.\n");
9576 IDWriteFontSetBuilder_Release(builder);
9578 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
9579 ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
9580 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
9582 for (i = 0; i < count; i++) {
9583 IDWriteFontFamily1 *family;
9584 UINT32 j, fontcount;
9585 IDWriteFont3 *font;
9587 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
9588 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
9590 fontcount = IDWriteFontFamily1_GetFontCount(family);
9591 for (j = 0; j < fontcount; ++j)
9593 IDWriteFontSet *fontset;
9594 UINT32 setcount, id;
9596 hr = IDWriteFontFamily1_GetFont(family, j, &font);
9597 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
9599 /* Create a set with a single font reference, test set properties. */
9600 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
9601 ok(hr == S_OK, "Failed to create font set builder, hr %#x.\n", hr);
9603 hr = IDWriteFont3_GetFontFaceReference(font, &ref);
9604 ok(hr == S_OK, "Failed to get fontface reference, hr %#x.\n", hr);
9606 EXPECT_REF(ref, 1);
9607 hr = IDWriteFontSetBuilder_AddFontFaceReference(builder, ref);
9608 ok(hr == S_OK, "Failed to add fontface reference, hr %#x.\n", hr);
9609 EXPECT_REF(ref, 1);
9611 hr = IDWriteFontSetBuilder_CreateFontSet(builder, &fontset);
9612 ok(hr == S_OK, "Failed to create a font set, hr %#x.\n", hr);
9614 setcount = IDWriteFontSet_GetFontCount(fontset);
9615 ok(setcount == 1, "Unexpected font count %u.\n", setcount);
9617 ref2 = (void *)0xdeadbeef;
9618 hr = IDWriteFontSet_GetFontFaceReference(fontset, setcount, &ref2);
9619 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
9620 ok(!ref2, "Unexpected pointer.\n");
9622 ref2 = NULL;
9623 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref2);
9624 ok(hr == S_OK, "Failed to get font face reference, hr %#x.\n", hr);
9625 ok(ref2 != ref, "Unexpected reference.\n");
9627 ref3 = NULL;
9628 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref3);
9629 ok(hr == S_OK, "Failed to get font face reference, hr %#x.\n", hr);
9630 ok(ref2 != ref3, "Unexpected reference.\n");
9632 IDWriteFontFaceReference_Release(ref3);
9633 IDWriteFontFaceReference_Release(ref2);
9635 for (id = DWRITE_FONT_PROPERTY_ID_FAMILY_NAME; id < DWRITE_FONT_PROPERTY_ID_TOTAL; ++id)
9637 IDWriteLocalizedStrings *values;
9638 WCHAR buffW[255], buff2W[255];
9639 UINT32 c, ivalue = 0;
9640 BOOL exists = FALSE;
9642 hr = IDWriteFontSet_GetPropertyValues(fontset, 0, id, &exists, &values);
9643 ok(hr == S_OK, "Failed to get property value, hr %#x.\n", hr);
9645 if (id == DWRITE_FONT_PROPERTY_ID_WEIGHT || id == DWRITE_FONT_PROPERTY_ID_STRETCH
9646 || id == DWRITE_FONT_PROPERTY_ID_STYLE)
9648 todo_wine
9649 ok(exists, "Property %u expected to exist.\n", id);
9652 if (!exists)
9653 continue;
9655 switch (id)
9657 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
9658 ivalue = IDWriteFont3_GetWeight(font);
9659 break;
9660 case DWRITE_FONT_PROPERTY_ID_STRETCH:
9661 ivalue = IDWriteFont3_GetStretch(font);
9662 break;
9663 case DWRITE_FONT_PROPERTY_ID_STYLE:
9664 ivalue = IDWriteFont3_GetStyle(font);
9665 break;
9666 default:
9670 switch (id)
9672 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
9673 case DWRITE_FONT_PROPERTY_ID_STRETCH:
9674 case DWRITE_FONT_PROPERTY_ID_STYLE:
9675 c = IDWriteLocalizedStrings_GetCount(values);
9676 ok(c == 1, "Unexpected string count %u.\n", c);
9678 buffW[0] = 'a';
9679 hr = IDWriteLocalizedStrings_GetLocaleName(values, 0, buffW, ARRAY_SIZE(buffW));
9680 ok(hr == S_OK, "Failed to get locale name, hr %#x.\n", hr);
9681 ok(!*buffW, "Unexpected locale %s.\n", wine_dbgstr_w(buffW));
9683 buff2W[0] = 0;
9684 hr = IDWriteLocalizedStrings_GetString(values, 0, buff2W, ARRAY_SIZE(buff2W));
9685 ok(hr == S_OK, "Failed to get property string, hr %#x.\n", hr);
9687 wsprintfW(buffW, L"%u", ivalue);
9688 ok(!lstrcmpW(buffW, buff2W), "Unexpected property value %s, expected %s.\n", wine_dbgstr_w(buff2W),
9689 wine_dbgstr_w(buffW));
9690 break;
9691 default:
9695 IDWriteLocalizedStrings_Release(values);
9698 IDWriteFontSet_Release(fontset);
9699 IDWriteFontFaceReference_Release(ref);
9700 IDWriteFontSetBuilder_Release(builder);
9702 IDWriteFont3_Release(font);
9705 IDWriteFontFamily1_Release(family);
9708 IDWriteFontCollection1_Release(collection);
9710 refcount = IDWriteFactory3_Release(factory);
9711 ok(!refcount, "Factory not released, %u.\n", refcount);
9714 static void test_font_resource(void)
9716 IDWriteFontFaceReference1 *reference, *reference2;
9717 IDWriteFontResource *resource, *resource2;
9718 IDWriteFontFile *fontfile, *fontfile2;
9719 DWRITE_FONT_AXIS_VALUE axis_values[2];
9720 IDWriteFontFace5 *fontface5;
9721 IDWriteFontFace *fontface;
9722 IDWriteFactory6 *factory;
9723 UINT32 count, index;
9724 HRESULT hr;
9725 ULONG ref;
9726 BOOL ret;
9728 if (!(factory = create_factory_iid(&IID_IDWriteFactory6)))
9730 win_skip("IDWriteFactory6 is not supported.\n");
9731 return;
9734 fontface = create_fontface((IDWriteFactory *)factory);
9736 count = 1;
9737 hr = IDWriteFontFace_GetFiles(fontface, &count, &fontfile);
9738 ok(hr == S_OK, "Failed to get file object, hr %#x.\n", hr);
9740 hr = IDWriteFactory6_CreateFontResource(factory, fontfile, 0, &resource);
9741 ok(hr == S_OK, "Failed to create font resource, hr %#x.\n", hr);
9743 hr = IDWriteFactory6_CreateFontResource(factory, fontfile, 0, &resource2);
9744 ok(hr == S_OK, "Failed to create font resource, hr %#x.\n", hr);
9745 ok(resource != resource2, "Unexpected instance.\n");
9746 IDWriteFontResource_Release(resource2);
9748 hr = IDWriteFontResource_GetFontFile(resource, &fontfile2);
9749 ok(hr == S_OK, "Failed to get font file, hr %#x.\n", hr);
9750 ok(fontfile2 == fontfile, "Unexpected file instance.\n");
9751 IDWriteFontFile_Release(fontfile2);
9753 index = IDWriteFontResource_GetFontFaceIndex(resource);
9754 ok(!index, "Unexpected index %u.\n", index);
9756 /* Specify axis value, font has no variations. */
9757 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9758 axis_values[0].value = 400.0f;
9759 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 1, &reference);
9760 ok(hr == S_OK, "Failed to create reference object, hr %#x.\n", hr);
9762 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9763 ok(count == 1, "Unexpected axis value count.\n");
9765 IDWriteFontFaceReference1_Release(reference);
9767 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 1,
9768 &reference);
9769 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9770 ok(count == 1, "Unexpected axis value count.\n");
9771 IDWriteFontFaceReference1_Release(reference);
9773 EXPECT_REF(resource, 1);
9774 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0, &reference);
9775 ok(hr == S_OK, "Failed to create reference object, hr %#x.\n", hr);
9776 EXPECT_REF(resource, 1);
9778 hr = IDWriteFontResource_CreateFontFaceReference(resource, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0, &reference2);
9779 ok(hr == S_OK, "Failed to create reference object, hr %#x.\n", hr);
9780 ok(reference != reference2, "Unexpected reference instance.\n");
9781 IDWriteFontFaceReference1_Release(reference2);
9782 IDWriteFontFaceReference1_Release(reference);
9784 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace5, (void **)&fontface5);
9785 ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
9787 hr = IDWriteFontFace5_GetFontResource(fontface5, &resource2);
9788 ok(hr == S_OK, "Failed to get font resource, hr %#x.\n", hr);
9789 ok(resource != resource2, "Unexpected resource instance.\n");
9790 IDWriteFontResource_Release(resource);
9792 hr = IDWriteFontFace5_GetFontResource(fontface5, &resource);
9793 ok(hr == S_OK, "Failed to get font resource, hr %#x.\n", hr);
9794 ok(resource != resource2, "Unexpected resource instance.\n");
9795 EXPECT_REF(resource, 1);
9796 IDWriteFontResource_Release(resource);
9797 IDWriteFontResource_Release(resource2);
9799 IDWriteFontFace5_Release(fontface5);
9801 /* Reference equality regarding set axis values. */
9802 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9803 axis_values[0].value = 400.0f;
9804 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9805 axis_values[1].value = 1.0f;
9806 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9807 &reference);
9808 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference);
9809 ok(count == 2, "Unexpected axis value count.\n");
9811 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, NULL, 0,
9812 &reference2);
9813 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9814 ok(!count, "Unexpected axis value count.\n");
9816 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9817 ok(!ret, "Unexpected result.\n");
9818 IDWriteFontFaceReference1_Release(reference2);
9820 /* Different values order. */
9821 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9822 axis_values[0].value = 1.0f;
9823 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9824 axis_values[1].value = 400.0f;
9825 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9826 &reference2);
9827 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9828 ok(count == 2, "Unexpected axis value count.\n");
9830 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9831 ok(!ret, "Unexpected result.\n");
9832 IDWriteFontFaceReference1_Release(reference2);
9834 /* Different axis values. */
9835 axis_values[0].axisTag = DWRITE_FONT_AXIS_TAG_ITALIC;
9836 axis_values[0].value = 1.0f;
9837 axis_values[1].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
9838 axis_values[1].value = 401.0f;
9839 hr = IDWriteFactory6_CreateFontFaceReference(factory, fontfile, 0, DWRITE_FONT_SIMULATIONS_NONE, axis_values, 2,
9840 &reference2);
9841 count = IDWriteFontFaceReference1_GetFontAxisValueCount(reference2);
9842 ok(count == 2, "Unexpected axis value count.\n");
9844 ret = IDWriteFontFaceReference1_Equals(reference, (IDWriteFontFaceReference *)reference2);
9845 ok(!ret, "Unexpected result.\n");
9846 IDWriteFontFaceReference1_Release(reference2);
9848 memset(axis_values, 0, sizeof(axis_values));
9849 hr = IDWriteFontFaceReference1_GetFontAxisValues(reference, axis_values, 1);
9850 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
9851 ok(!axis_values[0].axisTag, "Unexpected axis tag.\n");
9853 memset(axis_values, 0, sizeof(axis_values));
9854 hr = IDWriteFontFaceReference1_GetFontAxisValues(reference, axis_values, 2);
9855 ok(hr == S_OK, "Failed to get axis values, hr %#x.\n", hr);
9856 ok(axis_values[0].axisTag == DWRITE_FONT_AXIS_TAG_WEIGHT, "Unexpected axis tag.\n");
9858 hr = IDWriteFontFaceReference1_CreateFontFace(reference, &fontface5);
9859 ok(hr == S_OK, "Failed to create a font face, hr %#x.\n", hr);
9860 IDWriteFontFace5_Release(fontface5);
9862 IDWriteFontFaceReference1_Release(reference);
9864 IDWriteFontFile_Release(fontfile);
9866 IDWriteFontFace_Release(fontface);
9867 ref = IDWriteFactory6_Release(factory);
9868 ok(ref == 0, "Factory wasn't released, %u.\n", ref);
9871 static BOOL get_expected_is_color(IDWriteFontFace2 *fontface)
9873 void *context;
9874 UINT32 size;
9875 BOOL exists;
9876 void *data;
9877 HRESULT hr;
9879 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_CPAL_TAG, (const void **)&data, &size, &context, &exists);
9880 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
9881 if (context)
9882 IDWriteFontFace2_ReleaseFontTable(fontface, context);
9884 if (exists)
9886 hr = IDWriteFontFace2_TryGetFontTable(fontface, MS_COLR_TAG, (const void **)&data, &size, &context, &exists);
9887 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
9888 if (context)
9889 IDWriteFontFace2_ReleaseFontTable(fontface, context);
9892 return exists;
9895 static void test_IsColorFont(void)
9897 IDWriteFontCollection *collection;
9898 IDWriteFactory2 *factory;
9899 UINT32 count, i;
9900 ULONG refcount;
9901 HRESULT hr;
9903 factory = create_factory_iid(&IID_IDWriteFactory2);
9905 if (!factory)
9907 win_skip("IsColorFont() is not supported.\n");
9908 return;
9911 hr = IDWriteFactory2_GetSystemFontCollection(factory, &collection, FALSE);
9912 ok(hr == S_OK, "Failed to get font collection, hr %#x.\n", hr);
9914 count = IDWriteFontCollection_GetFontFamilyCount(collection);
9915 for (i = 0; i < count; ++i)
9917 IDWriteLocalizedStrings *names;
9918 IDWriteFontFamily *family;
9919 UINT32 font_count, j;
9920 WCHAR nameW[256];
9922 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
9923 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
9925 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
9926 ok(hr == S_OK, "Failed to get names, hr %#x.\n", hr);
9927 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
9928 IDWriteLocalizedStrings_Release(names);
9930 font_count = IDWriteFontFamily_GetFontCount(family);
9932 for (j = 0; j < font_count; ++j)
9934 BOOL is_color_font, is_color_face, is_color_expected;
9935 IDWriteFontFace2 *fontface2;
9936 IDWriteFontFace *fontface;
9937 IDWriteFont2 *font2;
9938 IDWriteFont *font;
9940 hr = IDWriteFontFamily_GetFont(family, j, &font);
9941 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
9943 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont2, (void **)&font2);
9944 ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
9945 IDWriteFont_Release(font);
9947 hr = IDWriteFont2_CreateFontFace(font2, &fontface);
9948 ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
9950 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void **)&fontface2);
9951 ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
9952 IDWriteFontFace_Release(fontface);
9954 is_color_font = IDWriteFont2_IsColorFont(font2);
9955 is_color_face = IDWriteFontFace2_IsColorFont(fontface2);
9956 ok(is_color_font == is_color_face, "Unexpected color flag.\n");
9958 is_color_expected = get_expected_is_color(fontface2);
9959 ok(is_color_expected == is_color_face, "Unexpected is_color flag %d for %s, font %d.\n",
9960 is_color_face, wine_dbgstr_w(nameW), j);
9962 IDWriteFontFace2_Release(fontface2);
9963 IDWriteFont2_Release(font2);
9966 IDWriteFontFamily_Release(family);
9969 IDWriteFontCollection_Release(collection);
9970 refcount = IDWriteFactory2_Release(factory);
9971 ok(refcount == 0, "Factory not released, refcount %u.\n", refcount);
9974 static void test_GetVerticalGlyphVariants(void)
9976 UINT16 glyphs[1], glyph_variants[1];
9977 IDWriteFontFace1 *fontface1;
9978 IDWriteFontFace *fontface;
9979 IDWriteFactory *factory;
9980 unsigned int ch;
9981 ULONG refcount;
9982 HRESULT hr;
9983 BOOL ret;
9985 factory = create_factory();
9987 fontface = create_fontface(factory);
9988 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
9989 IDWriteFontFace_Release(fontface);
9990 if (FAILED(hr))
9992 win_skip("GetVerticalGlyphVariants() is not supported.\n");
9993 IDWriteFactory_Release(factory);
9994 return;
9997 ch = 'A';
9998 *glyphs = 0;
9999 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &ch, 1, glyphs);
10000 ok(hr == S_OK, "Failed to get glyph, hr %#x.\n", hr);
10001 ok(!!*glyphs, "Unexpected glyph %u.\n", glyphs[0]);
10003 memset(glyph_variants, 0, sizeof(glyph_variants));
10004 hr = IDWriteFontFace1_GetVerticalGlyphVariants(fontface1, 1, glyphs, glyph_variants);
10005 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10006 ok(glyphs[0] == glyph_variants[0], "Unexpected glyph.\n");
10008 ret = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
10009 ok(!ret, "Unexpected flag.\n");
10011 IDWriteFontFace1_Release(fontface1);
10012 refcount = IDWriteFactory_Release(factory);
10013 ok(!refcount, "Factory not released, refcount %u.\n", refcount);
10016 static HANDLE get_collection_expiration_event(IDWriteFontCollection *collection)
10018 IDWriteFontCollection3 *collection3;
10019 HANDLE event;
10020 HRESULT hr;
10022 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
10023 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10024 event = IDWriteFontCollection3_GetExpirationEvent(collection3);
10025 IDWriteFontCollection3_Release(collection3);
10027 return event;
10030 static void test_expiration_event(void)
10032 IDWriteFontCollection *collection, *collection2;
10033 IDWriteFontCollection3 *collection3;
10034 IDWriteFactory *factory, *factory2;
10035 unsigned int refcount;
10036 HANDLE event, event2;
10037 HRESULT hr;
10039 factory = create_factory();
10041 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
10042 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10044 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection3, (void **)&collection3);
10045 if (FAILED(hr))
10047 win_skip("Expiration events are not supported.\n");
10048 IDWriteFontCollection_Release(collection);
10049 IDWriteFactory_Release(factory);
10050 return;
10052 IDWriteFontCollection3_Release(collection3);
10054 event = get_collection_expiration_event(collection);
10055 todo_wine
10056 ok(!!event, "Unexpected event handle.\n");
10058 /* Compare handles with another isolated factory. */
10059 factory2 = create_factory();
10061 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection2, FALSE);
10062 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10063 event2 = get_collection_expiration_event(collection2);
10064 todo_wine {
10065 ok(!!event2, "Unexpected event handle.\n");
10066 ok(event != event2, "Unexpected event handle.\n");
10068 IDWriteFontCollection_Release(collection2);
10070 IDWriteFontCollection_Release(collection);
10072 refcount = IDWriteFactory_Release(factory2);
10073 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10074 refcount = IDWriteFactory_Release(factory);
10075 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10078 static void test_family_font_set(void)
10080 IDWriteFontCollection *collection;
10081 IDWriteFontFamily2 *family2;
10082 IDWriteFontFamily *family;
10083 IDWriteFactory *factory;
10084 unsigned int count, refcount;
10085 IDWriteFontSet1 *fontset, *fontset2;
10086 IDWriteLocalizedStrings *values;
10087 IDWriteFontResource *resource;
10088 WCHAR buffW[64];
10089 BOOL exists;
10090 HRESULT hr;
10092 factory = create_factory();
10094 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
10095 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10097 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
10098 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10100 if (SUCCEEDED(IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily2, (void **)&family2)))
10102 hr = IDWriteFontFamily2_GetFontSet(family2, &fontset);
10103 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10104 hr = IDWriteFontFamily2_GetFontSet(family2, &fontset2);
10105 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10106 ok(fontset != fontset2, "Unexpected fontset instance.\n");
10108 count = IDWriteFontSet1_GetFontCount(fontset);
10110 /* Invalid property id. */
10111 exists = TRUE;
10112 values = (void *)0xdeadbeef;
10113 hr = IDWriteFontSet1_GetPropertyValues(fontset, 0, 100, &exists, &values);
10114 ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
10115 ok(!exists && !values, "Unexpected return value.\n");
10117 /* Invalid index. */
10118 exists = TRUE;
10119 values = (void *)0xdeadbeef;
10120 hr = IDWriteFontSet1_GetPropertyValues(fontset, count, DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, &exists, &values);
10121 ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
10122 ok(!exists && !values, "Unexpected return value.\n");
10124 exists = TRUE;
10125 values = (void *)0xdeadbeef;
10126 hr = IDWriteFontSet1_GetPropertyValues(fontset, count, 100, &exists, &values);
10127 ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
10128 ok(!exists && !values, "Unexpected return value.\n");
10130 hr = IDWriteFontSet1_GetPropertyValues(fontset, 0, DWRITE_FONT_PROPERTY_ID_POSTSCRIPT_NAME, &exists, &values);
10131 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10132 ok(exists == !!values, "Unexpected return value.\n");
10133 if (values)
10135 hr = IDWriteLocalizedStrings_GetString(values, 0, buffW, ARRAY_SIZE(buffW));
10136 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10137 IDWriteLocalizedStrings_Release(values);
10140 hr = IDWriteFontSet1_CreateFontResource(fontset, 100, &resource);
10141 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
10143 hr = IDWriteFontSet1_CreateFontResource(fontset, 0, &resource);
10144 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10145 IDWriteFontResource_Release(resource);
10147 IDWriteFontSet1_Release(fontset2);
10148 IDWriteFontSet1_Release(fontset);
10150 IDWriteFontFamily2_Release(family2);
10152 else
10153 win_skip("IDWriteFontFamily2 is not supported.\n");
10155 IDWriteFontFamily_Release(family);
10156 IDWriteFontCollection_Release(collection);
10158 refcount = IDWriteFactory_Release(factory);
10159 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10162 static void test_system_font_set(void)
10164 IDWriteFontSet *fontset, *filtered_set;
10165 IDWriteFontFaceReference *ref;
10166 IDWriteFontFace3 *fontface;
10167 IDWriteFactory3 *factory;
10168 DWRITE_FONT_PROPERTY p;
10169 unsigned int count;
10170 HRESULT hr;
10172 if (!(factory = create_factory_iid(&IID_IDWriteFactory3)))
10174 win_skip("System font set is not supported.\n");
10175 return;
10178 hr = IDWriteFactory3_GetSystemFontSet(factory, &fontset);
10179 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10181 count = IDWriteFontSet_GetFontCount(fontset);
10182 ok(!!count, "Unexpected font count %u.\n", count);
10184 p.propertyId = DWRITE_FONT_PROPERTY_ID_FULL_NAME;
10185 p.propertyValue = L"Tahoma";
10186 p.localeName = L"";
10187 hr = IDWriteFontSet_GetMatchingFonts(fontset, &p, 1, &filtered_set);
10188 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10189 count = IDWriteFontSet_GetFontCount(filtered_set);
10190 ok(!!count, "Unexpected font count %u.\n", count);
10192 hr = IDWriteFontSet_GetFontFaceReference(filtered_set, 0, &ref);
10193 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10195 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
10196 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
10198 IDWriteFontFace3_Release(fontface);
10199 IDWriteFontFaceReference_Release(ref);
10201 IDWriteFontSet_Release(filtered_set);
10203 IDWriteFontSet_Release(fontset);
10205 IDWriteFactory3_Release(factory);
10208 static void test_CreateFontCollectionFromFontSet(void)
10210 unsigned int index, count, refcount;
10211 IDWriteFontCollection1 *collection;
10212 IDWriteFontSetBuilder1 *builder;
10213 DWRITE_FONT_PROPERTY props[1];
10214 IDWriteFontFaceReference *ref;
10215 IDWriteFactory5 *factory;
10216 IDWriteFontSet *fontset;
10217 IDWriteFontFile *file;
10218 WCHAR *path;
10219 BOOL exists;
10220 HRESULT hr;
10222 if (!(factory = create_factory_iid(&IID_IDWriteFactory5)))
10224 win_skip("_CreateFontCollectionFromFontSet() is not available.\n");
10225 return;
10228 hr = IDWriteFactory5_CreateFontSetBuilder(factory, &builder);
10229 ok(hr == S_OK, "Failed to create font set builder, hr %#x.\n", hr);
10231 path = create_testfontfile(test_fontfile);
10233 hr = IDWriteFactory5_CreateFontFileReference(factory, path, NULL, &file);
10234 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
10236 hr = IDWriteFontSetBuilder1_AddFontFile(builder, file);
10237 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
10239 /* Add same file, with explicit properties. */
10240 hr = IDWriteFactory5_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
10241 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
10242 props[0].propertyId = DWRITE_FONT_PROPERTY_ID_WEIGHT_STRETCH_STYLE_FAMILY_NAME;
10243 props[0].propertyValue = L"Another Font";
10244 props[0].localeName = L"en-US";
10245 hr = IDWriteFontSetBuilder1_AddFontFaceReference_(builder, ref, props, 1);
10246 todo_wine
10247 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
10248 IDWriteFontFaceReference_Release(ref);
10250 hr = IDWriteFontSetBuilder1_CreateFontSet(builder, &fontset);
10251 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
10253 hr = IDWriteFactory5_CreateFontCollectionFromFontSet(factory, fontset, &collection);
10254 todo_wine
10255 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
10257 if (SUCCEEDED(hr))
10259 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
10260 ok(count == 2, "Unexpected family count %u.\n", count);
10262 /* Explicit fontset properties are prioritized and not replaced by actual properties from a file. */
10263 exists = FALSE;
10264 hr = IDWriteFontCollection1_FindFamilyName(collection, L"Another Font", &index, &exists);
10265 ok(hr == S_OK, "Unexpected hr %#x.\n",hr);
10266 ok(!!exists, "Unexpected return value %d.\n", exists);
10268 IDWriteFontCollection1_Release(collection);
10270 IDWriteFontSet_Release(fontset);
10272 IDWriteFontSetBuilder1_Release(builder);
10274 IDWriteFontFile_Release(file);
10275 refcount = IDWriteFactory5_Release(factory);
10276 ok(!refcount, "Unexpected factory refcount %u.\n", refcount);
10277 DELETE_FONTFILE(path);
10280 START_TEST(font)
10282 IDWriteFactory *factory;
10284 if (!(factory = create_factory())) {
10285 win_skip("failed to create factory\n");
10286 return;
10289 test_object_lifetime();
10290 test_CreateFontFromLOGFONT();
10291 test_CreateBitmapRenderTarget();
10292 test_GetFontFamily();
10293 test_GetFamilyNames();
10294 test_CreateFontFace();
10295 test_GetMetrics();
10296 test_system_fontcollection();
10297 test_ConvertFontFaceToLOGFONT();
10298 test_CustomFontCollection();
10299 test_CreateCustomFontFileReference();
10300 test_CreateFontFileReference();
10301 test_shared_isolated();
10302 test_GetUnicodeRanges();
10303 test_GetFontFromFontFace();
10304 test_GetFirstMatchingFont();
10305 test_GetMatchingFonts();
10306 test_GetInformationalStrings();
10307 test_GetGdiInterop();
10308 test_CreateFontFaceFromHdc();
10309 test_GetSimulations();
10310 test_GetFaceNames();
10311 test_TryGetFontTable();
10312 test_ConvertFontToLOGFONT();
10313 test_CreateStreamFromKey();
10314 test_ReadFileFragment();
10315 test_GetDesignGlyphMetrics();
10316 test_GetDesignGlyphAdvances();
10317 test_IsMonospacedFont();
10318 test_GetGlyphRunOutline();
10319 test_GetEudcFontCollection();
10320 test_GetCaretMetrics();
10321 test_GetGlyphCount();
10322 test_GetKerningPairAdjustments();
10323 test_CreateRenderingParams();
10324 test_CreateGlyphRunAnalysis();
10325 test_GetGdiCompatibleMetrics();
10326 test_GetPanose();
10327 test_GetGdiCompatibleGlyphAdvances();
10328 test_GetRecommendedRenderingMode();
10329 test_GetAlphaBlendParams();
10330 test_CreateAlphaTexture();
10331 test_IsSymbolFont();
10332 test_GetPaletteEntries();
10333 test_TranslateColorGlyphRun();
10334 test_HasCharacter();
10335 test_CreateFontFaceReference();
10336 test_GetFontSignature();
10337 test_font_properties();
10338 test_HasVerticalGlyphVariants();
10339 test_HasKerningPairs();
10340 test_ComputeGlyphOrigins();
10341 test_inmemory_file_loader();
10342 test_GetGlyphImageFormats();
10343 test_CreateCustomRenderingParams();
10344 test_localfontfileloader();
10345 test_AnalyzeContainerType();
10346 test_fontsetbuilder();
10347 test_font_resource();
10348 test_IsColorFont();
10349 test_GetVerticalGlyphVariants();
10350 test_expiration_event();
10351 test_family_font_set();
10352 test_system_font_set();
10353 test_CreateFontCollectionFromFontSet();
10355 IDWriteFactory_Release(factory);