dwrite/tests: Use ARRAY_SIZE() macro in tests.
[wine.git] / dlls / dwrite / tests / font.c
blobdb9949faac6c1ed7baa4c6ddf4e249ddab3649af
1 /*
2 * Font related tests
4 * Copyright 2012, 2014-2017 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 ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
38 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
39 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
40 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
41 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
42 #define MS_0S2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
43 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
44 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
45 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
46 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
47 #define MS_KERN_TAG DWRITE_MAKE_OPENTYPE_TAG('k','e','r','n')
48 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
49 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
50 #define MS_CFF2_TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F','2')
51 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
52 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
53 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
54 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
55 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
57 /* 'sbix' formats */
58 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
59 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
60 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
62 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
63 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
65 #ifdef WORDS_BIGENDIAN
66 #define GET_BE_WORD(x) (x)
67 #define GET_BE_DWORD(x) (x)
68 #define GET_LE_WORD(x) RtlUshortByteSwap(x)
69 #define GET_LE_DWORD(x) RtlUlongByteSwap(x)
70 #else
71 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
72 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
73 #define GET_LE_WORD(x) (x)
74 #define GET_LE_DWORD(x) (x)
75 #endif
77 #define EXPECT_HR(hr,hr_exp) \
78 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
80 #define DEFINE_EXPECT(func) \
81 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
83 #define SET_EXPECT(func) \
84 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
86 #define CHECK_EXPECT2(func) \
87 do { \
88 ok(expect_ ##func, "unexpected call " #func "\n"); \
89 called_ ## func = TRUE; \
90 }while(0)
92 #define CHECK_EXPECT(func) \
93 do { \
94 CHECK_EXPECT2(func); \
95 expect_ ## func = FALSE; \
96 }while(0)
98 #define CHECK_CALLED(func) \
99 do { \
100 ok(called_ ## func, "expected " #func "\n"); \
101 expect_ ## func = called_ ## func = FALSE; \
102 }while(0)
104 #define CLEAR_CALLED(func) \
105 expect_ ## func = called_ ## func = FALSE
107 DEFINE_EXPECT(setfillmode);
109 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
110 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
112 ULONG rc;
113 IUnknown_AddRef(obj);
114 rc = IUnknown_Release(obj);
115 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
118 #define EXPECT_REF_BROKEN(obj,ref,brokenref) _expect_ref_broken((IUnknown*)obj, ref, brokenref, __LINE__)
119 static void _expect_ref_broken(IUnknown* obj, ULONG ref, ULONG brokenref, int line)
121 ULONG rc;
122 IUnknown_AddRef(obj);
123 rc = IUnknown_Release(obj);
124 ok_(__FILE__,line)(rc == ref || broken(rc == brokenref), "expected refcount %d, got %d\n", ref, rc);
127 static const WCHAR test_fontfile[] = {'w','i','n','e','_','t','e','s','t','_','f','o','n','t','.','t','t','f',0};
128 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
129 static const WCHAR arialW[] = {'A','r','i','a','l',0};
130 static const WCHAR tahomaUppercaseW[] = {'T','A','H','O','M','A',0};
131 static const WCHAR tahomaStrangecaseW[] = {'t','A','h','O','m','A',0};
132 static const WCHAR blahW[] = {'B','l','a','h','!',0};
133 static const WCHAR emojiW[] = {'S','e','g','o','e',' ','U','I',' ','E','m','o','j','i',0};
135 /* PANOSE is 10 bytes in size, need to pack the structure properly */
136 #include "pshpack2.h"
137 typedef struct
139 USHORT majorVersion;
140 USHORT minorVersion;
141 ULONG revision;
142 ULONG checksumadj;
143 ULONG magic;
144 USHORT flags;
145 USHORT unitsPerEm;
146 ULONGLONG created;
147 ULONGLONG modified;
148 SHORT xMin;
149 SHORT yMin;
150 SHORT xMax;
151 SHORT yMax;
152 USHORT macStyle;
153 USHORT lowestRecPPEM;
154 SHORT direction_hint;
155 SHORT index_format;
156 SHORT glyphdata_format;
157 } TT_HEAD;
159 enum TT_HEAD_MACSTYLE
161 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
162 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
163 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
164 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
165 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
166 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
167 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
170 typedef struct
172 USHORT version;
173 SHORT xAvgCharWidth;
174 USHORT usWeightClass;
175 USHORT usWidthClass;
176 SHORT fsType;
177 SHORT ySubscriptXSize;
178 SHORT ySubscriptYSize;
179 SHORT ySubscriptXOffset;
180 SHORT ySubscriptYOffset;
181 SHORT ySuperscriptXSize;
182 SHORT ySuperscriptYSize;
183 SHORT ySuperscriptXOffset;
184 SHORT ySuperscriptYOffset;
185 SHORT yStrikeoutSize;
186 SHORT yStrikeoutPosition;
187 SHORT sFamilyClass;
188 PANOSE panose;
189 ULONG ulUnicodeRange1;
190 ULONG ulUnicodeRange2;
191 ULONG ulUnicodeRange3;
192 ULONG ulUnicodeRange4;
193 CHAR achVendID[4];
194 USHORT fsSelection;
195 USHORT usFirstCharIndex;
196 USHORT usLastCharIndex;
197 /* According to the Apple spec, original version didn't have the below fields,
198 * version numbers were taken from the OpenType spec.
200 /* version 0 (TrueType 1.5) */
201 USHORT sTypoAscender;
202 USHORT sTypoDescender;
203 USHORT sTypoLineGap;
204 USHORT usWinAscent;
205 USHORT usWinDescent;
206 /* version 1 (TrueType 1.66) */
207 ULONG ulCodePageRange1;
208 ULONG ulCodePageRange2;
209 /* version 2 (OpenType 1.2) */
210 SHORT sxHeight;
211 SHORT sCapHeight;
212 USHORT usDefaultChar;
213 USHORT usBreakChar;
214 USHORT usMaxContext;
215 } TT_OS2_V2;
217 enum OS2_FSSELECTION {
218 OS2_FSSELECTION_ITALIC = 1 << 0,
219 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
220 OS2_FSSELECTION_NEGATIVE = 1 << 2,
221 OS2_FSSELECTION_OUTLINED = 1 << 3,
222 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
223 OS2_FSSELECTION_BOLD = 1 << 5,
224 OS2_FSSELECTION_REGULAR = 1 << 6,
225 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
226 OS2_FSSELECTION_WWS = 1 << 8,
227 OS2_FSSELECTION_OBLIQUE = 1 << 9
230 typedef struct {
231 ULONG Version;
232 ULONG italicAngle;
233 SHORT underlinePosition;
234 SHORT underlineThickness;
235 ULONG fixed_pitch;
236 ULONG minmemType42;
237 ULONG maxmemType42;
238 ULONG minmemType1;
239 ULONG maxmemType1;
240 } TT_POST;
242 typedef struct {
243 USHORT majorVersion;
244 USHORT minorVersion;
245 SHORT ascender;
246 SHORT descender;
247 SHORT linegap;
248 USHORT advanceWidthMax;
249 SHORT minLeftSideBearing;
250 SHORT minRightSideBearing;
251 SHORT xMaxExtent;
252 SHORT caretSlopeRise;
253 SHORT caretSlopeRun;
254 SHORT caretOffset;
255 SHORT reserved[4];
256 SHORT metricDataFormat;
257 USHORT numberOfHMetrics;
258 } TT_HHEA;
260 typedef struct {
261 DWORD version;
262 WORD ScriptList;
263 WORD FeatureList;
264 WORD LookupList;
265 } GSUB_Header;
267 typedef struct {
268 CHAR FeatureTag[4];
269 WORD Feature;
270 } OT_FeatureRecord;
272 typedef struct {
273 WORD FeatureCount;
274 OT_FeatureRecord FeatureRecord[1];
275 } OT_FeatureList;
277 typedef struct {
278 WORD FeatureParams;
279 WORD LookupCount;
280 WORD LookupListIndex[1];
281 } OT_Feature;
283 typedef struct {
284 WORD LookupCount;
285 WORD Lookup[1];
286 } OT_LookupList;
288 typedef struct {
289 WORD LookupType;
290 WORD LookupFlag;
291 WORD SubTableCount;
292 WORD SubTable[1];
293 } OT_LookupTable;
295 typedef struct {
296 WORD SubstFormat;
297 WORD Coverage;
298 WORD DeltaGlyphID;
299 } GSUB_SingleSubstFormat1;
301 typedef struct {
302 WORD SubstFormat;
303 WORD Coverage;
304 WORD GlyphCount;
305 WORD Substitute[1];
306 } GSUB_SingleSubstFormat2;
308 typedef struct {
309 WORD SubstFormat;
310 WORD ExtensionLookupType;
311 DWORD ExtensionOffset;
312 } GSUB_ExtensionPosFormat1;
314 typedef struct {
315 WORD version;
316 WORD flags;
317 DWORD numStrikes;
318 DWORD strikeOffset[1];
319 } sbix_header;
321 typedef struct {
322 WORD ppem;
323 WORD ppi;
324 DWORD glyphDataOffsets[1];
325 } sbix_strike;
327 typedef struct {
328 WORD originOffsetX;
329 WORD originOffsetY;
330 DWORD graphicType;
331 BYTE data[1];
332 } sbix_glyph_data;
334 typedef struct {
335 WORD majorVersion;
336 WORD minorVersion;
337 DWORD numSizes;
338 } CBLCHeader;
340 typedef struct {
341 BYTE res[12];
342 } sbitLineMetrics;
344 typedef struct {
345 DWORD indexSubTableArrayOffset;
346 DWORD indexTablesSize;
347 DWORD numberofIndexSubTables;
348 DWORD colorRef;
349 sbitLineMetrics hori;
350 sbitLineMetrics vert;
351 WORD startGlyphIndex;
352 WORD endGlyphIndex;
353 BYTE ppemX;
354 BYTE ppemY;
355 BYTE bitDepth;
356 BYTE flags;
357 } CBLCBitmapSizeTable;
359 typedef struct {
360 DWORD version;
361 WORD numGlyphs;
362 } maxp;
364 struct WOFFHeader
366 ULONG signature;
367 ULONG flavor;
368 ULONG length;
369 USHORT numTables;
370 USHORT reserved;
371 ULONG totalSfntSize;
372 USHORT majorVersion;
373 USHORT minorVersion;
374 ULONG metaOffset;
375 ULONG metaLength;
376 ULONG metaOrigLength;
377 ULONG privOffset;
378 ULONG privLength;
381 struct WOFFHeader2
383 ULONG signature;
384 ULONG flavor;
385 ULONG length;
386 USHORT numTables;
387 USHORT reserved;
388 ULONG totalSfntSize;
389 ULONG totalCompressedSize;
390 USHORT majorVersion;
391 USHORT minorVersion;
392 ULONG metaOffset;
393 ULONG metaLength;
394 ULONG metaOrigLength;
395 ULONG privOffset;
396 ULONG privLength;
399 #include "poppack.h"
401 static void *create_factory_iid(REFIID riid)
403 IUnknown *factory = NULL;
404 DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, riid, &factory);
405 return factory;
408 static IDWriteFactory *create_factory(void)
410 IDWriteFactory *factory = create_factory_iid(&IID_IDWriteFactory);
411 ok(factory != NULL, "Failed to create factory.\n");
412 return factory;
415 static IDWriteFontFace *create_fontface(IDWriteFactory *factory)
417 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
418 IDWriteGdiInterop *interop;
419 IDWriteFontFace *fontface;
420 IDWriteFont *font;
421 LOGFONTW logfont;
422 HRESULT hr;
424 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
425 ok(hr == S_OK, "got 0x%08x\n", hr);
427 memset(&logfont, 0, sizeof(logfont));
428 logfont.lfHeight = 12;
429 logfont.lfWidth = 12;
430 logfont.lfWeight = FW_NORMAL;
431 logfont.lfItalic = 1;
432 lstrcpyW(logfont.lfFaceName, tahomaW);
434 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
435 ok(hr == S_OK, "got 0x%08x\n", hr);
437 hr = IDWriteFont_CreateFontFace(font, &fontface);
438 ok(hr == S_OK, "got 0x%08x\n", hr);
440 IDWriteFont_Release(font);
441 IDWriteGdiInterop_Release(interop);
443 return fontface;
446 static IDWriteFont *get_font(IDWriteFactory *factory, const WCHAR *name, DWRITE_FONT_STYLE style)
448 IDWriteFontCollection *collection;
449 IDWriteFontFamily *family;
450 IDWriteFont *font = NULL;
451 UINT32 index;
452 BOOL exists;
453 HRESULT hr;
455 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
456 ok(hr == S_OK, "got 0x%08x\n", hr);
458 index = ~0;
459 exists = FALSE;
460 hr = IDWriteFontCollection_FindFamilyName(collection, name, &index, &exists);
461 ok(hr == S_OK, "got 0x%08x\n", hr);
462 if (!exists) goto not_found;
464 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
465 ok(hr == S_OK, "got 0x%08x\n", hr);
467 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
468 DWRITE_FONT_STRETCH_NORMAL, style, &font);
469 ok(hr == S_OK, "got 0x%08x\n", hr);
471 IDWriteFontFamily_Release(family);
472 not_found:
473 IDWriteFontCollection_Release(collection);
474 return font;
477 static IDWriteFont *get_tahoma_instance(IDWriteFactory *factory, DWRITE_FONT_STYLE style)
479 IDWriteFont *font = get_font(factory, tahomaW, style);
480 ok(font != NULL, "failed to get Tahoma\n");
481 return font;
484 static WCHAR *create_testfontfile(const WCHAR *filename)
486 static WCHAR pathW[MAX_PATH];
487 DWORD written;
488 HANDLE file;
489 HRSRC res;
490 void *ptr;
492 GetTempPathW(ARRAY_SIZE(pathW), pathW);
493 lstrcatW(pathW, filename);
495 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
496 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW),
497 GetLastError());
499 res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
500 ok( res != 0, "couldn't find resource\n" );
501 ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
502 WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
503 ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
504 CloseHandle( file );
506 return pathW;
509 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
510 static void _delete_testfontfile(const WCHAR *filename, int line)
512 BOOL ret = DeleteFileW(filename);
513 ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError());
516 struct test_fontenumerator
518 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
519 LONG ref;
521 DWORD index;
522 IDWriteFontFile *font_file;
525 static inline struct test_fontenumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
527 return CONTAINING_RECORD(iface, struct test_fontenumerator, IDWriteFontFileEnumerator_iface);
530 static HRESULT WINAPI singlefontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
532 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
534 *obj = iface;
535 IDWriteFontFileEnumerator_AddRef(iface);
536 return S_OK;
538 return E_NOINTERFACE;
541 static ULONG WINAPI singlefontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
543 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
544 return InterlockedIncrement(&This->ref);
547 static ULONG WINAPI singlefontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
549 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
550 ULONG ref = InterlockedDecrement(&This->ref);
551 if (!ref) {
552 IDWriteFontFile_Release(This->font_file);
553 heap_free(This);
555 return ref;
558 static HRESULT WINAPI singlefontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **font_file)
560 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
561 IDWriteFontFile_AddRef(This->font_file);
562 *font_file = This->font_file;
563 return S_OK;
566 static HRESULT WINAPI singlefontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
568 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
570 if (This->index > 1) {
571 *current = FALSE;
572 return S_OK;
575 This->index++;
576 *current = TRUE;
577 return S_OK;
580 static const struct IDWriteFontFileEnumeratorVtbl singlefontfileenumeratorvtbl =
582 singlefontfileenumerator_QueryInterface,
583 singlefontfileenumerator_AddRef,
584 singlefontfileenumerator_Release,
585 singlefontfileenumerator_MoveNext,
586 singlefontfileenumerator_GetCurrentFontFile
589 static HRESULT create_enumerator(IDWriteFontFile *font_file, IDWriteFontFileEnumerator **ret)
591 struct test_fontenumerator *enumerator;
593 enumerator = heap_alloc(sizeof(struct test_fontenumerator));
594 if (!enumerator)
595 return E_OUTOFMEMORY;
597 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &singlefontfileenumeratorvtbl;
598 enumerator->ref = 1;
599 enumerator->index = 0;
600 enumerator->font_file = font_file;
601 IDWriteFontFile_AddRef(font_file);
603 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
604 return S_OK;
607 struct test_fontcollectionloader
609 IDWriteFontCollectionLoader IDWriteFontFileCollectionLoader_iface;
610 IDWriteFontFileLoader *loader;
613 static inline struct test_fontcollectionloader *impl_from_IDWriteFontFileCollectionLoader(IDWriteFontCollectionLoader* iface)
615 return CONTAINING_RECORD(iface, struct test_fontcollectionloader, IDWriteFontFileCollectionLoader_iface);
618 static HRESULT WINAPI resourcecollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
620 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontCollectionLoader))
622 *obj = iface;
623 IDWriteFontCollectionLoader_AddRef(iface);
624 return S_OK;
626 return E_NOINTERFACE;
629 static ULONG WINAPI resourcecollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
631 return 2;
634 static ULONG WINAPI resourcecollectionloader_Release(IDWriteFontCollectionLoader *iface)
636 return 1;
639 static HRESULT WINAPI resourcecollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory,
640 const void * collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator ** fontFileEnumerator)
642 struct test_fontcollectionloader *This = impl_from_IDWriteFontFileCollectionLoader(iface);
643 IDWriteFontFile *font_file;
644 HRESULT hr;
646 hr = IDWriteFactory_CreateCustomFontFileReference(factory, collectionKey, collectionKeySize, This->loader, &font_file);
647 ok(hr == S_OK, "Failed to create custom file reference, hr %#x.\n", hr);
649 hr = create_enumerator(font_file, fontFileEnumerator);
650 ok(hr == S_OK, "got 0x%08x\n", hr);
652 IDWriteFontFile_Release(font_file);
653 return hr;
656 static const struct IDWriteFontCollectionLoaderVtbl resourcecollectionloadervtbl = {
657 resourcecollectionloader_QueryInterface,
658 resourcecollectionloader_AddRef,
659 resourcecollectionloader_Release,
660 resourcecollectionloader_CreateEnumeratorFromKey
663 /* Here is a functional custom font set of interfaces */
664 struct test_fontdatastream
666 IDWriteFontFileStream IDWriteFontFileStream_iface;
667 LONG ref;
669 LPVOID data;
670 DWORD size;
673 static inline struct test_fontdatastream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream* iface)
675 return CONTAINING_RECORD(iface, struct test_fontdatastream, IDWriteFontFileStream_iface);
678 static HRESULT WINAPI fontdatastream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
680 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
682 *obj = iface;
683 IDWriteFontFileStream_AddRef(iface);
684 return S_OK;
686 *obj = NULL;
687 return E_NOINTERFACE;
690 static ULONG WINAPI fontdatastream_AddRef(IDWriteFontFileStream *iface)
692 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
693 ULONG ref = InterlockedIncrement(&This->ref);
694 return ref;
697 static ULONG WINAPI fontdatastream_Release(IDWriteFontFileStream *iface)
699 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
700 ULONG ref = InterlockedDecrement(&This->ref);
701 if (ref == 0)
702 HeapFree(GetProcessHeap(), 0, This);
703 return ref;
706 static HRESULT WINAPI fontdatastream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
708 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
709 *fragment_context = NULL;
710 if (offset+fragment_size > This->size)
712 *fragment_start = NULL;
713 return E_FAIL;
715 else
717 *fragment_start = (BYTE*)This->data + offset;
718 return S_OK;
722 static void WINAPI fontdatastream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
724 /* Do Nothing */
727 static HRESULT WINAPI fontdatastream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
729 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
730 *size = This->size;
731 return S_OK;
734 static HRESULT WINAPI fontdatastream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
736 return E_NOTIMPL;
739 static const IDWriteFontFileStreamVtbl fontdatastreamvtbl =
741 fontdatastream_QueryInterface,
742 fontdatastream_AddRef,
743 fontdatastream_Release,
744 fontdatastream_ReadFileFragment,
745 fontdatastream_ReleaseFileFragment,
746 fontdatastream_GetFileSize,
747 fontdatastream_GetLastWriteTime
750 static HRESULT create_fontdatastream(LPVOID data, UINT size, IDWriteFontFileStream** iface)
752 struct test_fontdatastream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct test_fontdatastream));
753 if (!This)
754 return E_OUTOFMEMORY;
756 This->data = data;
757 This->size = size;
758 This->ref = 1;
759 This->IDWriteFontFileStream_iface.lpVtbl = &fontdatastreamvtbl;
761 *iface = &This->IDWriteFontFileStream_iface;
762 return S_OK;
765 static HRESULT WINAPI resourcefontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
767 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
769 *obj = iface;
770 return S_OK;
772 *obj = NULL;
773 return E_NOINTERFACE;
776 static ULONG WINAPI resourcefontfileloader_AddRef(IDWriteFontFileLoader *iface)
778 return 2;
781 static ULONG WINAPI resourcefontfileloader_Release(IDWriteFontFileLoader *iface)
783 return 1;
786 static HRESULT WINAPI resourcefontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
787 IDWriteFontFileStream **stream)
789 LPVOID data;
790 DWORD size;
791 HGLOBAL mem;
793 mem = LoadResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
794 ok(mem != NULL, "Failed to lock font resource\n");
795 if (mem)
797 size = SizeofResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
798 data = LockResource(mem);
799 return create_fontdatastream(data, size, stream);
801 return E_FAIL;
804 static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = {
805 resourcefontfileloader_QueryInterface,
806 resourcefontfileloader_AddRef,
807 resourcefontfileloader_Release,
808 resourcefontfileloader_CreateStreamFromKey
811 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
813 static D2D1_POINT_2F g_startpoints[2];
814 static int g_startpoint_count;
816 static HRESULT WINAPI test_geometrysink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **ret)
818 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
819 IsEqualIID(riid, &IID_IUnknown))
821 *ret = iface;
822 ID2D1SimplifiedGeometrySink_AddRef(iface);
823 return S_OK;
826 *ret = NULL;
827 return E_NOINTERFACE;
830 static ULONG WINAPI test_geometrysink_AddRef(ID2D1SimplifiedGeometrySink *iface)
832 return 2;
835 static ULONG WINAPI test_geometrysink_Release(ID2D1SimplifiedGeometrySink *iface)
837 return 1;
840 static void WINAPI test_geometrysink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
842 CHECK_EXPECT(setfillmode);
843 ok(mode == D2D1_FILL_MODE_WINDING, "fill mode %d\n", mode);
846 static void WINAPI test_geometrysink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT flags)
848 ok(0, "unexpected SetSegmentFlags() - flags %d\n", flags);
851 static void WINAPI test_geometrysink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
852 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
854 ok(figureBegin == D2D1_FIGURE_BEGIN_FILLED, "begin figure %d\n", figureBegin);
855 if (g_startpoint_count < ARRAY_SIZE(g_startpoints))
856 g_startpoints[g_startpoint_count] = startPoint;
857 g_startpoint_count++;
860 static void WINAPI test_geometrysink_AddLines(ID2D1SimplifiedGeometrySink *iface,
861 const D2D1_POINT_2F *points, UINT32 count)
865 static void WINAPI test_geometrysink_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
866 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
870 static void WINAPI test_geometrysink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
872 ok(figureEnd == D2D1_FIGURE_END_CLOSED, "end figure %d\n", figureEnd);
875 static HRESULT WINAPI test_geometrysink_Close(ID2D1SimplifiedGeometrySink *iface)
877 ok(0, "unexpected Close()\n");
878 return E_NOTIMPL;
881 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink_vtbl = {
882 test_geometrysink_QueryInterface,
883 test_geometrysink_AddRef,
884 test_geometrysink_Release,
885 test_geometrysink_SetFillMode,
886 test_geometrysink_SetSegmentFlags,
887 test_geometrysink_BeginFigure,
888 test_geometrysink_AddLines,
889 test_geometrysink_AddBeziers,
890 test_geometrysink_EndFigure,
891 test_geometrysink_Close
894 static void WINAPI test_geometrysink2_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
895 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
897 ok(0, "unexpected call\n");
900 static void WINAPI test_geometrysink2_AddLines(ID2D1SimplifiedGeometrySink *iface,
901 const D2D1_POINT_2F *points, UINT32 count)
903 ok(0, "unexpected call\n");
906 static void WINAPI test_geometrysink2_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
907 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
909 ok(0, "unexpected call\n");
912 static void WINAPI test_geometrysink2_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
914 ok(0, "unexpected call\n");
917 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink2_vtbl = {
918 test_geometrysink_QueryInterface,
919 test_geometrysink_AddRef,
920 test_geometrysink_Release,
921 test_geometrysink_SetFillMode,
922 test_geometrysink_SetSegmentFlags,
923 test_geometrysink2_BeginFigure,
924 test_geometrysink2_AddLines,
925 test_geometrysink2_AddBeziers,
926 test_geometrysink2_EndFigure,
927 test_geometrysink_Close
930 static ID2D1SimplifiedGeometrySink test_geomsink = { &test_geometrysink_vtbl };
931 static ID2D1SimplifiedGeometrySink test_geomsink2 = { &test_geometrysink2_vtbl };
933 static void test_CreateFontFromLOGFONT(void)
935 static const WCHAR tahomaspW[] = {'T','a','h','o','m','a',' ',0};
936 IDWriteGdiInterop1 *interop1;
937 IDWriteGdiInterop *interop;
938 DWRITE_FONT_WEIGHT weight;
939 DWRITE_FONT_STYLE style;
940 IDWriteFont *font;
941 LOGFONTW logfont;
942 LONG weights[][2] = {
943 {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
944 {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
945 { 0, DWRITE_FONT_WEIGHT_NORMAL},
946 { 50, DWRITE_FONT_WEIGHT_NORMAL},
947 {150, DWRITE_FONT_WEIGHT_NORMAL},
948 {250, DWRITE_FONT_WEIGHT_NORMAL},
949 {350, DWRITE_FONT_WEIGHT_NORMAL},
950 {450, DWRITE_FONT_WEIGHT_NORMAL},
951 {650, DWRITE_FONT_WEIGHT_BOLD},
952 {750, DWRITE_FONT_WEIGHT_BOLD},
953 {850, DWRITE_FONT_WEIGHT_BOLD},
954 {950, DWRITE_FONT_WEIGHT_BOLD},
955 {960, DWRITE_FONT_WEIGHT_BOLD},
957 OUTLINETEXTMETRICW otm;
958 IDWriteFactory *factory;
959 HRESULT hr;
960 BOOL ret;
961 HDC hdc;
962 HFONT hfont;
963 BOOL exists;
964 ULONG ref;
965 int i;
966 UINT r;
968 factory = create_factory();
970 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
971 ok(hr == S_OK, "got %#x\n", hr);
973 if (0)
974 /* null out parameter crashes this call */
975 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
977 font = (void*)0xdeadbeef;
978 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
979 EXPECT_HR(hr, E_INVALIDARG);
980 ok(font == NULL, "got %p\n", font);
982 memset(&logfont, 0, sizeof(logfont));
983 logfont.lfHeight = 12;
984 logfont.lfWidth = 12;
985 logfont.lfWeight = FW_NORMAL;
986 logfont.lfItalic = 1;
987 lstrcpyW(logfont.lfFaceName, tahomaW);
989 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
990 EXPECT_HR(hr, S_OK);
992 hfont = CreateFontIndirectW(&logfont);
993 hdc = CreateCompatibleDC(0);
994 SelectObject(hdc, hfont);
996 otm.otmSize = sizeof(otm);
997 r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
998 ok(r, "got %d\n", r);
999 DeleteDC(hdc);
1000 DeleteObject(hfont);
1002 exists = TRUE;
1003 hr = IDWriteFont_HasCharacter(font, 0xd800, &exists);
1004 ok(hr == S_OK, "got 0x%08x\n", hr);
1005 ok(exists == FALSE, "got %d\n", exists);
1007 exists = FALSE;
1008 hr = IDWriteFont_HasCharacter(font, 0x20, &exists);
1009 ok(hr == S_OK, "got 0x%08x\n", hr);
1010 ok(exists == TRUE, "got %d\n", exists);
1012 /* now check properties */
1013 weight = IDWriteFont_GetWeight(font);
1014 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1016 style = IDWriteFont_GetStyle(font);
1017 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1018 ok(otm.otmfsSelection & 1, "got 0x%08x\n", otm.otmfsSelection);
1020 ret = IDWriteFont_IsSymbolFont(font);
1021 ok(!ret, "got %d\n", ret);
1023 IDWriteFont_Release(font);
1025 /* weight values */
1026 for (i = 0; i < ARRAY_SIZE(weights); i++)
1028 memset(&logfont, 0, sizeof(logfont));
1029 logfont.lfHeight = 12;
1030 logfont.lfWidth = 12;
1031 logfont.lfWeight = weights[i][0];
1032 lstrcpyW(logfont.lfFaceName, tahomaW);
1034 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1035 EXPECT_HR(hr, S_OK);
1037 weight = IDWriteFont_GetWeight(font);
1038 ok(weight == weights[i][1],
1039 "%d: got %d, expected %d\n", i, weight, weights[i][1]);
1041 IDWriteFont_Release(font);
1044 /* weight not from enum */
1045 memset(&logfont, 0, sizeof(logfont));
1046 logfont.lfHeight = 12;
1047 logfont.lfWidth = 12;
1048 logfont.lfWeight = 550;
1049 lstrcpyW(logfont.lfFaceName, tahomaW);
1051 font = NULL;
1052 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1053 ok(hr == S_OK, "got 0x%08x\n", hr);
1055 weight = IDWriteFont_GetWeight(font);
1056 ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
1057 "got %d\n", weight);
1059 IDWriteFont_Release(font);
1061 /* empty or nonexistent face name */
1062 memset(&logfont, 0, sizeof(logfont));
1063 logfont.lfHeight = 12;
1064 logfont.lfWidth = 12;
1065 logfont.lfWeight = FW_NORMAL;
1066 lstrcpyW(logfont.lfFaceName, blahW);
1068 font = (void*)0xdeadbeef;
1069 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1070 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1071 ok(font == NULL, "got %p\n", font);
1073 /* Try with name 'Tahoma ' */
1074 memset(&logfont, 0, sizeof(logfont));
1075 logfont.lfHeight = 12;
1076 logfont.lfWidth = 12;
1077 logfont.lfWeight = FW_NORMAL;
1078 lstrcpyW(logfont.lfFaceName, tahomaspW);
1080 font = (void*)0xdeadbeef;
1081 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1082 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1083 ok(font == NULL, "got %p\n", font);
1085 /* empty string as a facename */
1086 memset(&logfont, 0, sizeof(logfont));
1087 logfont.lfHeight = 12;
1088 logfont.lfWidth = 12;
1089 logfont.lfWeight = FW_NORMAL;
1091 font = (void*)0xdeadbeef;
1092 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1093 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1094 ok(font == NULL, "got %p\n", font);
1096 /* IDWriteGdiInterop1::CreateFontFromLOGFONT() */
1097 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
1098 if (hr == S_OK) {
1099 memset(&logfont, 0, sizeof(logfont));
1100 logfont.lfHeight = 12;
1101 logfont.lfWidth = 12;
1102 logfont.lfWeight = FW_NORMAL;
1103 logfont.lfItalic = 1;
1104 lstrcpyW(logfont.lfFaceName, tahomaW);
1106 hr = IDWriteGdiInterop1_CreateFontFromLOGFONT(interop1, &logfont, NULL, &font);
1107 ok(hr == S_OK, "got 0x%08x\n", hr);
1109 IDWriteFont_Release(font);
1110 IDWriteGdiInterop1_Release(interop1);
1112 else
1113 win_skip("IDWriteGdiInterop1 is not supported, skipping CreateFontFromLOGFONT() tests.\n");
1115 ref = IDWriteGdiInterop_Release(interop);
1116 ok(ref == 0, "interop is not released, %u\n", ref);
1117 ref = IDWriteFactory_Release(factory);
1118 ok(ref == 0, "factory is not released, %u\n", ref);
1121 static void test_CreateBitmapRenderTarget(void)
1123 IDWriteBitmapRenderTarget *target, *target2;
1124 IDWriteBitmapRenderTarget1 *target1;
1125 IDWriteRenderingParams *params;
1126 IDWriteGdiInterop *interop;
1127 IDWriteFontFace *fontface;
1128 IDWriteFactory *factory;
1129 DWRITE_GLYPH_RUN run;
1130 HBITMAP hbm, hbm2;
1131 UINT16 glyphs[2];
1132 DWRITE_MATRIX m;
1133 DIBSECTION ds;
1134 XFORM xform;
1135 COLORREF c;
1136 HRESULT hr;
1137 FLOAT pdip;
1138 SIZE size;
1139 ULONG ref;
1140 UINT32 ch;
1141 HDC hdc;
1142 int ret;
1144 factory = create_factory();
1146 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1147 EXPECT_HR(hr, S_OK);
1149 target = NULL;
1150 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
1151 EXPECT_HR(hr, S_OK);
1153 if (0) /* crashes on native */
1154 hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
1156 size.cx = size.cy = -1;
1157 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1158 EXPECT_HR(hr, S_OK);
1159 ok(size.cx == 0, "got %d\n", size.cx);
1160 ok(size.cy == 0, "got %d\n", size.cy);
1162 target2 = NULL;
1163 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
1164 EXPECT_HR(hr, S_OK);
1165 ok(target != target2, "got %p, %p\n", target2, target);
1166 IDWriteBitmapRenderTarget_Release(target2);
1168 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1169 ok(hdc != NULL, "got %p\n", hdc);
1171 /* test mode */
1172 ret = GetGraphicsMode(hdc);
1173 ok(ret == GM_ADVANCED, "got %d\n", ret);
1175 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1176 ok(hbm != NULL, "got %p\n", hbm);
1178 /* check DIB properties */
1179 ret = GetObjectW(hbm, sizeof(ds), &ds);
1180 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1181 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1182 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1183 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1184 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1185 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1187 IDWriteBitmapRenderTarget_Release(target);
1189 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1190 ok(!hbm, "got %p\n", hbm);
1192 target = NULL;
1193 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
1194 EXPECT_HR(hr, S_OK);
1196 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1197 ok(hdc != NULL, "got %p\n", hdc);
1199 /* test context settings */
1200 c = GetTextColor(hdc);
1201 ok(c == RGB(0, 0, 0), "got 0x%08x\n", c);
1202 ret = GetBkMode(hdc);
1203 ok(ret == OPAQUE, "got %d\n", ret);
1204 c = GetBkColor(hdc);
1205 ok(c == RGB(255, 255, 255), "got 0x%08x\n", c);
1207 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1208 ok(hbm != NULL, "got %p\n", hbm);
1210 /* check DIB properties */
1211 ret = GetObjectW(hbm, sizeof(ds), &ds);
1212 ok(ret == sizeof(ds), "got %d\n", ret);
1213 ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
1214 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1215 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1216 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1217 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1219 size.cx = size.cy = -1;
1220 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1221 EXPECT_HR(hr, S_OK);
1222 ok(size.cx == 10, "got %d\n", size.cx);
1223 ok(size.cy == 5, "got %d\n", size.cy);
1225 /* resize to same size */
1226 hr = IDWriteBitmapRenderTarget_Resize(target, 10, 5);
1227 ok(hr == S_OK, "got 0x%08x\n", hr);
1229 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1230 ok(hbm2 == hbm, "got %p, %p\n", hbm2, hbm);
1232 /* shrink */
1233 hr = IDWriteBitmapRenderTarget_Resize(target, 5, 5);
1234 ok(hr == S_OK, "got 0x%08x\n", hr);
1236 size.cx = size.cy = -1;
1237 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1238 ok(hr == S_OK, "got 0x%08x\n", hr);
1239 ok(size.cx == 5, "got %d\n", size.cx);
1240 ok(size.cy == 5, "got %d\n", size.cy);
1242 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1243 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1245 hr = IDWriteBitmapRenderTarget_Resize(target, 20, 5);
1246 ok(hr == S_OK, "got 0x%08x\n", hr);
1248 size.cx = size.cy = -1;
1249 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1250 ok(hr == S_OK, "got 0x%08x\n", hr);
1251 ok(size.cx == 20, "got %d\n", size.cx);
1252 ok(size.cy == 5, "got %d\n", size.cy);
1254 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1255 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1257 hr = IDWriteBitmapRenderTarget_Resize(target, 1, 5);
1258 ok(hr == S_OK, "got 0x%08x\n", hr);
1260 size.cx = size.cy = -1;
1261 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1262 ok(hr == S_OK, "got 0x%08x\n", hr);
1263 ok(size.cx == 1, "got %d\n", size.cx);
1264 ok(size.cy == 5, "got %d\n", size.cy);
1266 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1267 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1269 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1270 ok(ret == sizeof(ds), "got %d\n", ret);
1271 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1272 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1273 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1274 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1275 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1277 /* empty rectangle */
1278 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 5);
1279 ok(hr == S_OK, "got 0x%08x\n", hr);
1281 size.cx = size.cy = -1;
1282 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1283 ok(hr == S_OK, "got 0x%08x\n", hr);
1284 ok(size.cx == 0, "got %d\n", size.cx);
1285 ok(size.cy == 5, "got %d\n", size.cy);
1287 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1288 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1290 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1291 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1292 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1293 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1294 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1295 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1296 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1298 /* transform tests, current hdc transform is not immediately affected */
1299 if (0) /* crashes on native */
1300 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, NULL);
1302 memset(&m, 0xcc, sizeof(m));
1303 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1304 ok(hr == S_OK, "got 0x%08x\n", hr);
1305 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);
1306 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1307 ret = GetWorldTransform(hdc, &xform);
1308 ok(ret, "got %d\n", ret);
1309 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1310 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1312 memset(&m, 0, sizeof(m));
1313 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1314 ok(hr == S_OK, "got 0x%08x\n", hr);
1316 memset(&m, 0xcc, sizeof(m));
1317 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1318 ok(hr == S_OK, "got 0x%08x\n", hr);
1319 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);
1320 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1321 ret = GetWorldTransform(hdc, &xform);
1322 ok(ret, "got %d\n", ret);
1323 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1324 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1326 memset(&m, 0, sizeof(m));
1327 m.m11 = 2.0; m.m22 = 1.0;
1328 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1329 ok(hr == S_OK, "got 0x%08x\n", hr);
1330 ret = GetWorldTransform(hdc, &xform);
1331 ok(ret, "got %d\n", ret);
1332 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1333 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1335 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, NULL);
1336 ok(hr == S_OK, "got 0x%08x\n", hr);
1338 memset(&m, 0xcc, sizeof(m));
1339 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1340 ok(hr == S_OK, "got 0x%08x\n", hr);
1341 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);
1342 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1344 /* pixels per dip */
1345 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1346 ok(pdip == 1.0, "got %.2f\n", pdip);
1348 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
1349 ok(hr == S_OK, "got 0x%08x\n", hr);
1351 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, -1.0);
1352 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1354 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 0.0);
1355 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1357 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1358 ok(pdip == 2.0, "got %.2f\n", pdip);
1360 hr = IDWriteBitmapRenderTarget_QueryInterface(target, &IID_IDWriteBitmapRenderTarget1, (void**)&target1);
1361 if (hr == S_OK) {
1362 DWRITE_TEXT_ANTIALIAS_MODE mode;
1364 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1365 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1367 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE+1);
1368 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1370 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1371 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1373 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
1374 ok(hr == S_OK, "got 0x%08x\n", hr);
1376 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1377 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, "got %d\n", mode);
1379 IDWriteBitmapRenderTarget1_Release(target1);
1381 else
1382 win_skip("IDWriteBitmapRenderTarget1 is not supported.\n");
1384 /* DrawGlyphRun() argument validation. */
1385 hr = IDWriteBitmapRenderTarget_Resize(target, 16, 16);
1386 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
1388 fontface = create_fontface(factory);
1390 ch = 'A';
1391 glyphs[0] = 0;
1392 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, glyphs);
1393 ok(hr == S_OK, "got 0x%08x\n", hr);
1394 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
1395 glyphs[1] = glyphs[0];
1397 memset(&run, 0, sizeof(run));
1398 run.fontFace = fontface;
1399 run.fontEmSize = 12.0f;
1400 run.glyphCount = 2;
1401 run.glyphIndices = glyphs;
1403 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
1404 DWRITE_RENDERING_MODE_DEFAULT, &params);
1405 ok(hr == S_OK, "Failed to create rendering params, hr %#x.\n", hr);
1407 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1408 &run, NULL, RGB(255, 0, 0), NULL);
1409 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1411 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1412 &run, NULL, RGB(255, 0, 0), NULL);
1413 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1415 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1416 &run, params, RGB(255, 0, 0), NULL);
1417 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Unexpected hr %#x.\n", hr);
1419 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL,
1420 &run, params, RGB(255, 0, 0), NULL);
1421 ok(hr == S_OK, "Failed to draw a run, hr %#x.\n", hr);
1423 IDWriteRenderingParams_Release(params);
1425 /* Zero sized target returns earlier. */
1426 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 16);
1427 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
1429 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1430 &run, NULL, RGB(255, 0, 0), NULL);
1431 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1433 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1434 &run, params, RGB(255, 0, 0), NULL);
1435 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1437 IDWriteFontFace_Release(fontface);
1439 ref = IDWriteBitmapRenderTarget_Release(target);
1440 ok(ref == 0, "render target not released, %u\n", ref);
1441 ref = IDWriteGdiInterop_Release(interop);
1442 ok(ref == 0, "interop not released, %u\n", ref);
1443 ref = IDWriteFactory_Release(factory);
1444 ok(ref == 0, "factory not released, %u\n", ref);
1447 static void test_GetFontFamily(void)
1449 IDWriteFontCollection *collection, *collection2;
1450 IDWriteFontCollection *syscoll;
1451 IDWriteFontFamily *family, *family2;
1452 IDWriteFontFamily1 *family1;
1453 IDWriteGdiInterop *interop;
1454 IDWriteFont *font, *font2;
1455 IDWriteFactory *factory;
1456 LOGFONTW logfont;
1457 HRESULT hr;
1458 ULONG ref;
1460 factory = create_factory();
1462 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1463 EXPECT_HR(hr, S_OK);
1465 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1466 ok(hr == S_OK, "got 0x%08x\n", hr);
1468 memset(&logfont, 0, sizeof(logfont));
1469 logfont.lfHeight = 12;
1470 logfont.lfWidth = 12;
1471 logfont.lfWeight = FW_NORMAL;
1472 logfont.lfItalic = 1;
1473 lstrcpyW(logfont.lfFaceName, tahomaW);
1475 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1476 ok(hr == S_OK, "got 0x%08x\n", hr);
1478 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1479 ok(hr == S_OK, "got 0x%08x\n", hr);
1480 ok(font2 != font, "got %p, %p\n", font2, font);
1482 if (0) /* crashes on native */
1483 hr = IDWriteFont_GetFontFamily(font, NULL);
1485 EXPECT_REF(font, 1);
1486 hr = IDWriteFont_GetFontFamily(font, &family);
1487 EXPECT_HR(hr, S_OK);
1488 EXPECT_REF(font, 1);
1489 EXPECT_REF(family, 2);
1491 hr = IDWriteFont_GetFontFamily(font, &family2);
1492 EXPECT_HR(hr, S_OK);
1493 ok(family2 == family, "got %p, previous %p\n", family2, family);
1494 EXPECT_REF(font, 1);
1495 EXPECT_REF(family, 3);
1496 IDWriteFontFamily_Release(family2);
1498 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
1499 EXPECT_HR(hr, E_NOINTERFACE);
1500 ok(family2 == NULL, "got %p\n", family2);
1502 hr = IDWriteFont_GetFontFamily(font2, &family2);
1503 ok(hr == S_OK, "got 0x%08x\n", hr);
1504 ok(family2 != family, "got %p, %p\n", family2, family);
1506 collection = NULL;
1507 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
1508 ok(hr == S_OK, "got 0x%08x\n", hr);
1510 collection2 = NULL;
1511 hr = IDWriteFontFamily_GetFontCollection(family2, &collection2);
1512 ok(hr == S_OK, "got 0x%08x\n", hr);
1513 ok(collection == collection2, "got %p, %p\n", collection, collection2);
1514 ok(collection == syscoll, "got %p, %p\n", collection, syscoll);
1516 IDWriteFont_Release(font);
1517 IDWriteFont_Release(font2);
1519 hr = IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily1, (void**)&family1);
1520 if (hr == S_OK) {
1521 IDWriteFontFaceReference *ref, *ref1;
1522 IDWriteFontList1 *fontlist1;
1523 IDWriteFontList *fontlist;
1524 IDWriteFont3 *font3;
1525 IDWriteFont1 *font1;
1527 font3 = (void*)0xdeadbeef;
1528 hr = IDWriteFontFamily1_GetFont(family1, ~0u, &font3);
1529 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1530 ok(font3 == NULL, "got %p\n", font3);
1532 hr = IDWriteFontFamily1_GetFont(family1, 0, &font3);
1533 ok(hr == S_OK, "got 0x%08x\n", hr);
1535 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont, (void**)&font);
1536 ok(hr == S_OK, "got 0x%08x\n", hr);
1537 IDWriteFont_Release(font);
1539 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont1, (void**)&font1);
1540 ok(hr == S_OK, "got 0x%08x\n", hr);
1541 IDWriteFont1_Release(font1);
1543 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList1, (void **)&fontlist1);
1544 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Failed to get interface, hr %#x.\n", hr);
1545 if (hr == S_OK) {
1546 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void **)&fontlist);
1547 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1548 ok(fontlist == (IDWriteFontList *)fontlist1, "Unexpected interface pointer.\n");
1549 ok(fontlist != (IDWriteFontList *)family1, "Unexpected interface pointer.\n");
1550 ok(fontlist != (IDWriteFontList *)family, "Unexpected interface pointer.\n");
1551 IDWriteFontList1_Release(fontlist1);
1552 IDWriteFontList_Release(fontlist);
1555 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void**)&fontlist);
1556 ok(hr == S_OK, "got 0x%08x\n", hr);
1557 IDWriteFontList_Release(fontlist);
1559 IDWriteFont3_Release(font3);
1561 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref);
1562 ok(hr == S_OK, "got 0x%08x\n", hr);
1564 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref1);
1565 ok(hr == S_OK, "got 0x%08x\n", hr);
1566 ok(ref != ref1, "got %p, %p\n", ref, ref1);
1568 IDWriteFontFaceReference_Release(ref);
1569 IDWriteFontFaceReference_Release(ref1);
1571 IDWriteFontFamily1_Release(family1);
1573 else
1574 win_skip("IDWriteFontFamily1 is not supported.\n");
1576 IDWriteFontCollection_Release(syscoll);
1577 IDWriteFontCollection_Release(collection2);
1578 IDWriteFontCollection_Release(collection);
1579 IDWriteFontFamily_Release(family2);
1580 IDWriteFontFamily_Release(family);
1581 IDWriteGdiInterop_Release(interop);
1582 ref = IDWriteFactory_Release(factory);
1583 ok(ref == 0, "factory not released, %u\n", ref);
1586 static void test_GetFamilyNames(void)
1588 IDWriteFontFamily *family;
1589 IDWriteLocalizedStrings *names, *names2;
1590 IDWriteGdiInterop *interop;
1591 IDWriteFactory *factory;
1592 IDWriteFont *font;
1593 LOGFONTW logfont;
1594 WCHAR buffer[100];
1595 HRESULT hr;
1596 UINT32 len;
1597 ULONG ref;
1599 factory = create_factory();
1601 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1602 EXPECT_HR(hr, S_OK);
1604 memset(&logfont, 0, sizeof(logfont));
1605 logfont.lfHeight = 12;
1606 logfont.lfWidth = 12;
1607 logfont.lfWeight = FW_NORMAL;
1608 logfont.lfItalic = 1;
1609 lstrcpyW(logfont.lfFaceName, tahomaW);
1611 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1612 EXPECT_HR(hr, S_OK);
1614 hr = IDWriteFont_GetFontFamily(font, &family);
1615 EXPECT_HR(hr, S_OK);
1617 if (0) /* crashes on native */
1618 hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
1620 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1621 ok(hr == S_OK, "got 0x%08x\n", hr);
1622 EXPECT_REF(names, 1);
1624 hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
1625 ok(hr == S_OK, "got 0x%08x\n", hr);
1626 EXPECT_REF(names2, 1);
1627 ok(names != names2, "got %p, was %p\n", names2, names);
1629 IDWriteLocalizedStrings_Release(names2);
1631 /* GetStringLength */
1632 if (0) /* crashes on native */
1633 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
1635 len = 100;
1636 hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
1637 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1638 ok(len == (UINT32)-1, "got %u\n", len);
1640 len = 0;
1641 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
1642 ok(hr == S_OK, "got 0x%08x\n", hr);
1643 ok(len > 0, "got %u\n", len);
1645 /* GetString */
1646 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
1647 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1649 hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
1650 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1652 if (0)
1653 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
1655 buffer[0] = 1;
1656 hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
1657 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1658 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1660 buffer[0] = 1;
1661 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
1662 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1663 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1665 buffer[0] = 1;
1666 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
1667 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1668 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1670 buffer[0] = 0;
1671 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1672 ok(hr == S_OK, "got 0x%08x\n", hr);
1673 ok(buffer[0] != 0, "got %x\n", buffer[0]);
1675 IDWriteLocalizedStrings_Release(names);
1677 IDWriteFontFamily_Release(family);
1678 IDWriteFont_Release(font);
1679 IDWriteGdiInterop_Release(interop);
1680 ref = IDWriteFactory_Release(factory);
1681 ok(ref == 0, "factory not released, %u\n", ref);
1684 static void test_CreateFontFace(void)
1686 IDWriteFontFace *fontface, *fontface2;
1687 IDWriteFontCollection *collection;
1688 DWRITE_FONT_FILE_TYPE file_type;
1689 DWRITE_FONT_FACE_TYPE face_type;
1690 IDWriteGdiInterop *interop;
1691 IDWriteFont *font, *font2;
1692 IDWriteFontFamily *family;
1693 IDWriteFactory *factory;
1694 IDWriteFontFile *file;
1695 LOGFONTW logfont;
1696 BOOL supported;
1697 UINT32 count;
1698 WCHAR *path;
1699 HRESULT hr;
1701 factory = create_factory();
1703 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1704 EXPECT_HR(hr, S_OK);
1706 memset(&logfont, 0, sizeof(logfont));
1707 logfont.lfHeight = 12;
1708 logfont.lfWidth = 12;
1709 logfont.lfWeight = FW_NORMAL;
1710 logfont.lfItalic = 1;
1711 lstrcpyW(logfont.lfFaceName, tahomaW);
1713 font = NULL;
1714 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1715 ok(hr == S_OK, "got 0x%08x\n", hr);
1717 font2 = NULL;
1718 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1719 ok(hr == S_OK, "got 0x%08x\n", hr);
1720 ok(font != font2, "got %p, %p\n", font, font2);
1722 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
1723 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1725 if (0) /* crashes on native */
1726 hr = IDWriteFont_CreateFontFace(font, NULL);
1728 fontface = NULL;
1729 hr = IDWriteFont_CreateFontFace(font, &fontface);
1730 ok(hr == S_OK, "got 0x%08x\n", hr);
1732 fontface2 = NULL;
1733 hr = IDWriteFont_CreateFontFace(font, &fontface2);
1734 ok(hr == S_OK, "got 0x%08x\n", hr);
1735 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1736 IDWriteFontFace_Release(fontface2);
1738 fontface2 = NULL;
1739 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1740 ok(hr == S_OK, "got 0x%08x\n", hr);
1741 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1742 IDWriteFontFace_Release(fontface2);
1744 IDWriteFont_Release(font2);
1745 IDWriteFont_Release(font);
1747 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFont, (void**)&font);
1748 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL), "got 0x%08x\n", hr);
1750 IDWriteFontFace_Release(fontface);
1751 IDWriteGdiInterop_Release(interop);
1753 /* Create from system collection */
1754 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1755 ok(hr == S_OK, "got 0x%08x\n", hr);
1757 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
1758 ok(hr == S_OK, "got 0x%08x\n", hr);
1760 font = NULL;
1761 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1762 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1763 ok(hr == S_OK, "got 0x%08x\n", hr);
1765 font2 = NULL;
1766 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1767 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
1768 ok(hr == S_OK, "got 0x%08x\n", hr);
1769 ok(font != font2, "got %p, %p\n", font, font2);
1771 fontface = NULL;
1772 hr = IDWriteFont_CreateFontFace(font, &fontface);
1773 ok(hr == S_OK, "got 0x%08x\n", hr);
1775 fontface2 = NULL;
1776 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1777 ok(hr == S_OK, "got 0x%08x\n", hr);
1778 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1780 IDWriteFontFace_Release(fontface);
1781 IDWriteFontFace_Release(fontface2);
1782 IDWriteFont_Release(font2);
1783 IDWriteFont_Release(font);
1784 IDWriteFontFamily_Release(family);
1785 IDWriteFontCollection_Release(collection);
1787 /* IDWriteFactory::CreateFontFace() */
1788 path = create_testfontfile(test_fontfile);
1789 factory = create_factory();
1791 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
1792 ok(hr == S_OK, "got 0x%08x\n",hr);
1794 supported = FALSE;
1795 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1796 face_type = DWRITE_FONT_FACE_TYPE_CFF;
1797 count = 0;
1798 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &count);
1799 ok(hr == S_OK, "got 0x%08x\n", hr);
1800 ok(supported == TRUE, "got %i\n", supported);
1801 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
1802 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
1803 ok(count == 1, "got %i\n", count);
1805 /* invalid simulation flags */
1806 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, ~0u, &fontface);
1807 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1809 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0xf, &fontface);
1810 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1812 /* try mismatching face type, the one that's not supported */
1813 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1814 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
1816 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, 1, &file, 0,
1817 DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1818 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* < win10 */, "got 0x%08x\n", hr);
1820 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_RAW_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1821 todo_wine
1822 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == E_INVALIDARG) /* older versions */, "got 0x%08x\n", hr);
1824 fontface = (void*)0xdeadbeef;
1825 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TYPE1, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1826 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1827 ok(fontface == NULL, "got %p\n", fontface);
1829 fontface = (void*)0xdeadbeef;
1830 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_VECTOR, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1831 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1832 ok(fontface == NULL, "got %p\n", fontface);
1834 fontface = (void*)0xdeadbeef;
1835 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_BITMAP, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1836 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1837 ok(fontface == NULL, "got %p\n", fontface);
1839 fontface = NULL;
1840 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_UNKNOWN, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1841 todo_wine
1842 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* < win10 */, "got 0x%08x\n", hr);
1843 if (hr == S_OK) {
1844 ok(fontface != NULL, "got %p\n", fontface);
1845 face_type = IDWriteFontFace_GetType(fontface);
1846 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %d\n", face_type);
1847 IDWriteFontFace_Release(fontface);
1850 IDWriteFontFile_Release(file);
1851 IDWriteFactory_Release(factory);
1852 DELETE_FONTFILE(path);
1855 static void get_expected_font_metrics(IDWriteFontFace *fontface, DWRITE_FONT_METRICS1 *metrics)
1857 void *os2_context, *head_context, *post_context, *hhea_context;
1858 const TT_OS2_V2 *tt_os2;
1859 const TT_HEAD *tt_head;
1860 const TT_POST *tt_post;
1861 const TT_HHEA *tt_hhea;
1862 UINT32 size;
1863 BOOL exists;
1864 HRESULT hr;
1866 memset(metrics, 0, sizeof(*metrics));
1868 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void**)&tt_os2, &size, &os2_context, &exists);
1869 ok(hr == S_OK, "got 0x%08x\n", hr);
1870 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void**)&tt_head, &size, &head_context, &exists);
1871 ok(hr == S_OK, "got 0x%08x\n", hr);
1872 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HHEA_TAG, (const void**)&tt_hhea, &size, &hhea_context, &exists);
1873 ok(hr == S_OK, "got 0x%08x\n", hr);
1874 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_POST_TAG, (const void**)&tt_post, &size, &post_context, &exists);
1875 ok(hr == S_OK, "got 0x%08x\n", hr);
1877 if (tt_head) {
1878 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
1879 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
1880 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
1881 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
1882 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
1885 if (tt_os2) {
1886 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
1887 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
1888 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1889 metrics->descent = descent < 0 ? -descent : 0;
1890 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1891 metrics->hasTypographicMetrics = TRUE;
1893 else {
1894 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
1895 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1896 interpreted as large unsigned value. */
1897 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
1899 if (tt_hhea) {
1900 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
1901 INT32 linegap;
1903 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
1904 metrics->ascent - metrics->descent;
1905 metrics->lineGap = linegap > 0 ? linegap : 0;
1909 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
1910 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
1912 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
1913 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
1914 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
1915 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
1916 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
1917 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
1918 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
1919 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
1922 if (tt_post) {
1923 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1924 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1927 if (metrics->underlineThickness == 0)
1928 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1929 if (metrics->strikethroughThickness == 0)
1930 metrics->strikethroughThickness = metrics->underlineThickness;
1932 if (tt_os2)
1933 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
1934 if (tt_head)
1935 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
1936 if (tt_hhea)
1937 IDWriteFontFace_ReleaseFontTable(fontface, hhea_context);
1938 if (tt_post)
1939 IDWriteFontFace_ReleaseFontTable(fontface, post_context);
1942 static void check_font_metrics(const WCHAR *nameW, BOOL has_metrics1, const DWRITE_FONT_METRICS *got,
1943 const DWRITE_FONT_METRICS1 *expected)
1945 ok(got->designUnitsPerEm == expected->designUnitsPerEm, "font %s: designUnitsPerEm %u, expected %u\n",
1946 wine_dbgstr_w(nameW), got->designUnitsPerEm, expected->designUnitsPerEm);
1947 ok(got->ascent == expected->ascent, "font %s: ascent %u, expected %u\n", wine_dbgstr_w(nameW), got->ascent,
1948 expected->ascent);
1949 ok(got->descent == expected->descent, "font %s: descent %u, expected %u\n", wine_dbgstr_w(nameW), got->descent,
1950 expected->descent);
1951 ok(got->lineGap == expected->lineGap, "font %s: lineGap %d, expected %d\n", wine_dbgstr_w(nameW), got->lineGap,
1952 expected->lineGap);
1953 ok(got->underlinePosition == expected->underlinePosition, "font %s: underlinePosition %d, expected %d\n",
1954 wine_dbgstr_w(nameW), got->underlinePosition, expected->underlinePosition);
1955 ok(got->underlineThickness == expected->underlineThickness, "font %s: underlineThickness %u, "
1956 "expected %u\n", wine_dbgstr_w(nameW), got->underlineThickness, expected->underlineThickness);
1957 ok(got->strikethroughPosition == expected->strikethroughPosition, "font %s: strikethroughPosition %d, expected %d\n",
1958 wine_dbgstr_w(nameW), got->strikethroughPosition, expected->strikethroughPosition);
1959 ok(got->strikethroughThickness == expected->strikethroughThickness, "font %s: strikethroughThickness %u, "
1960 "expected %u\n", wine_dbgstr_w(nameW), got->strikethroughThickness, expected->strikethroughThickness);
1962 if (has_metrics1) {
1963 const DWRITE_FONT_METRICS1 *m1 = (const DWRITE_FONT_METRICS1*)got;
1964 ok(m1->hasTypographicMetrics == expected->hasTypographicMetrics, "font %s: hasTypographicMetrics %d, "
1965 "expected %d\n", wine_dbgstr_w(nameW), m1->hasTypographicMetrics, expected->hasTypographicMetrics);
1966 ok(m1->glyphBoxLeft == expected->glyphBoxLeft, "font %s: glyphBoxLeft %d, expected %d\n", wine_dbgstr_w(nameW),
1967 m1->glyphBoxLeft, expected->glyphBoxLeft);
1968 ok(m1->glyphBoxTop == expected->glyphBoxTop, "font %s: glyphBoxTop %d, expected %d\n", wine_dbgstr_w(nameW),
1969 m1->glyphBoxTop, expected->glyphBoxTop);
1970 ok(m1->glyphBoxRight == expected->glyphBoxRight, "font %s: glyphBoxRight %d, expected %d\n", wine_dbgstr_w(nameW),
1971 m1->glyphBoxRight, expected->glyphBoxRight);
1972 ok(m1->glyphBoxBottom == expected->glyphBoxBottom, "font %s: glyphBoxBottom %d, expected %d\n", wine_dbgstr_w(nameW),
1973 m1->glyphBoxBottom, expected->glyphBoxBottom);
1975 ok(m1->subscriptPositionX == expected->subscriptPositionX, "font %s: subscriptPositionX %d, expected %d\n",
1976 wine_dbgstr_w(nameW), m1->subscriptPositionX, expected->subscriptPositionX);
1977 ok(m1->subscriptPositionY == expected->subscriptPositionY, "font %s: subscriptPositionY %d, expected %d\n",
1978 wine_dbgstr_w(nameW), m1->subscriptPositionY, expected->subscriptPositionY);
1979 ok(m1->subscriptSizeX == expected->subscriptSizeX, "font %s: subscriptSizeX %d, expected %d\n",
1980 wine_dbgstr_w(nameW), m1->subscriptSizeX, expected->subscriptSizeX);
1981 ok(m1->subscriptSizeY == expected->subscriptSizeY, "font %s: subscriptSizeY %d, expected %d\n",
1982 wine_dbgstr_w(nameW), m1->subscriptSizeY, expected->subscriptSizeY);
1983 ok(m1->superscriptPositionX == expected->superscriptPositionX, "font %s: superscriptPositionX %d, expected %d\n",
1984 wine_dbgstr_w(nameW), m1->superscriptPositionX, expected->superscriptPositionX);
1985 ok(m1->superscriptPositionY == expected->superscriptPositionY, "font %s: superscriptPositionY %d, expected %d\n",
1986 wine_dbgstr_w(nameW), m1->superscriptPositionY, expected->superscriptPositionY);
1987 ok(m1->superscriptSizeX == expected->superscriptSizeX, "font %s: superscriptSizeX %d, expected %d\n",
1988 wine_dbgstr_w(nameW), m1->superscriptSizeX, expected->superscriptSizeX);
1989 ok(m1->superscriptSizeY == expected->superscriptSizeY, "font %s: superscriptSizeY %d, expected %d\n",
1990 wine_dbgstr_w(nameW), m1->superscriptSizeY, expected->superscriptSizeY);
1994 static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
1996 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1997 BOOL exists = FALSE;
1998 UINT32 index;
1999 HRESULT hr;
2001 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
2002 ok(hr == S_OK, "got 0x%08x\n", hr);
2003 ok(exists, "got %d\n", exists);
2005 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
2006 ok(hr == S_OK, "got 0x%08x\n", hr);
2009 static void test_GetMetrics(void)
2011 DWRITE_FONT_METRICS metrics, metrics2;
2012 IDWriteFontCollection *syscollection;
2013 IDWriteGdiInterop *interop;
2014 IDWriteFontFace *fontface;
2015 IDWriteFactory *factory;
2016 OUTLINETEXTMETRICW otm;
2017 IDWriteFontFile *file;
2018 IDWriteFont1 *font1;
2019 IDWriteFont *font;
2020 LOGFONTW logfont;
2021 UINT32 count, i;
2022 HRESULT hr;
2023 HDC hdc;
2024 HFONT hfont;
2025 ULONG ref;
2026 int ret;
2028 factory = create_factory();
2030 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2031 EXPECT_HR(hr, S_OK);
2033 memset(&logfont, 0, sizeof(logfont));
2034 logfont.lfHeight = 12;
2035 logfont.lfWidth = 12;
2036 logfont.lfWeight = FW_NORMAL;
2037 logfont.lfItalic = 1;
2038 lstrcpyW(logfont.lfFaceName, tahomaW);
2040 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2041 ok(hr == S_OK, "got 0x%08x\n", hr);
2043 hfont = CreateFontIndirectW(&logfont);
2044 hdc = CreateCompatibleDC(0);
2045 SelectObject(hdc, hfont);
2047 otm.otmSize = sizeof(otm);
2048 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
2049 ok(ret, "got %d\n", ret);
2050 DeleteDC(hdc);
2051 DeleteObject(hfont);
2053 if (0) /* crashes on native */
2054 IDWriteFont_GetMetrics(font, NULL);
2056 memset(&metrics, 0, sizeof(metrics));
2057 IDWriteFont_GetMetrics(font, &metrics);
2059 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2060 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2061 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2062 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2063 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2064 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2065 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2066 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2067 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2068 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2070 hr = IDWriteFont_CreateFontFace(font, &fontface);
2071 ok(hr == S_OK, "got 0x%08x\n", hr);
2073 memset(&metrics, 0, sizeof(metrics));
2074 IDWriteFontFace_GetMetrics(fontface, &metrics);
2076 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2077 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2078 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2079 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2080 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2081 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2082 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2083 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2084 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2085 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2087 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
2088 if (hr == S_OK) {
2089 DWRITE_FONT_METRICS1 metrics1;
2090 IDWriteFontFace1 *fontface1;
2092 memset(&metrics1, 0, sizeof(metrics1));
2093 IDWriteFont1_GetMetrics(font1, &metrics1);
2095 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2096 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2097 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2098 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2099 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2100 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2101 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2102 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2103 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2104 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2105 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2106 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2107 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2108 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2109 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2110 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2111 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2112 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2113 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2114 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2115 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2117 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2118 ok(hr == S_OK, "got 0x%08x\n", hr);
2120 memset(&metrics1, 0, sizeof(metrics1));
2121 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2123 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2124 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2125 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2126 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2127 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2128 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2129 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2130 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2131 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2132 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2133 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2134 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2135 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2136 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2137 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2138 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2139 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2140 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2141 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2142 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2143 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2145 IDWriteFontFace1_Release(fontface1);
2146 IDWriteFont1_Release(font1);
2148 else
2149 win_skip("DWRITE_FONT_METRICS1 is not supported.\n");
2151 IDWriteFontFace_Release(fontface);
2152 IDWriteFont_Release(font);
2153 IDWriteGdiInterop_Release(interop);
2155 /* bold simulation affects returned font metrics */
2156 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
2158 /* create regulat Tahoma with bold simulation */
2159 hr = IDWriteFont_CreateFontFace(font, &fontface);
2160 ok(hr == S_OK, "got 0x%08x\n", hr);
2162 count = 1;
2163 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
2164 ok(hr == S_OK, "got 0x%08x\n", hr);
2166 IDWriteFontFace_GetMetrics(fontface, &metrics);
2167 ok(IDWriteFontFace_GetSimulations(fontface) == 0, "wrong simulations flags\n");
2168 IDWriteFontFace_Release(fontface);
2170 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
2171 0, DWRITE_FONT_SIMULATIONS_BOLD, &fontface);
2172 ok(hr == S_OK, "got 0x%08x\n", hr);
2173 IDWriteFontFace_GetMetrics(fontface, &metrics2);
2174 ok(IDWriteFontFace_GetSimulations(fontface) == DWRITE_FONT_SIMULATIONS_BOLD, "wrong simulations flags\n");
2176 ok(metrics.ascent == metrics2.ascent, "got %u, %u\n", metrics2.ascent, metrics.ascent);
2177 ok(metrics.descent == metrics2.descent, "got %u, %u\n", metrics2.descent, metrics.descent);
2178 ok(metrics.lineGap == metrics2.lineGap, "got %d, %d\n", metrics2.lineGap, metrics.lineGap);
2179 ok(metrics.capHeight == metrics2.capHeight, "got %u, %u\n", metrics2.capHeight, metrics.capHeight);
2180 ok(metrics.xHeight == metrics2.xHeight, "got %u, %u\n", metrics2.xHeight, metrics.xHeight);
2181 ok(metrics.underlinePosition == metrics2.underlinePosition, "got %d, %d\n", metrics2.underlinePosition,
2182 metrics.underlinePosition);
2183 ok(metrics.underlineThickness == metrics2.underlineThickness, "got %u, %u\n", metrics2.underlineThickness,
2184 metrics.underlineThickness);
2185 ok(metrics.strikethroughPosition == metrics2.strikethroughPosition, "got %d, %d\n", metrics2.strikethroughPosition,
2186 metrics.strikethroughPosition);
2187 ok(metrics.strikethroughThickness == metrics2.strikethroughThickness, "got %u, %u\n", metrics2.strikethroughThickness,
2188 metrics.strikethroughThickness);
2190 IDWriteFontFile_Release(file);
2191 IDWriteFontFace_Release(fontface);
2192 IDWriteFont_Release(font);
2194 /* test metrics for whole system collection */
2195 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
2196 ok(hr == S_OK, "got 0x%08x\n", hr);
2197 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
2199 for (i = 0; i < count; i++) {
2200 DWRITE_FONT_METRICS1 expected_metrics, metrics1;
2201 IDWriteLocalizedStrings *names;
2202 IDWriteFontFace1 *fontface1;
2203 IDWriteFontFamily *family;
2204 IDWriteFont *font;
2205 WCHAR nameW[256];
2207 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
2208 ok(hr == S_OK, "got 0x%08x\n", hr);
2210 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
2211 DWRITE_FONT_STYLE_NORMAL, &font);
2212 ok(hr == S_OK, "got 0x%08x\n", hr);
2214 hr = IDWriteFont_CreateFontFace(font, &fontface);
2215 ok(hr == S_OK, "got 0x%08x\n", hr);
2217 fontface1 = NULL;
2218 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2220 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2221 ok(hr == S_OK, "got 0x%08x\n", hr);
2223 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
2225 IDWriteLocalizedStrings_Release(names);
2226 IDWriteFont_Release(font);
2228 get_expected_font_metrics(fontface, &expected_metrics);
2229 if (fontface1) {
2230 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2231 check_font_metrics(nameW, TRUE, (const DWRITE_FONT_METRICS*)&metrics1, &expected_metrics);
2233 else {
2234 IDWriteFontFace_GetMetrics(fontface, &metrics);
2235 check_font_metrics(nameW, FALSE, &metrics, &expected_metrics);
2238 if (fontface1)
2239 IDWriteFontFace1_Release(fontface1);
2240 IDWriteFontFace_Release(fontface);
2241 IDWriteFontFamily_Release(family);
2243 IDWriteFontCollection_Release(syscollection);
2244 ref = IDWriteFactory_Release(factory);
2245 ok(ref == 0, "factory not released, %u\n", ref);
2248 static void test_system_fontcollection(void)
2250 IDWriteFontCollection *collection, *coll2;
2251 IDWriteLocalFontFileLoader *localloader;
2252 IDWriteFontCollection1 *collection1;
2253 IDWriteFactory *factory, *factory2;
2254 IDWriteFontFileLoader *loader;
2255 IDWriteFontFamily *family;
2256 IDWriteFontFace *fontface;
2257 IDWriteFontFile *file;
2258 IDWriteFont *font;
2259 HRESULT hr;
2260 ULONG ref;
2261 UINT32 i;
2262 BOOL ret;
2264 factory = create_factory();
2266 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2267 ok(hr == S_OK, "got 0x%08x\n", hr);
2269 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, FALSE);
2270 ok(hr == S_OK, "got 0x%08x\n", hr);
2271 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2272 IDWriteFontCollection_Release(coll2);
2274 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, TRUE);
2275 ok(hr == S_OK, "got 0x%08x\n", hr);
2276 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2277 IDWriteFontCollection_Release(coll2);
2279 factory2 = create_factory();
2280 hr = IDWriteFactory_GetSystemFontCollection(factory2, &coll2, FALSE);
2281 ok(hr == S_OK, "got 0x%08x\n", hr);
2282 ok(coll2 != collection, "got %p, was %p\n", coll2, collection);
2283 IDWriteFontCollection_Release(coll2);
2284 IDWriteFactory_Release(factory2);
2286 i = IDWriteFontCollection_GetFontFamilyCount(collection);
2287 ok(i, "got %u\n", i);
2289 /* invalid index */
2290 family = (void*)0xdeadbeef;
2291 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2292 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2293 ok(family == NULL, "got %p\n", family);
2295 ret = FALSE;
2296 i = (UINT32)-1;
2297 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaW, &i, &ret);
2298 ok(hr == S_OK, "got 0x%08x\n", hr);
2299 ok(ret, "got %d\n", ret);
2300 ok(i != (UINT32)-1, "got %u\n", i);
2302 ret = FALSE;
2303 i = (UINT32)-1;
2304 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaUppercaseW, &i, &ret);
2305 ok(hr == S_OK, "got 0x%08x\n", hr);
2306 ok(ret, "got %d\n", ret);
2307 ok(i != (UINT32)-1, "got %u\n", i);
2309 ret = FALSE;
2310 i = (UINT32)-1;
2311 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaStrangecaseW, &i, &ret);
2312 ok(hr == S_OK, "got 0x%08x\n", hr);
2313 ok(ret, "got %d\n", ret);
2314 ok(i != (UINT32)-1, "got %u\n", i);
2316 /* get back local file loader */
2317 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2318 ok(hr == S_OK, "got 0x%08x\n", hr);
2320 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2321 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2322 ok(hr == S_OK, "got 0x%08x\n", hr);
2323 IDWriteFontFamily_Release(family);
2325 hr = IDWriteFont_CreateFontFace(font, &fontface);
2326 ok(hr == S_OK, "got 0x%08x\n", hr);
2327 IDWriteFont_Release(font);
2329 i = 1;
2330 file = NULL;
2331 hr = IDWriteFontFace_GetFiles(fontface, &i, &file);
2332 ok(hr == S_OK, "got 0x%08x\n", hr);
2333 ok(file != NULL, "got %p\n", file);
2334 IDWriteFontFace_Release(fontface);
2336 hr = IDWriteFontFile_GetLoader(file, &loader);
2337 ok(hr == S_OK, "got 0x%08x\n", hr);
2338 IDWriteFontFile_Release(file);
2340 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2341 ok(hr == S_OK, "got 0x%08x\n", hr);
2342 IDWriteLocalFontFileLoader_Release(localloader);
2344 /* local loader is not registered by default */
2345 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
2346 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2347 hr = IDWriteFactory_UnregisterFontFileLoader(factory, loader);
2348 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2350 /* try with a different factory */
2351 factory2 = create_factory();
2352 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2353 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2354 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2355 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2356 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2357 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2358 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2359 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2360 IDWriteFactory_Release(factory2);
2362 IDWriteFontFileLoader_Release(loader);
2364 ret = TRUE;
2365 i = 0;
2366 hr = IDWriteFontCollection_FindFamilyName(collection, blahW, &i, &ret);
2367 ok(hr == S_OK, "got 0x%08x\n", hr);
2368 ok(!ret, "got %d\n", ret);
2369 ok(i == (UINT32)-1, "got %u\n", i);
2371 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection1, (void**)&collection1);
2372 if (hr == S_OK) {
2373 IDWriteFontSet *fontset, *fontset2;
2374 IDWriteFontFamily1 *family1;
2375 IDWriteFactory3 *factory3;
2377 hr = IDWriteFontCollection1_QueryInterface(collection1, &IID_IDWriteFontCollection, (void**)&coll2);
2378 ok(hr == S_OK, "got 0x%08x\n", hr);
2379 ok(coll2 == collection, "got %p, %p\n", collection, coll2);
2380 IDWriteFontCollection_Release(coll2);
2382 family1 = (void*)0xdeadbeef;
2383 hr = IDWriteFontCollection1_GetFontFamily(collection1, ~0u, &family1);
2384 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2385 ok(family1 == NULL, "got %p\n", family1);
2387 hr = IDWriteFontCollection1_GetFontFamily(collection1, 0, &family1);
2388 ok(hr == S_OK, "got 0x%08x\n", hr);
2389 IDWriteFontFamily1_Release(family1);
2391 /* system fontset */
2392 EXPECT_REF(collection1, 2);
2393 EXPECT_REF(factory, 2);
2394 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset);
2395 todo_wine
2396 ok(hr == S_OK, "Failed to get fontset, hr %#x.\n", hr);
2397 if (hr == S_OK) {
2398 EXPECT_REF(collection1, 2);
2399 EXPECT_REF(factory, 2);
2400 EXPECT_REF(fontset, 1);
2402 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset2);
2403 ok(hr == S_OK, "Failed to get fontset, hr %#x.\n", hr);
2404 ok(fontset != fontset2, "Expected new fontset instance.\n");
2405 EXPECT_REF(fontset2, 1);
2406 IDWriteFontSet_Release(fontset2);
2408 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3);
2409 ok(hr == S_OK, "Failed to get IDWriteFactory3 interface, hr %#x.\n", hr);
2411 EXPECT_REF(factory, 3);
2412 hr = IDWriteFactory3_GetSystemFontSet(factory3, &fontset2);
2413 ok(hr == S_OK, "Failed to get system font set, hr %#x.\n", hr);
2414 ok(fontset != fontset2, "Expected new fontset instance.\n");
2415 EXPECT_REF(fontset2, 1);
2416 EXPECT_REF(factory, 4);
2418 IDWriteFontSet_Release(fontset2);
2419 IDWriteFontSet_Release(fontset);
2421 IDWriteFactory3_Release(factory3);
2423 IDWriteFontCollection1_Release(collection1);
2425 else
2426 win_skip("IDWriteFontCollection1 is not supported.\n");
2428 ref = IDWriteFontCollection_Release(collection);
2429 ok(ref == 0, "collection not released, %u\n", ref);
2430 ref = IDWriteFactory_Release(factory);
2431 ok(ref == 0, "factory not released, %u\n", ref);
2434 static void get_logfont_from_font(IDWriteFont *font, LOGFONTW *logfont)
2436 void *os2_context, *head_context;
2437 IDWriteLocalizedStrings *names;
2438 DWRITE_FONT_SIMULATIONS sim;
2439 IDWriteFontFace *fontface;
2440 const TT_OS2_V2 *tt_os2;
2441 DWRITE_FONT_STYLE style;
2442 const TT_HEAD *tt_head;
2443 LONG weight;
2444 UINT32 size;
2445 BOOL exists;
2446 HRESULT hr;
2448 /* These are rendering time properties. */
2449 logfont->lfHeight = 0;
2450 logfont->lfWidth = 0;
2451 logfont->lfEscapement = 0;
2452 logfont->lfOrientation = 0;
2453 logfont->lfUnderline = 0;
2454 logfont->lfStrikeOut = 0;
2456 logfont->lfWeight = 0;
2457 logfont->lfItalic = 0;
2459 hr = IDWriteFont_CreateFontFace(font, &fontface);
2460 ok(hr == S_OK, "Failed to create font face, %#x\n", hr);
2462 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void **)&tt_os2, &size,
2463 &os2_context, &exists);
2464 ok(hr == S_OK, "Failed to get OS/2 table, %#x\n", hr);
2466 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void **)&tt_head, &size,
2467 &head_context, &exists);
2468 ok(hr == S_OK, "Failed to get head table, %#x\n", hr);
2470 sim = IDWriteFont_GetSimulations(font);
2472 /* lfWeight */
2473 weight = FW_REGULAR;
2474 if (tt_os2) {
2475 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
2477 if (usWeightClass >= 1 && usWeightClass <= 9)
2478 usWeightClass *= 100;
2480 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
2481 weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
2482 else if (usWeightClass > 0)
2483 weight = usWeightClass;
2485 else if (tt_head) {
2486 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2487 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
2488 weight = DWRITE_FONT_WEIGHT_BOLD;
2490 if (sim & DWRITE_FONT_SIMULATIONS_BOLD)
2491 weight += (FW_BOLD - FW_REGULAR) / 2 + 1;
2492 logfont->lfWeight = weight;
2494 /* lfItalic */
2495 if (IDWriteFont_GetSimulations(font) & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2496 logfont->lfItalic = 1;
2498 style = IDWriteFont_GetStyle(font);
2499 if (!logfont->lfItalic && ((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE))) {
2500 if (tt_os2) {
2501 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
2502 logfont->lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
2504 else if (tt_head) {
2505 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2506 logfont->lfItalic = !!(macStyle & TT_HEAD_MACSTYLE_ITALIC);
2510 /* lfFaceName */
2511 exists = FALSE;
2512 logfont->lfFaceName[0] = 0;
2513 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &exists);
2514 if (SUCCEEDED(hr)) {
2515 if (exists) {
2516 static const WCHAR enusW[] = {'e','n','-','u','s',0};
2517 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
2518 UINT32 index;
2520 /* Fallback to en-us if there's no string for user locale. */
2521 exists = FALSE;
2522 if (GetSystemDefaultLocaleName(localeW, ARRAY_SIZE(localeW)))
2523 IDWriteLocalizedStrings_FindLocaleName(names, localeW, &index, &exists);
2525 if (!exists)
2526 IDWriteLocalizedStrings_FindLocaleName(names, enusW, &index, &exists);
2528 if (exists)
2529 IDWriteLocalizedStrings_GetString(names, index, logfont->lfFaceName, ARRAY_SIZE(logfont->lfFaceName));
2532 IDWriteLocalizedStrings_Release(names);
2535 if (tt_os2)
2536 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2537 if (tt_head)
2538 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2539 IDWriteFontFace_Release(fontface);
2542 static void test_ConvertFontFaceToLOGFONT(void)
2544 IDWriteFontCollection *collection;
2545 IDWriteGdiInterop *interop;
2546 IDWriteFontFace *fontface;
2547 IDWriteFactory *factory;
2548 LOGFONTW logfont;
2549 UINT32 count, i;
2550 HRESULT hr;
2551 ULONG ref;
2553 factory = create_factory();
2555 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2556 ok(hr == S_OK, "got 0x%08x\n", hr);
2558 if (0) /* crashes on native */
2560 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, NULL);
2561 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, NULL);
2563 memset(&logfont, 0xcc, sizeof(logfont));
2564 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, &logfont);
2565 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2566 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2568 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2569 ok(hr == S_OK, "got 0x%08x\n", hr);
2571 count = IDWriteFontCollection_GetFontFamilyCount(collection);
2572 for (i = 0; i < count; i++) {
2573 WCHAR nameW[128], familynameW[64], facenameW[64];
2574 IDWriteLocalizedStrings *names;
2575 DWRITE_FONT_SIMULATIONS sim;
2576 IDWriteFontFamily *family;
2577 UINT32 font_count, j;
2578 IDWriteFont *font;
2579 LOGFONTW lf;
2581 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2582 ok(hr == S_OK, "got 0x%08x\n", hr);
2584 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2585 ok(hr == S_OK, "got 0x%08x\n", hr);
2587 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
2588 IDWriteLocalizedStrings_Release(names);
2590 font_count = IDWriteFontFamily_GetFontCount(family);
2592 for (j = 0; j < font_count; j++) {
2593 static const WCHAR spaceW[] = {' ', 0};
2594 IDWriteFontFace *fontface;
2596 hr = IDWriteFontFamily_GetFont(family, j, &font);
2597 ok(hr == S_OK, "got 0x%08x\n", hr);
2599 hr = IDWriteFont_GetFaceNames(font, &names);
2600 ok(hr == S_OK, "got 0x%08x\n", hr);
2602 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
2603 IDWriteLocalizedStrings_Release(names);
2605 lstrcpyW(nameW, familynameW);
2606 lstrcatW(nameW, spaceW);
2607 lstrcatW(nameW, facenameW);
2609 hr = IDWriteFont_CreateFontFace(font, &fontface);
2610 ok(hr == S_OK, "got 0x%08x\n", hr);
2612 memset(&logfont, 0xcc, sizeof(logfont));
2613 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, &logfont);
2614 ok(hr == S_OK, "got 0x%08x\n", hr);
2616 sim = IDWriteFontFace_GetSimulations(fontface);
2617 get_logfont_from_font(font, &lf);
2619 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
2620 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
2621 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
2622 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
2623 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
2624 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
2625 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
2627 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
2628 logfont.lfOutPrecision);
2629 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
2630 logfont.lfClipPrecision);
2631 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
2632 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
2633 logfont.lfPitchAndFamily);
2635 IDWriteFontFace_Release(fontface);
2636 IDWriteFont_Release(font);
2639 IDWriteFontFamily_Release(family);
2642 IDWriteFontCollection_Release(collection);
2643 IDWriteGdiInterop_Release(interop);
2644 ref = IDWriteFactory_Release(factory);
2645 ok(ref == 0, "factory not released, %u\n", ref);
2648 static HRESULT WINAPI fontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2650 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
2652 *obj = iface;
2653 IDWriteFontFileEnumerator_AddRef(iface);
2654 return S_OK;
2656 return E_NOINTERFACE;
2659 static ULONG WINAPI fontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2661 return 2;
2664 static ULONG WINAPI fontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2666 return 1;
2669 static HRESULT WINAPI fontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2671 *file = NULL;
2672 return E_FAIL;
2675 static HRESULT WINAPI fontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2677 *current = FALSE;
2678 return S_OK;
2681 static const struct IDWriteFontFileEnumeratorVtbl dwritefontfileenumeratorvtbl =
2683 fontfileenumerator_QueryInterface,
2684 fontfileenumerator_AddRef,
2685 fontfileenumerator_Release,
2686 fontfileenumerator_MoveNext,
2687 fontfileenumerator_GetCurrentFontFile,
2690 struct collection_loader
2692 IDWriteFontCollectionLoader IDWriteFontCollectionLoader_iface;
2693 LONG ref;
2696 static inline struct collection_loader *impl_from_IDWriteFontCollectionLoader(IDWriteFontCollectionLoader *iface)
2698 return CONTAINING_RECORD(iface, struct collection_loader, IDWriteFontCollectionLoader_iface);
2701 static HRESULT WINAPI fontcollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
2703 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2705 if (IsEqualIID(&IID_IDWriteFontCollectionLoader, riid) ||
2706 IsEqualIID(&IID_IUnknown, riid))
2708 *obj = &loader->IDWriteFontCollectionLoader_iface;
2709 IDWriteFontCollectionLoader_AddRef(iface);
2710 return S_OK;
2713 *obj = NULL;
2714 return E_NOINTERFACE;
2717 static ULONG WINAPI fontcollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
2719 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2720 return InterlockedIncrement(&loader->ref);
2723 static ULONG WINAPI fontcollectionloader_Release(IDWriteFontCollectionLoader *iface)
2725 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2726 ULONG ref = InterlockedDecrement(&loader->ref);
2728 if (!ref)
2729 heap_free(loader);
2731 return ref;
2734 static HRESULT WINAPI fontcollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory, const void *key,
2735 UINT32 key_size, IDWriteFontFileEnumerator **ret)
2737 static IDWriteFontFileEnumerator enumerator = { &dwritefontfileenumeratorvtbl };
2738 *ret = &enumerator;
2739 return S_OK;
2742 static const struct IDWriteFontCollectionLoaderVtbl dwritefontcollectionloadervtbl = {
2743 fontcollectionloader_QueryInterface,
2744 fontcollectionloader_AddRef,
2745 fontcollectionloader_Release,
2746 fontcollectionloader_CreateEnumeratorFromKey
2749 static IDWriteFontCollectionLoader *create_collection_loader(void)
2751 struct collection_loader *loader = heap_alloc(sizeof(*loader));
2753 loader->IDWriteFontCollectionLoader_iface.lpVtbl = &dwritefontcollectionloadervtbl;
2754 loader->ref = 1;
2756 return &loader->IDWriteFontCollectionLoader_iface;
2759 static void test_CustomFontCollection(void)
2761 static const WCHAR fontnameW[] = {'w','i','n','e','_','t','e','s','t',0};
2762 IDWriteFontCollectionLoader *loader, *loader2, *loader3;
2763 IDWriteFontCollection *font_collection = NULL;
2764 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
2765 struct test_fontcollectionloader resource_collection = { { &resourcecollectionloadervtbl }, &rloader };
2766 IDWriteFontFamily *family, *family2, *family3;
2767 IDWriteFontFace *idfontface, *idfontface2;
2768 IDWriteFontFile *fontfile, *fontfile2;
2769 IDWriteLocalizedStrings *string;
2770 IDWriteFont *idfont, *idfont2;
2771 IDWriteFactory *factory;
2772 UINT32 index, count;
2773 BOOL exists;
2774 HRESULT hr;
2775 HRSRC font;
2776 ULONG ref;
2778 factory = create_factory();
2780 loader = create_collection_loader();
2781 loader2 = create_collection_loader();
2782 loader3 = create_collection_loader();
2784 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, NULL);
2785 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2787 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, NULL);
2788 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2790 EXPECT_REF(loader, 1);
2791 EXPECT_REF(loader2, 1);
2793 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
2794 ok(hr == S_OK, "got 0x%08x\n", hr);
2795 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader2);
2796 ok(hr == S_OK, "got 0x%08x\n", hr);
2797 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
2798 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2800 EXPECT_REF(loader, 2);
2801 EXPECT_REF(loader2, 2);
2803 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
2804 ok(hr == S_OK, "got 0x%08x\n", hr);
2805 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
2806 ok(hr == S_OK, "got 0x%08x\n", hr);
2808 /* Loader wasn't registered. */
2809 font_collection = (void*)0xdeadbeef;
2810 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader3, "Billy", 6, &font_collection);
2811 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2812 ok(font_collection == NULL, "got %p\n", font_collection);
2814 EXPECT_REF(factory, 1);
2815 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader, "Billy", 6, &font_collection);
2816 ok(hr == S_OK, "got 0x%08x\n", hr);
2817 todo_wine
2818 EXPECT_REF(factory, 1);
2819 EXPECT_REF(loader, 2);
2820 IDWriteFontCollection_Release(font_collection);
2822 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader2, "Billy", 6, &font_collection);
2823 ok(hr == S_OK, "got 0x%08x\n", hr);
2824 IDWriteFontCollection_Release(font_collection);
2826 font_collection = (void*)0xdeadbeef;
2827 hr = IDWriteFactory_CreateCustomFontCollection(factory, (IDWriteFontCollectionLoader*)0xdeadbeef, "Billy", 6, &font_collection);
2828 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2829 ok(font_collection == NULL, "got %p\n", font_collection);
2831 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
2832 ok(font != NULL, "Failed to find font resource\n");
2834 hr = IDWriteFactory_CreateCustomFontCollection(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface,
2835 &font, sizeof(HRSRC), &font_collection);
2836 ok(hr == S_OK, "got 0x%08x\n",hr);
2837 EXPECT_REF(font_collection, 1);
2839 index = 1;
2840 exists = FALSE;
2841 hr = IDWriteFontCollection_FindFamilyName(font_collection, fontnameW, &index, &exists);
2842 ok(hr == S_OK, "got 0x%08x\n", hr);
2843 ok(index == 0, "got index %i\n", index);
2844 ok(exists, "got exists %i\n", exists);
2846 count = IDWriteFontCollection_GetFontFamilyCount(font_collection);
2847 ok(count == 1, "got %u\n", count);
2849 family = NULL;
2850 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family);
2851 ok(hr == S_OK, "got 0x%08x\n", hr);
2852 EXPECT_REF(family, 1);
2854 family2 = NULL;
2855 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family2);
2856 ok(hr == S_OK, "got 0x%08x\n", hr);
2857 EXPECT_REF(family2, 1);
2858 ok(family != family2, "got %p, %p\n", family, family2);
2860 hr = IDWriteFontFamily_GetFont(family, 0, &idfont);
2861 ok(hr == S_OK, "got 0x%08x\n", hr);
2862 EXPECT_REF(idfont, 1);
2863 EXPECT_REF(family, 2);
2864 hr = IDWriteFontFamily_GetFont(family, 0, &idfont2);
2865 ok(hr == S_OK, "got 0x%08x\n", hr);
2866 EXPECT_REF(idfont2, 1);
2867 EXPECT_REF(family, 3);
2868 ok(idfont != idfont2, "got %p, %p\n", idfont, idfont2);
2869 IDWriteFont_Release(idfont2);
2871 hr = IDWriteFont_GetInformationalStrings(idfont, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &string, &exists);
2872 ok(hr == S_OK, "got 0x%08x\n", hr);
2873 ok(exists, "got %d\n", exists);
2874 EXPECT_REF(string, 1);
2875 IDWriteLocalizedStrings_Release(string);
2877 family3 = NULL;
2878 hr = IDWriteFont_GetFontFamily(idfont, &family3);
2879 ok(hr == S_OK, "got 0x%08x\n", hr);
2880 EXPECT_REF(family, 3);
2881 ok(family == family3, "got %p, %p\n", family, family3);
2882 IDWriteFontFamily_Release(family3);
2884 idfontface = NULL;
2885 hr = IDWriteFont_CreateFontFace(idfont, &idfontface);
2886 ok(hr == S_OK, "got 0x%08x\n", hr);
2887 EXPECT_REF(idfont, 1);
2889 idfont2 = NULL;
2890 hr = IDWriteFontFamily_GetFont(family2, 0, &idfont2);
2891 ok(hr == S_OK, "got 0x%08x\n", hr);
2892 EXPECT_REF(idfont2, 1);
2893 EXPECT_REF(idfont, 1);
2894 ok(idfont2 != idfont, "Font instances should not match\n");
2896 idfontface2 = NULL;
2897 hr = IDWriteFont_CreateFontFace(idfont2, &idfontface2);
2898 ok(hr == S_OK, "got 0x%08x\n", hr);
2899 ok(idfontface2 == idfontface, "fontfaces should match\n");
2901 index = 1;
2902 fontfile = NULL;
2903 hr = IDWriteFontFace_GetFiles(idfontface, &index, &fontfile);
2904 ok(hr == S_OK, "got 0x%08x\n", hr);
2906 index = 1;
2907 fontfile2 = NULL;
2908 hr = IDWriteFontFace_GetFiles(idfontface2, &index, &fontfile2);
2909 ok(hr == S_OK, "got 0x%08x\n", hr);
2910 ok(fontfile == fontfile2, "fontfiles should match\n");
2912 IDWriteFont_Release(idfont);
2913 IDWriteFont_Release(idfont2);
2914 IDWriteFontFile_Release(fontfile);
2915 IDWriteFontFile_Release(fontfile2);
2916 IDWriteFontFace_Release(idfontface);
2917 IDWriteFontFace_Release(idfontface2);
2918 IDWriteFontFamily_Release(family2);
2919 IDWriteFontFamily_Release(family);
2920 IDWriteFontCollection_Release(font_collection);
2922 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
2923 ok(hr == S_OK, "got 0x%08x\n", hr);
2924 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
2925 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2926 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader2);
2927 ok(hr == S_OK, "got 0x%08x\n", hr);
2928 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
2929 ok(hr == S_OK, "got 0x%08x\n", hr);
2930 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
2931 ok(hr == S_OK, "got 0x%08x\n", hr);
2933 IDWriteFontCollectionLoader_Release(loader);
2934 IDWriteFontCollectionLoader_Release(loader2);
2935 IDWriteFontCollectionLoader_Release(loader3);
2937 ref = IDWriteFactory_Release(factory);
2938 ok(ref == 0, "factory not released, %u\n", ref);
2941 static HRESULT WINAPI fontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
2943 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
2945 *obj = iface;
2946 IDWriteFontFileLoader_AddRef(iface);
2947 return S_OK;
2950 *obj = NULL;
2951 return E_NOINTERFACE;
2954 static ULONG WINAPI fontfileloader_AddRef(IDWriteFontFileLoader *iface)
2956 return 2;
2959 static ULONG WINAPI fontfileloader_Release(IDWriteFontFileLoader *iface)
2961 return 1;
2964 static HRESULT WINAPI fontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
2965 IDWriteFontFileStream **stream)
2967 return 0x8faecafe;
2970 static const struct IDWriteFontFileLoaderVtbl dwritefontfileloadervtbl = {
2971 fontfileloader_QueryInterface,
2972 fontfileloader_AddRef,
2973 fontfileloader_Release,
2974 fontfileloader_CreateStreamFromKey
2977 static void test_CreateCustomFontFileReference(void)
2979 IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl };
2980 IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl };
2981 IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl };
2982 IDWriteFactory *factory, *factory2;
2983 IDWriteFontFileLoader *loader;
2984 IDWriteFontFile *file, *file2;
2985 BOOL support;
2986 DWRITE_FONT_FILE_TYPE file_type;
2987 DWRITE_FONT_FACE_TYPE face_type;
2988 UINT32 count;
2989 IDWriteFontFace *face, *face2;
2990 HRESULT hr;
2991 HRSRC fontrsrc;
2992 UINT32 codePoints[1] = {0xa8};
2993 UINT16 indices[2];
2994 const void *key;
2995 UINT32 key_size;
2996 WCHAR *path;
2997 ULONG ref;
2999 path = create_testfontfile(test_fontfile);
3001 factory = create_factory();
3002 factory2 = create_factory();
3004 if (0) { /* crashes on win10 */
3005 hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
3006 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3008 /* local loader is accepted too */
3009 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3010 ok(hr == S_OK, "got 0x%08x\n", hr);
3012 hr = IDWriteFontFile_GetLoader(file, &loader);
3013 ok(hr == S_OK, "got 0x%08x\n", hr);
3015 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3016 ok(hr == S_OK, "got 0x%08x\n", hr);
3018 hr = IDWriteFactory_CreateCustomFontFileReference(factory, key, key_size, loader, &file2);
3019 ok(hr == S_OK, "got 0x%08x\n", hr);
3021 IDWriteFontFile_Release(file2);
3022 IDWriteFontFile_Release(file);
3023 IDWriteFontFileLoader_Release(loader);
3025 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3026 ok(hr == S_OK, "got 0x%08x\n", hr);
3027 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader2);
3028 ok(hr == S_OK, "got 0x%08x\n", hr);
3029 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3030 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
3031 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3032 ok(hr == S_OK, "got 0x%08x\n", hr);
3034 file = NULL;
3035 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3036 ok(hr == S_OK, "got 0x%08x\n", hr);
3037 IDWriteFontFile_Release(file);
3039 file = (void*)0xdeadbeef;
3040 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader3, &file);
3041 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3042 ok(file == NULL, "got %p\n", file);
3044 file = (void*)0xdeadbeef;
3045 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, NULL, &file);
3046 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3047 ok(file == NULL, "got %p\n", file);
3049 file = NULL;
3050 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3051 ok(hr == S_OK, "got 0x%08x\n", hr);
3053 file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
3054 face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
3055 support = TRUE;
3056 count = 1;
3057 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3058 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
3059 ok(support == FALSE, "got %i\n", support);
3060 ok(file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN, "got %i\n", file_type);
3061 ok(face_type == DWRITE_FONT_FACE_TYPE_UNKNOWN, "got %i\n", face_type);
3062 ok(count == 0, "got %i\n", count);
3064 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0, &face);
3065 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
3066 IDWriteFontFile_Release(file);
3068 fontrsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3069 ok(fontrsrc != NULL, "Failed to find font resource\n");
3071 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file);
3072 ok(hr == S_OK, "got 0x%08x\n", hr);
3074 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3075 face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3076 support = FALSE;
3077 count = 0;
3078 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3079 ok(hr == S_OK, "got 0x%08x\n", hr);
3080 ok(support == TRUE, "got %i\n", support);
3081 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
3082 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
3083 ok(count == 1, "got %i\n", count);
3085 /* invalid index */
3086 face = (void*)0xdeadbeef;
3087 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 1, DWRITE_FONT_SIMULATIONS_NONE, &face);
3088 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3089 ok(face == NULL, "got %p\n", face);
3091 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
3092 ok(hr == S_OK, "got 0x%08x\n", hr);
3094 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3095 ok(hr == S_OK, "got 0x%08x\n", hr);
3096 /* fontface instances are reused starting with win7 */
3097 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3098 IDWriteFontFace_Release(face2);
3100 /* file was created with different factory */
3101 face2 = NULL;
3102 hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3103 todo_wine
3104 ok(hr == S_OK, "got 0x%08x\n", hr);
3105 if (face2) {
3106 IDWriteFontFace_Release(face2);
3108 file2 = NULL;
3109 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2);
3110 ok(hr == S_OK, "got 0x%08x\n", hr);
3111 ok(file != file2, "got %p, %p\n", file, file2);
3113 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3114 ok(hr == S_OK, "got 0x%08x\n", hr);
3115 /* fontface instances are reused starting with win7 */
3116 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3117 IDWriteFontFace_Release(face2);
3118 IDWriteFontFile_Release(file2);
3120 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, NULL);
3121 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3123 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, NULL);
3124 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3126 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, indices);
3127 ok(hr == S_OK, "got 0x%08x\n", hr);
3129 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, indices);
3130 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3132 indices[0] = indices[1] = 11;
3133 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, indices);
3134 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3135 ok(indices[0] == 0, "got index %i\n", indices[0]);
3136 ok(indices[1] == 11, "got index %i\n", indices[1]);
3138 if (0) /* crashes on native */
3139 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, NULL);
3141 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 1, indices);
3142 ok(hr == S_OK, "got 0x%08x\n", hr);
3143 ok(indices[0] == 7, "Unexpected glyph index, %u.\n", indices[0]);
3144 IDWriteFontFace_Release(face);
3145 IDWriteFontFile_Release(file);
3147 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3148 ok(hr == S_OK, "got 0x%08x\n", hr);
3149 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3150 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3151 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader2);
3152 ok(hr == S_OK, "got 0x%08x\n", hr);
3153 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3154 ok(hr == S_OK, "got 0x%08x\n", hr);
3156 ref = IDWriteFactory_Release(factory2);
3157 ok(ref == 0, "factory not released, %u\n", ref);
3158 ref = IDWriteFactory_Release(factory);
3159 ok(ref == 0, "factory not released, %u\n", ref);
3160 DELETE_FONTFILE(path);
3163 static void test_CreateFontFileReference(void)
3165 HRESULT hr;
3166 IDWriteFontFile *ffile = NULL;
3167 BOOL support;
3168 DWRITE_FONT_FILE_TYPE type;
3169 DWRITE_FONT_FACE_TYPE face;
3170 UINT32 count;
3171 IDWriteFontFace *fface = NULL;
3172 IDWriteFactory *factory;
3173 WCHAR *path;
3174 ULONG ref;
3176 path = create_testfontfile(test_fontfile);
3177 factory = create_factory();
3179 ffile = (void*)0xdeadbeef;
3180 hr = IDWriteFactory_CreateFontFileReference(factory, NULL, NULL, &ffile);
3181 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
3182 ok(ffile == NULL, "got %p\n", ffile);
3184 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &ffile);
3185 ok(hr == S_OK, "got 0x%08x\n",hr);
3187 support = FALSE;
3188 type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3189 face = DWRITE_FONT_FACE_TYPE_CFF;
3190 count = 0;
3191 hr = IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count);
3192 ok(hr == S_OK, "got 0x%08x\n", hr);
3193 ok(support == TRUE, "got %i\n", support);
3194 ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type);
3195 ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face);
3196 ok(count == 1, "got %i\n", count);
3198 hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface);
3199 ok(hr == S_OK, "got 0x%08x\n", hr);
3201 IDWriteFontFace_Release(fface);
3202 IDWriteFontFile_Release(ffile);
3203 ref = IDWriteFactory_Release(factory);
3204 ok(ref == 0, "factory not released, %u\n", ref);
3206 DELETE_FONTFILE(path);
3209 static void test_shared_isolated(void)
3211 IDWriteFactory *isolated, *isolated2;
3212 IDWriteFactory *shared, *shared2;
3213 HRESULT hr;
3214 ULONG ref;
3216 /* invalid type */
3217 shared = NULL;
3218 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&shared);
3219 ok(hr == S_OK, "got 0x%08x\n", hr);
3220 ok(shared != NULL, "got %p\n", shared);
3221 IDWriteFactory_Release(shared);
3223 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared);
3224 ok(hr == S_OK, "got 0x%08x\n", hr);
3226 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3227 ok(hr == S_OK, "got 0x%08x\n", hr);
3228 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3229 IDWriteFactory_Release(shared2);
3231 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IUnknown, (IUnknown**)&shared2);
3232 ok(hr == S_OK, "got 0x%08x\n", hr);
3233 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3235 IDWriteFactory_Release(shared);
3236 IDWriteFactory_Release(shared2);
3238 /* we got 2 references, released 2 - still same pointer is returned */
3239 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3240 ok(hr == S_OK, "got 0x%08x\n", hr);
3241 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3242 IDWriteFactory_Release(shared2);
3244 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated);
3245 ok(hr == S_OK, "got 0x%08x\n", hr);
3247 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3248 ok(hr == S_OK, "got 0x%08x\n", hr);
3249 ok(isolated != isolated2, "got %p, and %p\n", isolated, isolated2);
3250 IDWriteFactory_Release(isolated2);
3252 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IUnknown, (IUnknown**)&isolated2);
3253 ok(hr == S_OK, "got 0x%08x\n", hr);
3254 IDWriteFactory_Release(isolated2);
3256 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3257 ok(hr == S_OK, "got 0x%08x\n", hr);
3258 ok(shared != isolated2, "got %p, and %p\n", shared, isolated2);
3260 ref = IDWriteFactory_Release(isolated);
3261 ok(ref == 0, "factory not released, %u\n", ref);
3262 ref = IDWriteFactory_Release(isolated2);
3263 ok(ref == 0, "factory not released, %u\n", ref);
3266 static void test_GetUnicodeRanges(void)
3268 DWRITE_UNICODE_RANGE *ranges, r;
3269 IDWriteFontFile *ffile = NULL;
3270 IDWriteFontFace1 *fontface1;
3271 IDWriteFontFace *fontface;
3272 IDWriteFactory *factory;
3273 UINT32 count;
3274 HRESULT hr;
3275 HRSRC font;
3276 ULONG ref;
3278 factory = create_factory();
3280 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3281 ok(hr == S_OK, "got 0x%08x\n", hr);
3283 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3284 ok(font != NULL, "Failed to find font resource\n");
3286 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile);
3287 ok(hr == S_OK, "got 0x%08x\n", hr);
3289 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3290 ok(hr == S_OK, "got 0x%08x\n", hr);
3291 IDWriteFontFile_Release(ffile);
3293 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3294 IDWriteFontFace_Release(fontface);
3295 if (hr != S_OK) {
3296 win_skip("GetUnicodeRanges() is not supported.\n");
3297 IDWriteFactory_Release(factory);
3298 return;
3301 count = 0;
3302 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
3303 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3304 ok(count > 0, "got %u\n", count);
3306 count = 1;
3307 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count);
3308 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3309 ok(count == 0, "got %u\n", count);
3311 count = 0;
3312 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count);
3313 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3314 ok(count > 1, "got %u\n", count);
3316 ranges = heap_alloc(count*sizeof(DWRITE_UNICODE_RANGE));
3317 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
3318 ok(hr == S_OK, "got 0x%08x\n", hr);
3320 ranges[0].first = ranges[0].last = 0;
3321 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count);
3322 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3323 ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last);
3325 heap_free(ranges);
3327 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3328 ok(hr == S_OK, "got 0x%08x\n", hr);
3330 IDWriteFontFace1_Release(fontface1);
3331 ref = IDWriteFactory_Release(factory);
3332 ok(ref == 0, "factory not released, %u\n", ref);
3335 static void test_GetFontFromFontFace(void)
3337 IDWriteFontFace *fontface, *fontface2;
3338 IDWriteFontCollection *collection;
3339 IDWriteFont *font, *font2, *font3;
3340 IDWriteFontFamily *family;
3341 IDWriteFactory *factory;
3342 IDWriteFontFile *file;
3343 WCHAR *path;
3344 HRESULT hr;
3345 ULONG ref;
3347 factory = create_factory();
3349 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3350 ok(hr == S_OK, "got 0x%08x\n", hr);
3352 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3353 ok(hr == S_OK, "got 0x%08x\n", hr);
3355 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3356 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3357 ok(hr == S_OK, "got 0x%08x\n", hr);
3359 hr = IDWriteFont_CreateFontFace(font, &fontface);
3360 ok(hr == S_OK, "got 0x%08x\n", hr);
3362 font2 = NULL;
3363 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
3364 ok(hr == S_OK, "got 0x%08x\n", hr);
3365 ok(font2 != font, "got %p, %p\n", font2, font);
3367 font3 = NULL;
3368 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3369 ok(hr == S_OK, "got 0x%08x\n", hr);
3370 ok(font3 != font && font3 != font2, "got %p, %p, %p\n", font3, font2, font);
3372 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
3373 ok(hr == S_OK, "got 0x%08x\n", hr);
3374 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3375 IDWriteFontFace_Release(fontface2);
3377 hr = IDWriteFont_CreateFontFace(font3, &fontface2);
3378 ok(hr == S_OK, "got 0x%08x\n", hr);
3379 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3380 IDWriteFontFace_Release(fontface2);
3381 IDWriteFontFace_Release(fontface);
3382 IDWriteFont_Release(font3);
3383 IDWriteFactory_Release(factory);
3385 /* fontface that wasn't created from this collection */
3386 factory = create_factory();
3387 path = create_testfontfile(test_fontfile);
3389 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3390 ok(hr == S_OK, "got 0x%08x\n",hr);
3392 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3393 ok(hr == S_OK, "got 0x%08x\n", hr);
3394 IDWriteFontFile_Release(file);
3396 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3397 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
3398 ok(font3 == NULL, "got %p\n", font3);
3399 IDWriteFontFace_Release(fontface);
3401 IDWriteFont_Release(font);
3402 IDWriteFont_Release(font2);
3403 IDWriteFontFamily_Release(family);
3404 IDWriteFontCollection_Release(collection);
3405 ref = IDWriteFactory_Release(factory);
3406 ok(ref == 0, "factory not released, %u\n", ref);
3407 DELETE_FONTFILE(path);
3410 static void test_GetFirstMatchingFont(void)
3412 DWRITE_FONT_SIMULATIONS simulations;
3413 IDWriteFontCollection *collection;
3414 IDWriteFontFamily *family;
3415 IDWriteFont *font, *font2;
3416 IDWriteFactory *factory;
3417 HRESULT hr;
3418 ULONG ref;
3420 factory = create_factory();
3422 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3423 ok(hr == S_OK, "got 0x%08x\n", hr);
3425 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3426 ok(hr == S_OK, "got 0x%08x\n", hr);
3428 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3429 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3430 ok(hr == S_OK, "got 0x%08x\n", hr);
3432 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3433 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
3434 ok(hr == S_OK, "got 0x%08x\n", hr);
3435 ok(font != font2, "got %p, %p\n", font, font2);
3436 IDWriteFont_Release(font);
3437 IDWriteFont_Release(font2);
3439 /* out-of-range font props are allowed */
3440 hr = IDWriteFontFamily_GetFirstMatchingFont(family, 1000, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3441 ok(hr == S_OK, "got 0x%08x\n", hr);
3442 IDWriteFont_Release(font);
3444 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, 10, DWRITE_FONT_STYLE_NORMAL, &font);
3445 ok(hr == S_OK, "got 0x%08x\n", hr);
3446 IDWriteFont_Release(font);
3448 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3449 10, &font);
3450 ok(hr == S_OK, "got 0x%08x\n", hr);
3451 IDWriteFont_Release(font);
3453 IDWriteFontFamily_Release(family);
3455 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
3456 simulations = IDWriteFont_GetSimulations(font);
3457 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "%d\n", simulations);
3458 IDWriteFont_Release(font);
3460 IDWriteFontCollection_Release(collection);
3461 ref = IDWriteFactory_Release(factory);
3462 ok(ref == 0, "factory not released, %u\n", ref);
3465 static void test_GetMatchingFonts(void)
3467 IDWriteFontCollection *collection;
3468 IDWriteFontFamily *family;
3469 IDWriteFactory *factory;
3470 IDWriteFontList *fontlist, *fontlist2;
3471 IDWriteFontList1 *fontlist1;
3472 HRESULT hr;
3473 ULONG ref;
3475 factory = create_factory();
3477 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3478 ok(hr == S_OK, "got 0x%08x\n", hr);
3480 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3481 ok(hr == S_OK, "got 0x%08x\n", hr);
3483 /* out-of-range font props are allowed */
3484 hr = IDWriteFontFamily_GetMatchingFonts(family, 1000, DWRITE_FONT_STRETCH_NORMAL,
3485 DWRITE_FONT_STYLE_NORMAL, &fontlist);
3486 ok(hr == S_OK, "got 0x%08x\n", hr);
3487 IDWriteFontList_Release(fontlist);
3489 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, 10,
3490 DWRITE_FONT_STYLE_NORMAL, &fontlist);
3491 ok(hr == S_OK, "got 0x%08x\n", hr);
3492 IDWriteFontList_Release(fontlist);
3494 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3495 10, &fontlist);
3496 ok(hr == S_OK, "got 0x%08x\n", hr);
3497 IDWriteFontList_Release(fontlist);
3499 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
3500 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
3501 ok(hr == S_OK, "got 0x%08x\n", hr);
3503 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
3504 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
3505 ok(hr == S_OK, "got 0x%08x\n", hr);
3506 ok(fontlist != fontlist2, "got %p, %p\n", fontlist, fontlist2);
3507 IDWriteFontList_Release(fontlist2);
3509 hr = IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList1, (void**)&fontlist1);
3510 if (hr == S_OK) {
3511 IDWriteFontFaceReference *ref, *ref1;
3512 IDWriteFont3 *font;
3513 UINT32 count;
3515 count = IDWriteFontList1_GetFontCount(fontlist1);
3516 ok(count > 0, "got %u\n", count);
3518 font = (void*)0xdeadbeef;
3519 hr = IDWriteFontList1_GetFont(fontlist1, ~0u, &font);
3520 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3521 ok(font == NULL, "got %p\n", font);
3523 font = (void*)0xdeadbeef;
3524 hr = IDWriteFontList1_GetFont(fontlist1, count, &font);
3525 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3526 ok(font == NULL, "got %p\n", font);
3528 hr = IDWriteFontList1_GetFont(fontlist1, 0, &font);
3529 ok(hr == S_OK, "got 0x%08x\n", hr);
3530 IDWriteFont3_Release(font);
3532 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref);
3533 ok(hr == S_OK, "got 0x%08x\n", hr);
3535 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref1);
3536 ok(hr == S_OK, "got 0x%08x\n", hr);
3537 ok(ref != ref1, "got %p, %p\n", ref, ref1);
3539 IDWriteFontFaceReference_Release(ref1);
3540 IDWriteFontFaceReference_Release(ref);
3541 IDWriteFontList1_Release(fontlist1);
3543 else
3544 win_skip("IDWriteFontList1 is not supported.\n");
3546 IDWriteFontList_Release(fontlist);
3547 IDWriteFontFamily_Release(family);
3549 IDWriteFontCollection_Release(collection);
3550 ref = IDWriteFactory_Release(factory);
3551 ok(ref == 0, "factory not released, %u\n", ref);
3554 static void test_GetInformationalStrings(void)
3556 IDWriteLocalizedStrings *strings, *strings2;
3557 IDWriteFontCollection *collection;
3558 IDWriteFontFamily *family;
3559 IDWriteFactory *factory;
3560 IDWriteFont *font;
3561 BOOL exists;
3562 HRESULT hr;
3563 ULONG ref;
3565 factory = create_factory();
3567 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3568 ok(hr == S_OK, "got 0x%08x\n", hr);
3570 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3571 ok(hr == S_OK, "got 0x%08x\n", hr);
3573 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3574 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3575 ok(hr == S_OK, "got 0x%08x\n", hr);
3577 exists = TRUE;
3578 strings = (void*)0xdeadbeef;
3579 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1, &strings, &exists);
3580 ok(hr == S_OK, "got 0x%08x\n", hr);
3581 ok(exists == FALSE, "got %d\n", exists);
3582 ok(strings == NULL, "got %p\n", strings);
3584 exists = TRUE;
3585 strings = NULL;
3586 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists);
3587 ok(hr == S_OK, "got 0x%08x\n", hr);
3588 ok(exists == FALSE, "got %d\n", exists);
3590 exists = FALSE;
3591 strings = NULL;
3592 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
3593 ok(hr == S_OK, "got 0x%08x\n", hr);
3594 ok(exists == TRUE, "got %d\n", exists);
3596 /* strings instance is not reused */
3597 strings2 = NULL;
3598 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings2, &exists);
3599 ok(hr == S_OK, "got 0x%08x\n", hr);
3600 ok(strings2 != strings, "got %p, %p\n", strings2, strings);
3602 IDWriteLocalizedStrings_Release(strings);
3603 IDWriteLocalizedStrings_Release(strings2);
3604 IDWriteFont_Release(font);
3605 IDWriteFontFamily_Release(family);
3606 IDWriteFontCollection_Release(collection);
3607 ref = IDWriteFactory_Release(factory);
3608 ok(ref == 0, "factory not released, %u\n", ref);
3611 static void test_GetGdiInterop(void)
3613 IDWriteGdiInterop *interop, *interop2;
3614 IDWriteFactory *factory, *factory2;
3615 IDWriteFont *font;
3616 LOGFONTW logfont;
3617 HRESULT hr;
3618 ULONG ref;
3620 factory = create_factory();
3622 interop = NULL;
3623 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3624 ok(hr == S_OK, "got 0x%08x\n", hr);
3626 interop2 = NULL;
3627 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
3628 ok(hr == S_OK, "got 0x%08x\n", hr);
3629 ok(interop == interop2, "got %p, %p\n", interop, interop2);
3630 IDWriteGdiInterop_Release(interop2);
3632 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory2);
3633 ok(hr == S_OK, "got 0x%08x\n", hr);
3635 /* each factory gets its own interop */
3636 interop2 = NULL;
3637 hr = IDWriteFactory_GetGdiInterop(factory2, &interop2);
3638 ok(hr == S_OK, "got 0x%08x\n", hr);
3639 ok(interop != interop2, "got %p, %p\n", interop, interop2);
3641 /* release factory - interop still works */
3642 IDWriteFactory_Release(factory2);
3644 memset(&logfont, 0, sizeof(logfont));
3645 logfont.lfHeight = 12;
3646 logfont.lfWidth = 12;
3647 logfont.lfWeight = FW_NORMAL;
3648 logfont.lfItalic = 1;
3649 lstrcpyW(logfont.lfFaceName, tahomaW);
3651 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop2, &logfont, &font);
3652 ok(hr == S_OK, "got 0x%08x\n", hr);
3653 IDWriteFont_Release(font);
3655 IDWriteGdiInterop_Release(interop2);
3656 IDWriteGdiInterop_Release(interop);
3657 ref = IDWriteFactory_Release(factory);
3658 ok(ref == 0, "factory not released, %u\n", ref);
3661 static void test_CreateFontFaceFromHdc(void)
3663 IDWriteGdiInterop *interop;
3664 IDWriteFontFace *fontface;
3665 IDWriteFactory *factory;
3666 HFONT hfont, oldhfont;
3667 LOGFONTW logfont;
3668 LOGFONTA lf;
3669 HRESULT hr;
3670 ULONG ref;
3671 HDC hdc;
3673 factory = create_factory();
3675 interop = NULL;
3676 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3677 ok(hr == S_OK, "got 0x%08x\n", hr);
3679 /* Invalid HDC. */
3680 fontface = (void*)0xdeadbeef;
3681 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, NULL, &fontface);
3682 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3683 ok(fontface == NULL, "got %p\n", fontface);
3685 fontface = (void *)0xdeadbeef;
3686 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, (HDC)0xdeadbeef, &fontface);
3687 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3688 ok(fontface == NULL, "got %p\n", fontface);
3690 memset(&logfont, 0, sizeof(logfont));
3691 logfont.lfHeight = 12;
3692 logfont.lfWidth = 12;
3693 logfont.lfWeight = FW_NORMAL;
3694 logfont.lfItalic = 1;
3695 lstrcpyW(logfont.lfFaceName, tahomaW);
3697 hfont = CreateFontIndirectW(&logfont);
3698 hdc = CreateCompatibleDC(0);
3699 oldhfont = SelectObject(hdc, hfont);
3701 fontface = NULL;
3702 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
3703 ok(hr == S_OK, "got 0x%08x\n", hr);
3704 IDWriteFontFace_Release(fontface);
3705 DeleteObject(SelectObject(hdc, oldhfont));
3707 /* Select bitmap font MS Sans Serif, format that's not supported by DirectWrite. */
3708 memset(&lf, 0, sizeof(lf));
3709 lf.lfHeight = -12;
3710 strcpy(lf.lfFaceName, "MS Sans Serif");
3712 hfont = CreateFontIndirectA(&lf);
3713 oldhfont = SelectObject(hdc, hfont);
3715 fontface = (void *)0xdeadbeef;
3716 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
3717 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* Vista */, "got 0x%08x\n", hr);
3718 ok(fontface == NULL, "got %p\n", fontface);
3720 DeleteObject(SelectObject(hdc, oldhfont));
3721 DeleteDC(hdc);
3723 IDWriteGdiInterop_Release(interop);
3724 ref = IDWriteFactory_Release(factory);
3725 ok(ref == 0, "factory not released, %u\n", ref);
3728 static void test_GetSimulations(void)
3730 DWRITE_FONT_SIMULATIONS simulations;
3731 IDWriteGdiInterop *interop;
3732 IDWriteFontFace *fontface;
3733 IDWriteFactory *factory;
3734 IDWriteFont *font;
3735 LOGFONTW logfont;
3736 HRESULT hr;
3737 ULONG ref;
3739 factory = create_factory();
3741 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3742 ok(hr == S_OK, "got 0x%08x\n", hr);
3744 memset(&logfont, 0, sizeof(logfont));
3745 logfont.lfHeight = 12;
3746 logfont.lfWidth = 12;
3747 logfont.lfWeight = FW_NORMAL;
3748 logfont.lfItalic = 1;
3749 lstrcpyW(logfont.lfFaceName, tahomaW);
3751 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3752 ok(hr == S_OK, "got 0x%08x\n", hr);
3754 simulations = IDWriteFont_GetSimulations(font);
3755 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
3756 hr = IDWriteFont_CreateFontFace(font, &fontface);
3757 ok(hr == S_OK, "got 0x%08x\n", hr);
3758 simulations = IDWriteFontFace_GetSimulations(fontface);
3759 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
3760 IDWriteFontFace_Release(fontface);
3761 IDWriteFont_Release(font);
3763 memset(&logfont, 0, sizeof(logfont));
3764 logfont.lfHeight = 12;
3765 logfont.lfWidth = 12;
3766 logfont.lfWeight = FW_NORMAL;
3767 logfont.lfItalic = 0;
3768 lstrcpyW(logfont.lfFaceName, tahomaW);
3770 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3771 ok(hr == S_OK, "got 0x%08x\n", hr);
3773 simulations = IDWriteFont_GetSimulations(font);
3774 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
3775 hr = IDWriteFont_CreateFontFace(font, &fontface);
3776 ok(hr == S_OK, "got 0x%08x\n", hr);
3777 simulations = IDWriteFontFace_GetSimulations(fontface);
3778 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
3779 IDWriteFontFace_Release(fontface);
3780 IDWriteFont_Release(font);
3782 IDWriteGdiInterop_Release(interop);
3783 ref = IDWriteFactory_Release(factory);
3784 ok(ref == 0, "factory not released, %u\n", ref);
3787 static void test_GetFaceNames(void)
3789 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
3790 static const WCHAR enus2W[] = {'e','n','-','U','s',0};
3791 static const WCHAR enusW[] = {'e','n','-','u','s',0};
3792 IDWriteLocalizedStrings *strings, *strings2;
3793 IDWriteGdiInterop *interop;
3794 IDWriteFactory *factory;
3795 UINT32 count, index;
3796 IDWriteFont *font;
3797 LOGFONTW logfont;
3798 WCHAR buffW[255];
3799 BOOL exists;
3800 HRESULT hr;
3801 ULONG ref;
3803 factory = create_factory();
3805 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3806 ok(hr == S_OK, "got 0x%08x\n", hr);
3808 memset(&logfont, 0, sizeof(logfont));
3809 logfont.lfHeight = 12;
3810 logfont.lfWidth = 12;
3811 logfont.lfWeight = FW_NORMAL;
3812 logfont.lfItalic = 1;
3813 lstrcpyW(logfont.lfFaceName, tahomaW);
3815 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3816 ok(hr == S_OK, "got 0x%08x\n", hr);
3818 hr = IDWriteFont_GetFaceNames(font, &strings);
3819 ok(hr == S_OK, "got 0x%08x\n", hr);
3821 hr = IDWriteFont_GetFaceNames(font, &strings2);
3822 ok(hr == S_OK, "got 0x%08x\n", hr);
3823 ok(strings != strings2, "got %p, %p\n", strings2, strings);
3824 IDWriteLocalizedStrings_Release(strings2);
3826 count = IDWriteLocalizedStrings_GetCount(strings);
3827 ok(count == 1, "got %d\n", count);
3829 index = 1;
3830 exists = FALSE;
3831 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enus2W, &index, &exists);
3832 ok(hr == S_OK, "got 0x%08x\n", hr);
3833 ok(index == 0 && exists, "got %d, %d\n", index, exists);
3835 count = 0;
3836 hr = IDWriteLocalizedStrings_GetLocaleNameLength(strings, 1, &count);
3837 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3838 ok(count == ~0, "got %d\n", count);
3840 /* for simulated faces names are also simulated */
3841 buffW[0] = 0;
3842 hr = IDWriteLocalizedStrings_GetLocaleName(strings, 0, buffW, ARRAY_SIZE(buffW));
3843 ok(hr == S_OK, "got 0x%08x\n", hr);
3844 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
3846 buffW[0] = 0;
3847 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
3848 ok(hr == S_OK, "got 0x%08x\n", hr);
3849 ok(!lstrcmpW(buffW, obliqueW), "got %s\n", wine_dbgstr_w(buffW));
3850 IDWriteLocalizedStrings_Release(strings);
3852 IDWriteFont_Release(font);
3853 IDWriteGdiInterop_Release(interop);
3854 ref = IDWriteFactory_Release(factory);
3855 ok(ref == 0, "factory not released, %u\n", ref);
3858 struct local_refkey
3860 FILETIME writetime;
3861 WCHAR name[1];
3864 static void test_TryGetFontTable(void)
3866 IDWriteLocalFontFileLoader *localloader;
3867 WIN32_FILE_ATTRIBUTE_DATA info;
3868 const struct local_refkey *key;
3869 IDWriteFontFileLoader *loader;
3870 const void *table, *table2;
3871 IDWriteFontFace *fontface;
3872 void *context, *context2;
3873 IDWriteFactory *factory;
3874 IDWriteFontFile *file;
3875 WCHAR buffW[MAX_PATH];
3876 BOOL exists, ret;
3877 UINT32 size, len;
3878 WCHAR *path;
3879 HRESULT hr;
3880 ULONG ref;
3882 path = create_testfontfile(test_fontfile);
3884 factory = create_factory();
3886 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3887 ok(hr == S_OK, "got 0x%08x\n",hr);
3889 key = NULL;
3890 size = 0;
3891 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
3892 ok(hr == S_OK, "got 0x%08x\n", hr);
3893 ok(size != 0, "got %u\n", size);
3895 ret = GetFileAttributesExW(path, GetFileExInfoStandard, &info);
3896 ok(ret, "got %d\n", ret);
3897 ok(!memcmp(&info.ftLastWriteTime, &key->writetime, sizeof(key->writetime)), "got wrong write time\n");
3899 hr = IDWriteFontFile_GetLoader(file, &loader);
3900 ok(hr == S_OK, "got 0x%08x\n", hr);
3901 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
3902 IDWriteFontFileLoader_Release(loader);
3904 hr = IDWriteLocalFontFileLoader_GetFilePathLengthFromKey(localloader, key, size, &len);
3905 ok(hr == S_OK, "got 0x%08x\n", hr);
3906 ok(lstrlenW(key->name) == len, "path length %d\n", len);
3908 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, size, buffW, ARRAY_SIZE(buffW));
3909 ok(hr == S_OK, "got 0x%08x\n", hr);
3910 ok(!lstrcmpW(buffW, key->name), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(key->name));
3911 IDWriteLocalFontFileLoader_Release(localloader);
3913 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, 0, &fontface);
3914 ok(hr == S_OK, "got 0x%08x\n",hr);
3916 exists = FALSE;
3917 context = (void*)0xdeadbeef;
3918 table = NULL;
3919 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table, &size, &context, &exists);
3920 ok(hr == S_OK, "got 0x%08x\n",hr);
3921 ok(exists == TRUE, "got %d\n", exists);
3922 ok(context == NULL && table != NULL, "cmap: context %p, table %p\n", context, table);
3924 exists = FALSE;
3925 context2 = (void*)0xdeadbeef;
3926 table2 = NULL;
3927 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table2, &size, &context2, &exists);
3928 ok(hr == S_OK, "got 0x%08x\n",hr);
3929 ok(exists == TRUE, "got %d\n", exists);
3930 ok(context2 == context && table2 == table, "cmap: context2 %p, table2 %p\n", context2, table2);
3932 IDWriteFontFace_ReleaseFontTable(fontface, context2);
3933 IDWriteFontFace_ReleaseFontTable(fontface, context);
3935 /* table does not exist */
3936 exists = TRUE;
3937 context = (void*)0xdeadbeef;
3938 table = (void*)0xdeadbeef;
3939 hr = IDWriteFontFace_TryGetFontTable(fontface, 0xabababab, &table, &size, &context, &exists);
3940 ok(hr == S_OK, "got 0x%08x\n", hr);
3941 ok(exists == FALSE, "got %d\n", exists);
3942 ok(context == NULL && table == NULL, "got context %p, table pointer %p\n", context, table);
3944 IDWriteFontFace_Release(fontface);
3945 IDWriteFontFile_Release(file);
3946 ref = IDWriteFactory_Release(factory);
3947 ok(ref == 0, "factory not released, %u\n", ref);
3948 DELETE_FONTFILE(path);
3951 static void test_ConvertFontToLOGFONT(void)
3953 IDWriteFactory *factory, *factory2;
3954 IDWriteFontCollection *collection;
3955 IDWriteGdiInterop *interop;
3956 IDWriteFontFamily *family;
3957 IDWriteFont *font;
3958 LOGFONTW logfont;
3959 UINT32 i, count;
3960 BOOL system;
3961 HRESULT hr;
3962 ULONG ref;
3964 factory = create_factory();
3965 factory2 = create_factory();
3967 interop = NULL;
3968 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3969 ok(hr == S_OK, "got 0x%08x\n", hr);
3971 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection, FALSE);
3972 ok(hr == S_OK, "got 0x%08x\n", hr);
3974 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3975 ok(hr == S_OK, "got 0x%08x\n", hr);
3977 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3978 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3979 ok(hr == S_OK, "got 0x%08x\n", hr);
3981 if (0) { /* crashes on native */
3982 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, NULL, NULL);
3983 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, NULL);
3984 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, NULL, &system);
3987 memset(&logfont, 0xcc, sizeof(logfont));
3988 system = TRUE;
3989 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, &system);
3990 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3991 ok(!system, "got %d\n", system);
3992 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
3994 count = IDWriteFontCollection_GetFontFamilyCount(collection);
3995 for (i = 0; i < count; i++) {
3996 WCHAR nameW[128], familynameW[64], facenameW[64];
3997 IDWriteLocalizedStrings *names;
3998 DWRITE_FONT_SIMULATIONS sim;
3999 IDWriteFontFamily *family;
4000 UINT32 font_count, j;
4001 IDWriteFont *font;
4002 LOGFONTW lf;
4004 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
4005 ok(hr == S_OK, "got 0x%08x\n", hr);
4007 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
4008 ok(hr == S_OK, "got 0x%08x\n", hr);
4010 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
4011 IDWriteLocalizedStrings_Release(names);
4013 font_count = IDWriteFontFamily_GetFontCount(family);
4015 for (j = 0; j < font_count; j++) {
4016 static const WCHAR spaceW[] = {' ', 0};
4018 hr = IDWriteFontFamily_GetFont(family, j, &font);
4019 ok(hr == S_OK, "got 0x%08x\n", hr);
4021 hr = IDWriteFont_GetFaceNames(font, &names);
4022 ok(hr == S_OK, "got 0x%08x\n", hr);
4024 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
4025 IDWriteLocalizedStrings_Release(names);
4027 lstrcpyW(nameW, familynameW);
4028 lstrcatW(nameW, spaceW);
4029 lstrcatW(nameW, facenameW);
4031 system = FALSE;
4032 memset(&logfont, 0xcc, sizeof(logfont));
4033 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, &logfont, &system);
4034 ok(hr == S_OK, "got 0x%08x\n", hr);
4035 ok(system, "got %d\n", system);
4037 sim = IDWriteFont_GetSimulations(font);
4039 get_logfont_from_font(font, &lf);
4040 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
4041 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
4042 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
4043 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
4044 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
4045 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
4046 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
4048 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
4049 logfont.lfOutPrecision);
4050 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
4051 logfont.lfClipPrecision);
4052 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
4053 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
4054 logfont.lfPitchAndFamily);
4056 IDWriteFont_Release(font);
4059 IDWriteFontFamily_Release(family);
4062 IDWriteFactory_Release(factory2);
4064 IDWriteFontCollection_Release(collection);
4065 IDWriteFontFamily_Release(family);
4066 IDWriteFont_Release(font);
4067 IDWriteGdiInterop_Release(interop);
4068 ref = IDWriteFactory_Release(factory);
4069 ok(ref == 0, "factory not released, %u\n", ref);
4072 static void test_CreateStreamFromKey(void)
4074 IDWriteLocalFontFileLoader *localloader;
4075 IDWriteFontFileStream *stream, *stream2;
4076 IDWriteFontFileLoader *loader;
4077 IDWriteFactory *factory;
4078 IDWriteFontFile *file;
4079 UINT64 writetime;
4080 WCHAR *path;
4081 void *key;
4082 UINT32 size;
4083 HRESULT hr;
4084 ULONG ref;
4086 factory = create_factory();
4088 path = create_testfontfile(test_fontfile);
4090 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4091 ok(hr == S_OK, "got 0x%08x\n",hr);
4093 key = NULL;
4094 size = 0;
4095 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4096 ok(hr == S_OK, "got 0x%08x\n", hr);
4097 ok(size != 0, "got %u\n", size);
4099 hr = IDWriteFontFile_GetLoader(file, &loader);
4100 ok(hr == S_OK, "got 0x%08x\n", hr);
4101 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4102 IDWriteFontFileLoader_Release(loader);
4104 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4105 ok(hr == S_OK, "got 0x%08x\n", hr);
4106 EXPECT_REF(stream, 1);
4108 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2);
4109 ok(hr == S_OK, "got 0x%08x\n", hr);
4110 ok(stream == stream2 || broken(stream != stream2) /* Win7 SP0 */, "got %p, %p\n", stream, stream2);
4111 if (stream == stream2)
4112 EXPECT_REF(stream, 2);
4113 IDWriteFontFileStream_Release(stream);
4114 IDWriteFontFileStream_Release(stream2);
4116 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4117 ok(hr == S_OK, "got 0x%08x\n", hr);
4118 EXPECT_REF(stream, 1);
4120 writetime = 0;
4121 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4122 ok(hr == S_OK, "got 0x%08x\n", hr);
4123 ok(writetime != 0, "got %s\n", wine_dbgstr_longlong(writetime));
4125 IDWriteFontFileStream_Release(stream);
4126 IDWriteFontFile_Release(file);
4128 IDWriteLocalFontFileLoader_Release(localloader);
4129 ref = IDWriteFactory_Release(factory);
4130 ok(ref == 0, "factory not released, %u\n", ref);
4131 DELETE_FONTFILE(path);
4134 static void test_ReadFileFragment(void)
4136 IDWriteLocalFontFileLoader *localloader;
4137 IDWriteFontFileStream *stream;
4138 IDWriteFontFileLoader *loader;
4139 IDWriteFactory *factory;
4140 IDWriteFontFile *file;
4141 const void *fragment, *fragment2;
4142 void *key, *context, *context2;
4143 UINT64 filesize;
4144 UINT32 size;
4145 WCHAR *path;
4146 HRESULT hr;
4147 ULONG ref;
4149 factory = create_factory();
4151 path = create_testfontfile(test_fontfile);
4153 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4154 ok(hr == S_OK, "got 0x%08x\n",hr);
4156 key = NULL;
4157 size = 0;
4158 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4159 ok(hr == S_OK, "got 0x%08x\n", hr);
4160 ok(size != 0, "got %u\n", size);
4162 hr = IDWriteFontFile_GetLoader(file, &loader);
4163 ok(hr == S_OK, "got 0x%08x\n", hr);
4164 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4165 IDWriteFontFileLoader_Release(loader);
4167 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4168 ok(hr == S_OK, "got 0x%08x\n", hr);
4170 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
4171 ok(hr == S_OK, "got 0x%08x\n", hr);
4173 /* reading past the end of the stream */
4174 fragment = (void*)0xdeadbeef;
4175 context = (void*)0xdeadbeef;
4176 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize+1, &context);
4177 ok(hr == E_FAIL, "got 0x%08x\n", hr);
4178 ok(context == NULL, "got %p\n", context);
4179 ok(fragment == NULL, "got %p\n", fragment);
4181 fragment = (void*)0xdeadbeef;
4182 context = (void*)0xdeadbeef;
4183 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
4184 ok(hr == S_OK, "got 0x%08x\n", hr);
4185 ok(context == NULL, "got %p\n", context);
4186 ok(fragment != NULL, "got %p\n", fragment);
4188 fragment2 = (void*)0xdeadbeef;
4189 context2 = (void*)0xdeadbeef;
4190 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment2, 0, filesize, &context2);
4191 ok(hr == S_OK, "got 0x%08x\n", hr);
4192 ok(context2 == NULL, "got %p\n", context2);
4193 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
4195 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
4196 IDWriteFontFileStream_ReleaseFileFragment(stream, context2);
4198 /* fragment is released, try again */
4199 fragment = (void*)0xdeadbeef;
4200 context = (void*)0xdeadbeef;
4201 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
4202 ok(hr == S_OK, "got 0x%08x\n", hr);
4203 ok(context == NULL, "got %p\n", context);
4204 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
4205 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
4207 IDWriteFontFile_Release(file);
4208 IDWriteFontFileStream_Release(stream);
4209 IDWriteLocalFontFileLoader_Release(localloader);
4210 ref = IDWriteFactory_Release(factory);
4211 ok(ref == 0, "factory not released, %u\n", ref);
4212 DELETE_FONTFILE(path);
4215 static void test_GetDesignGlyphMetrics(void)
4217 DWRITE_GLYPH_METRICS metrics[2];
4218 IDWriteFontFace *fontface;
4219 IDWriteFactory *factory;
4220 IDWriteFontFile *file;
4221 UINT16 indices[2];
4222 UINT32 codepoint;
4223 WCHAR *path;
4224 HRESULT hr;
4225 ULONG ref;
4227 factory = create_factory();
4229 path = create_testfontfile(test_fontfile);
4231 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4232 ok(hr == S_OK, "got 0x%08x\n",hr);
4234 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
4235 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4236 ok(hr == S_OK, "got 0x%08x\n",hr);
4237 IDWriteFontFile_Release(file);
4239 codepoint = 'A';
4240 indices[0] = 0;
4241 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &indices[0]);
4242 ok(hr == S_OK, "got 0x%08x\n", hr);
4243 ok(indices[0] > 0, "got %u\n", indices[0]);
4245 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 0, metrics, FALSE);
4246 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
4248 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 1, metrics, FALSE);
4249 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
4251 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 0, metrics, FALSE);
4252 ok(hr == S_OK, "got 0x%08x\n",hr);
4254 /* missing glyphs are ignored */
4255 indices[1] = 1;
4256 memset(metrics, 0xcc, sizeof(metrics));
4257 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 2, metrics, FALSE);
4258 ok(hr == S_OK, "got 0x%08x\n",hr);
4259 ok(metrics[0].advanceWidth == 1000, "got %d\n", metrics[0].advanceWidth);
4260 ok(metrics[1].advanceWidth == 0, "got %d\n", metrics[1].advanceWidth);
4262 IDWriteFontFace_Release(fontface);
4263 ref = IDWriteFactory_Release(factory);
4264 ok(ref == 0, "factory not released, %u\n", ref);
4265 DELETE_FONTFILE(path);
4268 static void test_IsMonospacedFont(void)
4270 static const WCHAR courierW[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
4271 IDWriteFontCollection *collection;
4272 IDWriteFactory *factory;
4273 UINT32 index;
4274 BOOL exists;
4275 HRESULT hr;
4276 ULONG ref;
4278 factory = create_factory();
4279 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4280 ok(hr == S_OK, "got 0x%08x\n", hr);
4282 exists = FALSE;
4283 hr = IDWriteFontCollection_FindFamilyName(collection, courierW, &index, &exists);
4284 ok(hr == S_OK, "got 0x%08x\n", hr);
4285 if (exists) {
4286 IDWriteFontFamily *family;
4287 IDWriteFont1 *font1;
4288 IDWriteFont *font;
4290 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
4291 ok(hr == S_OK, "got 0x%08x\n", hr);
4293 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4294 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4295 ok(hr == S_OK, "got 0x%08x\n", hr);
4296 IDWriteFontFamily_Release(family);
4298 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
4299 if (hr == S_OK) {
4300 IDWriteFontFace1 *fontface1;
4301 IDWriteFontFace *fontface;
4302 BOOL is_monospaced;
4304 is_monospaced = IDWriteFont1_IsMonospacedFont(font1);
4305 ok(is_monospaced, "got %d\n", is_monospaced);
4307 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
4308 ok(hr == S_OK, "got 0x%08x\n", hr);
4309 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4310 ok(hr == S_OK, "got 0x%08x\n", hr);
4311 is_monospaced = IDWriteFontFace1_IsMonospacedFont(fontface1);
4312 ok(is_monospaced, "got %d\n", is_monospaced);
4313 IDWriteFontFace1_Release(fontface1);
4315 IDWriteFontFace_Release(fontface);
4316 IDWriteFont1_Release(font1);
4318 else
4319 win_skip("IsMonospacedFont() is not supported.\n");
4321 IDWriteFont_Release(font);
4323 else
4324 skip("Courier New font not found.\n");
4326 ref = IDWriteFontCollection_Release(collection);
4327 ok(ref == 0, "factory not released, %u\n", ref);
4330 static void test_GetDesignGlyphAdvances(void)
4332 IDWriteFontFace1 *fontface1;
4333 IDWriteFontFace *fontface;
4334 IDWriteFactory *factory;
4335 IDWriteFontFile *file;
4336 WCHAR *path;
4337 HRESULT hr;
4338 ULONG ref;
4340 factory = create_factory();
4342 path = create_testfontfile(test_fontfile);
4344 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4345 ok(hr == S_OK, "got 0x%08x\n", hr);
4347 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
4348 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4349 ok(hr == S_OK, "got 0x%08x\n", hr);
4350 IDWriteFontFile_Release(file);
4352 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4353 if (hr == S_OK) {
4354 UINT32 codepoint;
4355 UINT16 index;
4356 INT32 advance;
4358 codepoint = 'A';
4359 index = 0;
4360 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &index);
4361 ok(hr == S_OK, "got 0x%08x\n", hr);
4362 ok(index > 0, "got %u\n", index);
4364 advance = 0;
4365 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, FALSE);
4366 ok(hr == S_OK, "got 0x%08x\n", hr);
4367 ok(advance == 1000, "got %i\n", advance);
4369 advance = 0;
4370 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, TRUE);
4371 ok(hr == S_OK, "got 0x%08x\n", hr);
4372 todo_wine
4373 ok(advance == 2048, "got %i\n", advance);
4375 IDWriteFontFace1_Release(fontface1);
4377 else
4378 win_skip("GetDesignGlyphAdvances() is not supported.\n");
4380 IDWriteFontFace_Release(fontface);
4381 ref = IDWriteFactory_Release(factory);
4382 ok(ref == 0, "factory not released, %u\n", ref);
4383 DELETE_FONTFILE(path);
4386 static void test_GetGlyphRunOutline(void)
4388 DWRITE_GLYPH_OFFSET offsets[2];
4389 IDWriteFactory *factory;
4390 IDWriteFontFile *file;
4391 IDWriteFontFace *face;
4392 UINT32 codepoint;
4393 FLOAT advances[2];
4394 UINT16 glyphs[2];
4395 WCHAR *path;
4396 HRESULT hr;
4397 ULONG ref;
4399 path = create_testfontfile(test_fontfile);
4400 factory = create_factory();
4402 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4403 ok(hr == S_OK, "got 0x%08x\n",hr);
4405 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
4406 ok(hr == S_OK, "got 0x%08x\n", hr);
4407 IDWriteFontFile_Release(file);
4409 codepoint = 'A';
4410 glyphs[0] = 0;
4411 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4412 ok(hr == S_OK, "got 0x%08x\n", hr);
4413 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4414 glyphs[1] = glyphs[0];
4416 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, glyphs, advances, offsets, 1, FALSE, FALSE, NULL);
4417 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4419 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, NULL, NULL, offsets, 1, FALSE, FALSE, &test_geomsink);
4420 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4422 advances[0] = 1.0;
4423 advances[1] = 0.0;
4425 offsets[0].advanceOffset = 1.0;
4426 offsets[0].ascenderOffset = 1.0;
4427 offsets[1].advanceOffset = 0.0;
4428 offsets[1].ascenderOffset = 0.0;
4430 /* default advances, no offsets */
4431 memset(g_startpoints, 0, sizeof(g_startpoints));
4432 g_startpoint_count = 0;
4433 SET_EXPECT(setfillmode);
4434 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, FALSE, &test_geomsink);
4435 ok(hr == S_OK, "got 0x%08x\n", hr);
4436 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4437 if (g_startpoint_count == 2) {
4438 /* glyph advance of 500 is applied */
4439 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);
4440 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);
4442 CHECK_CALLED(setfillmode);
4444 /* default advances, no offsets, RTL */
4445 memset(g_startpoints, 0, sizeof(g_startpoints));
4446 g_startpoint_count = 0;
4447 SET_EXPECT(setfillmode);
4448 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, TRUE, &test_geomsink);
4449 ok(hr == S_OK, "got 0x%08x\n", hr);
4450 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4451 if (g_startpoint_count == 2) {
4452 /* advance is -500 now */
4453 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);
4454 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);
4456 CHECK_CALLED(setfillmode);
4458 /* default advances, additional offsets */
4459 memset(g_startpoints, 0, sizeof(g_startpoints));
4460 g_startpoint_count = 0;
4461 SET_EXPECT(setfillmode);
4462 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, FALSE, &test_geomsink);
4463 ok(hr == S_OK, "got 0x%08x\n", hr);
4464 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4465 if (g_startpoint_count == 2) {
4466 /* offsets applied to first contour */
4467 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);
4468 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);
4470 CHECK_CALLED(setfillmode);
4472 /* default advances, additional offsets, RTL */
4473 memset(g_startpoints, 0, sizeof(g_startpoints));
4474 g_startpoint_count = 0;
4475 SET_EXPECT(setfillmode);
4476 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, TRUE, &test_geomsink);
4477 ok(hr == S_OK, "got 0x%08x\n", hr);
4478 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4479 if (g_startpoint_count == 2) {
4480 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);
4481 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);
4483 CHECK_CALLED(setfillmode);
4485 /* custom advances and offsets, offset turns total advance value to zero */
4486 memset(g_startpoints, 0, sizeof(g_startpoints));
4487 g_startpoint_count = 0;
4488 SET_EXPECT(setfillmode);
4489 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, advances, offsets, 2, FALSE, FALSE, &test_geomsink);
4490 ok(hr == S_OK, "got 0x%08x\n", hr);
4491 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4492 if (g_startpoint_count == 2) {
4493 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);
4494 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);
4496 CHECK_CALLED(setfillmode);
4498 /* 0 glyph count */
4499 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 0, FALSE, FALSE, &test_geomsink2);
4500 ok(hr == S_OK, "got 0x%08x\n", hr);
4502 /* Glyph with open figure, single contour point. */
4503 codepoint = 'B';
4504 glyphs[0] = 0;
4505 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4506 ok(hr == S_OK, "got 0x%08x\n", hr);
4507 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4509 SET_EXPECT(setfillmode);
4510 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
4511 ok(hr == S_OK, "got 0x%08x\n", hr);
4512 CHECK_CALLED(setfillmode);
4514 IDWriteFactory_Release(factory);
4515 IDWriteFontFace_Release(face);
4516 DELETE_FONTFILE(path);
4518 /* space glyph */
4519 factory = create_factory();
4520 face = create_fontface(factory);
4522 codepoint = ' ';
4523 glyphs[0] = 0;
4524 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4525 ok(hr == S_OK, "got 0x%08x\n", hr);
4526 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4528 SET_EXPECT(setfillmode);
4529 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
4530 ok(hr == S_OK, "got 0x%08x\n", hr);
4531 CHECK_CALLED(setfillmode);
4533 IDWriteFontFace_Release(face);
4534 ref = IDWriteFactory_Release(factory);
4535 ok(ref == 0, "factory not released, %u\n", ref);
4538 static void test_GetEudcFontCollection(void)
4540 IDWriteFontCollection *coll, *coll2;
4541 IDWriteFactory1 *factory;
4542 HRESULT hr;
4543 ULONG ref;
4545 factory = create_factory_iid(&IID_IDWriteFactory1);
4546 if (!factory) {
4547 win_skip("GetEudcFontCollection() is not supported.\n");
4548 return;
4551 EXPECT_REF(factory, 1);
4552 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll, FALSE);
4553 ok(hr == S_OK, "got 0x%08x\n", hr);
4554 EXPECT_REF(factory, 2);
4555 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll2, FALSE);
4556 ok(hr == S_OK, "got 0x%08x\n", hr);
4557 EXPECT_REF(factory, 2);
4558 ok(coll == coll2, "got %p, %p\n", coll, coll2);
4559 IDWriteFontCollection_Release(coll);
4560 IDWriteFontCollection_Release(coll2);
4562 ref = IDWriteFactory1_Release(factory);
4563 ok(ref == 0, "factory not released, %u\n", ref);
4566 static void test_GetCaretMetrics(void)
4568 DWRITE_FONT_METRICS1 metrics;
4569 IDWriteFontFace1 *fontface1;
4570 DWRITE_CARET_METRICS caret;
4571 IDWriteFontFace *fontface;
4572 IDWriteFactory *factory;
4573 IDWriteFontFile *file;
4574 IDWriteFont *font;
4575 WCHAR *path;
4576 HRESULT hr;
4577 ULONG ref;
4579 path = create_testfontfile(test_fontfile);
4580 factory = create_factory();
4582 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4583 ok(hr == S_OK, "got 0x%08x\n", hr);
4585 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4586 ok(hr == S_OK, "got 0x%08x\n", hr);
4587 IDWriteFontFile_Release(file);
4589 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4590 IDWriteFontFace_Release(fontface);
4591 if (hr != S_OK) {
4592 win_skip("GetCaretMetrics() is not supported.\n");
4593 ref = IDWriteFactory_Release(factory);
4594 ok(ref == 0, "factory not released, %u\n", ref);
4595 DELETE_FONTFILE(path);
4596 return;
4599 memset(&caret, 0xcc, sizeof(caret));
4600 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4601 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
4602 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
4603 ok(caret.offset == 0, "got %d\n", caret.offset);
4604 IDWriteFontFace1_Release(fontface1);
4605 IDWriteFactory_Release(factory);
4607 /* now with Tahoma Normal */
4608 factory = create_factory();
4609 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
4610 hr = IDWriteFont_CreateFontFace(font, &fontface);
4611 ok(hr == S_OK, "got 0x%08x\n", hr);
4612 IDWriteFont_Release(font);
4613 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4614 ok(hr == S_OK, "got 0x%08x\n", hr);
4615 IDWriteFontFace_Release(fontface);
4617 memset(&caret, 0xcc, sizeof(caret));
4618 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4619 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
4620 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
4621 ok(caret.offset == 0, "got %d\n", caret.offset);
4622 IDWriteFontFace1_Release(fontface1);
4624 /* simulated italic */
4625 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
4626 hr = IDWriteFont_CreateFontFace(font, &fontface);
4627 ok(hr == S_OK, "got 0x%08x\n", hr);
4628 IDWriteFont_Release(font);
4629 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4630 ok(hr == S_OK, "got 0x%08x\n", hr);
4631 IDWriteFontFace_Release(fontface);
4633 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
4635 memset(&caret, 0xcc, sizeof(caret));
4636 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4637 ok(caret.slopeRise == metrics.designUnitsPerEm, "got %d\n", caret.slopeRise);
4638 ok(caret.slopeRun > 0, "got %d\n", caret.slopeRun);
4639 ok(caret.offset == 0, "got %d\n", caret.offset);
4640 IDWriteFontFace1_Release(fontface1);
4642 ref = IDWriteFactory_Release(factory);
4643 ok(ref == 0, "factory not released, %u\n", ref);
4644 DELETE_FONTFILE(path);
4647 static void test_GetGlyphCount(void)
4649 IDWriteFontFace *fontface;
4650 IDWriteFactory *factory;
4651 IDWriteFontFile *file;
4652 UINT16 count;
4653 WCHAR *path;
4654 HRESULT hr;
4655 ULONG ref;
4657 path = create_testfontfile(test_fontfile);
4658 factory = create_factory();
4660 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4661 ok(hr == S_OK, "got 0x%08x\n", hr);
4663 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4664 ok(hr == S_OK, "got 0x%08x\n", hr);
4665 IDWriteFontFile_Release(file);
4667 count = IDWriteFontFace_GetGlyphCount(fontface);
4668 ok(count == 8, "got %u\n", count);
4670 IDWriteFontFace_Release(fontface);
4671 ref = IDWriteFactory_Release(factory);
4672 ok(ref == 0, "factory not released, %u\n", ref);
4673 DELETE_FONTFILE(path);
4676 static void test_GetKerningPairAdjustments(void)
4678 IDWriteFontFace1 *fontface1;
4679 IDWriteFontFace *fontface;
4680 IDWriteFactory *factory;
4681 IDWriteFontFile *file;
4682 WCHAR *path;
4683 HRESULT hr;
4684 ULONG ref;
4686 path = create_testfontfile(test_fontfile);
4687 factory = create_factory();
4689 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4690 ok(hr == S_OK, "got 0x%08x\n", hr);
4692 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4693 ok(hr == S_OK, "got 0x%08x\n", hr);
4694 IDWriteFontFile_Release(file);
4696 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4697 if (hr == S_OK) {
4698 INT32 adjustments[1];
4700 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 0, NULL, NULL);
4701 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
4703 if (0) /* crashes on native */
4704 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, NULL);
4706 adjustments[0] = 1;
4707 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, adjustments);
4708 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4709 ok(adjustments[0] == 0, "got %d\n", adjustments[0]);
4711 IDWriteFontFace1_Release(fontface1);
4713 else
4714 win_skip("GetKerningPairAdjustments() is not supported.\n");
4716 IDWriteFontFace_Release(fontface);
4717 ref = IDWriteFactory_Release(factory);
4718 ok(ref == 0, "factory not released, %u\n", ref);
4719 DELETE_FONTFILE(path);
4722 static void test_CreateRenderingParams(void)
4724 IDWriteRenderingParams2 *params2;
4725 IDWriteRenderingParams1 *params1;
4726 IDWriteRenderingParams *params;
4727 DWRITE_RENDERING_MODE mode;
4728 IDWriteFactory3 *factory3;
4729 IDWriteFactory *factory;
4730 HRESULT hr;
4731 ULONG ref;
4733 factory = create_factory();
4735 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
4736 DWRITE_RENDERING_MODE_DEFAULT, &params);
4737 ok(hr == S_OK, "got 0x%08x\n", hr);
4739 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams1, (void**)&params1);
4740 if (hr == S_OK) {
4741 FLOAT enhcontrast;
4743 /* test what enhanced contrast setting set by default to */
4744 enhcontrast = IDWriteRenderingParams1_GetGrayscaleEnhancedContrast(params1);
4745 ok(enhcontrast == 1.0, "got %.2f\n", enhcontrast);
4746 IDWriteRenderingParams1_Release(params1);
4748 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
4749 if (hr == S_OK) {
4750 DWRITE_GRID_FIT_MODE gridfit;
4752 /* default gridfit mode */
4753 gridfit = IDWriteRenderingParams2_GetGridFitMode(params2);
4754 ok(gridfit == DWRITE_GRID_FIT_MODE_DEFAULT, "got %d\n", gridfit);
4756 IDWriteRenderingParams2_Release(params2);
4758 else
4759 win_skip("IDWriteRenderingParams2 not supported.\n");
4761 else
4762 win_skip("IDWriteRenderingParams1 not supported.\n");
4764 IDWriteRenderingParams_Release(params);
4766 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
4767 ok(hr == S_OK, "got 0x%08x\n", hr);
4769 mode = IDWriteRenderingParams_GetRenderingMode(params);
4770 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
4771 IDWriteRenderingParams_Release(params);
4773 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
4774 if (hr == S_OK) {
4775 IDWriteRenderingParams3 *params3;
4777 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
4778 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_DEFAULT, &params3);
4779 ok(hr == S_OK, "got 0x%08x\n", hr);
4781 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
4782 ok(hr == S_OK, "got 0x%08x\n", hr);
4784 mode = IDWriteRenderingParams_GetRenderingMode(params);
4785 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
4787 IDWriteRenderingParams_Release(params);
4788 IDWriteRenderingParams3_Release(params3);
4789 IDWriteFactory3_Release(factory3);
4791 else
4792 win_skip("IDWriteRenderingParams3 not supported.\n");
4794 ref = IDWriteFactory_Release(factory);
4795 ok(ref == 0, "factory not released, %u\n", ref);
4798 static void test_CreateGlyphRunAnalysis(void)
4800 static const DWRITE_RENDERING_MODE rendermodes[] = {
4801 DWRITE_RENDERING_MODE_ALIASED,
4802 DWRITE_RENDERING_MODE_GDI_CLASSIC,
4803 DWRITE_RENDERING_MODE_GDI_NATURAL,
4804 DWRITE_RENDERING_MODE_NATURAL,
4805 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
4808 IDWriteGlyphRunAnalysis *analysis, *analysis2;
4809 IDWriteRenderingParams *params;
4810 IDWriteFactory3 *factory3;
4811 IDWriteFactory2 *factory2;
4812 IDWriteFactory *factory;
4813 DWRITE_GLYPH_RUN run;
4814 IDWriteFontFace *face;
4815 UINT16 glyph, glyphs[10];
4816 FLOAT advances[2];
4817 HRESULT hr;
4818 UINT32 ch;
4819 RECT rect, rect2;
4820 DWRITE_GLYPH_OFFSET offsets[2];
4821 DWRITE_GLYPH_METRICS metrics;
4822 DWRITE_FONT_METRICS fm;
4823 DWRITE_MATRIX m;
4824 ULONG size;
4825 BYTE *bits;
4826 ULONG ref;
4827 int i;
4829 factory = create_factory();
4830 face = create_fontface(factory);
4832 ch = 'A';
4833 glyph = 0;
4834 hr = IDWriteFontFace_GetGlyphIndices(face, &ch, 1, &glyph);
4835 ok(hr == S_OK, "got 0x%08x\n", hr);
4836 ok(glyph > 0, "got %u\n", glyph);
4838 hr = IDWriteFontFace_GetDesignGlyphMetrics(face, &glyph, 1, &metrics, FALSE);
4839 ok(hr == S_OK, "got 0x%08x\n", hr);
4840 advances[0] = metrics.advanceWidth;
4842 offsets[0].advanceOffset = 0.0;
4843 offsets[0].ascenderOffset = 0.0;
4845 run.fontFace = face;
4846 run.fontEmSize = 24.0;
4847 run.glyphCount = 1;
4848 run.glyphIndices = &glyph;
4849 run.glyphAdvances = advances;
4850 run.glyphOffsets = offsets;
4851 run.isSideways = FALSE;
4852 run.bidiLevel = 0;
4854 /* zero ppdip */
4855 analysis = (void*)0xdeadbeef;
4856 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 0.0, NULL,
4857 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4858 0.0, 0.0, &analysis);
4859 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4860 ok(analysis == NULL, "got %p\n", analysis);
4862 /* negative ppdip */
4863 analysis = (void*)0xdeadbeef;
4864 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, -1.0, NULL,
4865 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4866 0.0, 0.0, &analysis);
4867 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4868 ok(analysis == NULL, "got %p\n", analysis);
4870 /* default mode is not allowed */
4871 analysis = (void*)0xdeadbeef;
4872 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4873 DWRITE_RENDERING_MODE_DEFAULT, DWRITE_MEASURING_MODE_NATURAL,
4874 0.0, 0.0, &analysis);
4875 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4876 ok(analysis == NULL, "got %p\n", analysis);
4878 /* outline too */
4879 analysis = (void*)0xdeadbeef;
4880 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4881 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_MEASURING_MODE_NATURAL,
4882 0.0, 0.0, &analysis);
4883 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4884 ok(analysis == NULL, "got %p\n", analysis);
4886 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4887 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4888 0.0, 0.0, &analysis);
4889 ok(hr == S_OK, "got 0x%08x\n", hr);
4891 /* invalid texture type */
4892 memset(&rect, 0xcc, sizeof(rect));
4893 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &rect);
4894 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4895 ok(rect.left == 0 && rect.right == 0 &&
4896 rect.top == 0 && rect.bottom == 0, "unexpected rect\n");
4898 /* check how origin affects bounds */
4899 SetRectEmpty(&rect);
4900 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4901 ok(hr == S_OK, "got 0x%08x\n", hr);
4902 ok(!IsRectEmpty(&rect), "got empty rect\n");
4903 IDWriteGlyphRunAnalysis_Release(analysis);
4905 /* doubled ppdip */
4906 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
4907 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4908 0.0, 0.0, &analysis);
4909 ok(hr == S_OK, "got 0x%08x\n", hr);
4910 SetRectEmpty(&rect2);
4911 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4912 ok(hr == S_OK, "got 0x%08x\n", hr);
4913 ok(rect.right - rect.left < rect2.right - rect2.left, "expected wider rect\n");
4914 ok(rect.bottom - rect.top < rect2.bottom - rect2.top, "expected taller rect\n");
4915 IDWriteGlyphRunAnalysis_Release(analysis);
4917 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4918 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4919 10.0, -5.0, &analysis);
4920 ok(hr == S_OK, "got 0x%08x\n", hr);
4922 SetRectEmpty(&rect2);
4923 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4924 ok(hr == S_OK, "got 0x%08x\n", hr);
4925 ok(!IsRectEmpty(&rect2), "got empty rect\n");
4926 IDWriteGlyphRunAnalysis_Release(analysis);
4928 ok(!EqualRect(&rect, &rect2), "got equal bounds\n");
4929 OffsetRect(&rect, 10, -5);
4930 ok(EqualRect(&rect, &rect2), "got different bounds\n");
4932 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
4933 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4934 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
4935 0.0, 0.0, &analysis);
4936 ok(hr == S_OK, "got 0x%08x\n", hr);
4938 if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
4939 SetRectEmpty(&rect);
4940 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4941 ok(hr == S_OK, "got 0x%08x\n", hr);
4942 ok(!IsRectEmpty(&rect), "got empty rect\n");
4944 SetRect(&rect, 0, 0, 1, 1);
4945 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
4946 ok(hr == S_OK, "got 0x%08x\n", hr);
4947 ok(IsRectEmpty(&rect), "unexpected empty rect\n");
4949 else {
4950 SetRect(&rect, 0, 0, 1, 1);
4951 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4952 ok(hr == S_OK, "got 0x%08x\n", hr);
4953 ok(IsRectEmpty(&rect), "got empty rect\n");
4955 SetRectEmpty(&rect);
4956 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
4957 ok(hr == S_OK, "got 0x%08x\n", hr);
4958 ok(!IsRectEmpty(&rect), "got empty rect\n");
4961 IDWriteGlyphRunAnalysis_Release(analysis);
4964 IDWriteFontFace_GetMetrics(run.fontFace, &fm);
4966 /* check bbox for a single glyph run */
4967 for (run.fontEmSize = 1.0; run.fontEmSize <= 100.0; run.fontEmSize += 1.0) {
4968 DWRITE_GLYPH_METRICS gm;
4969 LONG bboxX, bboxY;
4971 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4972 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
4973 0.0, 0.0, &analysis);
4974 ok(hr == S_OK, "got 0x%08x\n", hr);
4976 SetRectEmpty(&rect);
4977 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4978 ok(hr == S_OK, "got 0x%08x\n", hr);
4980 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
4981 DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
4982 ok(hr == S_OK, "got 0x%08x\n", hr);
4984 /* metrics are in design units */
4985 bboxX = (int)floorf((gm.advanceWidth - gm.leftSideBearing - gm.rightSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
4986 bboxY = (int)floorf((gm.advanceHeight - gm.topSideBearing - gm.bottomSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
4988 rect.right -= rect.left;
4989 rect.bottom -= rect.top;
4990 ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %d, from metrics %d\n", run.fontEmSize, rect.right, bboxX);
4991 ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %d, from metrics %d\n", run.fontEmSize, rect.bottom, bboxY);
4993 IDWriteGlyphRunAnalysis_Release(analysis);
4996 /* without offsets */
4997 run.fontFace = face;
4998 run.fontEmSize = 24.0;
4999 run.glyphCount = 1;
5000 run.glyphIndices = &glyph;
5001 run.glyphAdvances = advances;
5002 run.glyphOffsets = NULL;
5003 run.isSideways = FALSE;
5004 run.bidiLevel = 0;
5006 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5007 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5008 0.0, 0.0, &analysis);
5009 ok(hr == S_OK, "got 0x%08x\n", hr);
5011 SetRectEmpty(&rect);
5012 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5013 ok(hr == S_OK, "got 0x%08x\n", hr);
5014 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5016 IDWriteGlyphRunAnalysis_Release(analysis);
5018 /* without explicit advances */
5019 run.fontFace = face;
5020 run.fontEmSize = 24.0;
5021 run.glyphCount = 1;
5022 run.glyphIndices = &glyph;
5023 run.glyphAdvances = NULL;
5024 run.glyphOffsets = NULL;
5025 run.isSideways = FALSE;
5026 run.bidiLevel = 0;
5028 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5029 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5030 0.0, 0.0, &analysis);
5031 ok(hr == S_OK, "got 0x%08x\n", hr);
5033 SetRectEmpty(&rect);
5034 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5035 ok(hr == S_OK, "got 0x%08x\n", hr);
5036 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5038 IDWriteGlyphRunAnalysis_Release(analysis);
5040 /* test that advances are scaled according to ppdip too */
5041 glyphs[0] = glyphs[1] = glyph;
5042 advances[0] = advances[1] = 100.0f;
5043 run.fontFace = face;
5044 run.fontEmSize = 24.0;
5045 run.glyphCount = 2;
5046 run.glyphIndices = glyphs;
5047 run.glyphAdvances = advances;
5048 run.glyphOffsets = NULL;
5049 run.isSideways = FALSE;
5050 run.bidiLevel = 0;
5052 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5053 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5054 0.0, 0.0, &analysis);
5055 ok(hr == S_OK, "got 0x%08x\n", hr);
5057 SetRectEmpty(&rect2);
5058 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5059 ok(hr == S_OK, "got 0x%08x\n", hr);
5060 ok(!IsRectEmpty(&rect2), "got empty bounds\n");
5061 ok(!EqualRect(&rect, &rect2), "got wrong rect2\n");
5062 ok((rect2.right - rect.left) > advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
5063 IDWriteGlyphRunAnalysis_Release(analysis);
5065 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5066 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5067 0.0, 0.0, &analysis);
5068 ok(hr == S_OK, "got 0x%08x\n", hr);
5070 SetRectEmpty(&rect);
5071 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5072 ok(hr == S_OK, "got 0x%08x\n", hr);
5073 ok((rect.right - rect.left) > 2 * advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
5074 IDWriteGlyphRunAnalysis_Release(analysis);
5076 /* with scaling transform */
5077 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5078 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5079 0.0, 0.0, &analysis);
5080 ok(hr == S_OK, "got 0x%08x\n", hr);
5082 SetRectEmpty(&rect);
5083 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5084 ok(hr == S_OK, "got 0x%08x\n", hr);
5085 ok(!IsRectEmpty(&rect), "got rect width %d\n", rect.right - rect.left);
5086 IDWriteGlyphRunAnalysis_Release(analysis);
5088 memset(&m, 0, sizeof(m));
5089 m.m11 = 2.0;
5090 m.m22 = 1.0;
5091 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5092 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5093 0.0, 0.0, &analysis);
5094 ok(hr == S_OK, "got 0x%08x\n", hr);
5096 SetRectEmpty(&rect2);
5097 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5098 ok(hr == S_OK, "got 0x%08x\n", hr);
5099 ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %d\n", rect2.right - rect2.left);
5101 /* instances are not reused for same runs */
5102 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5103 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5104 0.0, 0.0, &analysis2);
5105 ok(hr == S_OK, "got 0x%08x\n", hr);
5106 ok(analysis2 != analysis, "got %p, previous instance %p\n", analysis2, analysis);
5107 IDWriteGlyphRunAnalysis_Release(analysis2);
5109 IDWriteGlyphRunAnalysis_Release(analysis);
5111 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void **)&factory2) == S_OK) {
5112 FLOAT gamma, contrast, cleartype_level;
5114 /* Invalid antialias mode. */
5115 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5116 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
5117 0.0f, 0.0f, &analysis);
5118 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5120 /* Invalid grid fit mode. */
5121 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5122 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5123 0.0f, 0.0f, &analysis);
5124 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5126 /* Invalid rendering mode. */
5127 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_OUTLINE,
5128 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5129 0.0f, 0.0f, &analysis);
5130 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5132 /* Invalid measuring mode. */
5133 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5134 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5135 0.0f, 0.0f, &analysis);
5136 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5138 /* Win8 does not accept default grid fitting mode. */
5139 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
5140 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5141 0.0f, 0.0f, &analysis);
5142 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Win8 */, "Failed to create analysis, hr %#x.\n", hr);
5143 if (hr == S_OK)
5144 IDWriteGlyphRunAnalysis_Release(analysis);
5146 /* Natural mode, grayscale antialiased. */
5147 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
5148 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5149 0.0f, 0.0f, &analysis);
5150 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
5152 SetRect(&rect, 0, 1, 0, 1);
5153 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5154 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5155 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
5157 SetRectEmpty(&rect);
5158 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5159 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5160 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
5162 size = (rect.right - rect.left) * (rect.bottom - rect.top);
5163 bits = HeapAlloc(GetProcessHeap(), 0, size);
5165 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
5166 ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
5168 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
5169 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
5171 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
5172 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5174 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
5175 todo_wine
5176 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5178 HeapFree(GetProcessHeap(), 0, bits);
5180 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.1f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
5181 DWRITE_RENDERING_MODE_NATURAL, &params);
5182 ok(hr == S_OK, "Failed to create custom parameters, hr %#x.\n", hr);
5184 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &cleartype_level);
5185 ok(hr == S_OK, "Failed to get alpha blend params, hr %#x.\n", hr);
5186 todo_wine
5187 ok(cleartype_level == 0.0f, "Unexpected cleartype level %f.\n", cleartype_level);
5189 IDWriteRenderingParams_Release(params);
5190 IDWriteGlyphRunAnalysis_Release(analysis);
5192 IDWriteFactory2_Release(factory2);
5195 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3) == S_OK) {
5197 /* Invalid antialias mode. */
5198 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
5199 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
5200 0.0f, 0.0f, &analysis);
5201 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5203 /* Invalid grid fit mode. */
5204 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
5205 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5206 0.0f, 0.0f, &analysis);
5207 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5209 /* Invalid rendering mode. */
5210 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_OUTLINE,
5211 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5212 0.0f, 0.0f, &analysis);
5213 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5215 /* Invalid measuring mode. */
5216 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
5217 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED,
5218 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, 0.0f, 0.0f, &analysis);
5219 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5221 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
5222 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5223 0.0f, 0.0f, &analysis);
5224 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
5225 IDWriteGlyphRunAnalysis_Release(analysis);
5227 /* Natural mode, grayscale antialiased. */
5228 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
5229 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5230 0.0f, 0.0f, &analysis);
5231 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
5233 SetRect(&rect, 0, 1, 0, 1);
5234 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5235 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5236 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
5238 SetRectEmpty(&rect);
5239 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5240 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5241 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
5243 size = (rect.right - rect.left) * (rect.bottom - rect.top);
5244 bits = HeapAlloc(GetProcessHeap(), 0, size);
5246 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
5247 ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
5249 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
5250 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
5252 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
5253 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5255 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
5256 todo_wine
5257 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5259 HeapFree(GetProcessHeap(), 0, bits);
5261 IDWriteGlyphRunAnalysis_Release(analysis);
5263 IDWriteFactory3_Release(factory3);
5266 IDWriteFontFace_Release(face);
5267 ref = IDWriteFactory_Release(factory);
5268 ok(ref == 0, "factory not released, %u\n", ref);
5271 #define round(x) ((int)floor((x) + 0.5))
5273 struct VDMX_Header
5275 WORD version;
5276 WORD numRecs;
5277 WORD numRatios;
5280 struct VDMX_Ratio
5282 BYTE bCharSet;
5283 BYTE xRatio;
5284 BYTE yStartRatio;
5285 BYTE yEndRatio;
5288 struct VDMX_group
5290 WORD recs;
5291 BYTE startsz;
5292 BYTE endsz;
5295 struct VDMX_vTable
5297 WORD yPelHeight;
5298 SHORT yMax;
5299 SHORT yMin;
5302 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
5304 WORD num_ratios, i, group_offset = 0;
5305 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
5306 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
5308 num_ratios = GET_BE_WORD(hdr->numRatios);
5310 for (i = 0; i < num_ratios; i++)
5312 if (!ratios[i].bCharSet) continue;
5314 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
5315 ratios[i].yEndRatio == 0) ||
5316 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
5317 ratios[i].yEndRatio >= dev_y_ratio))
5319 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
5320 break;
5323 if (group_offset)
5324 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
5325 return NULL;
5328 static BOOL get_vdmx_size(const struct VDMX_group *group, int emsize, int *a, int *d)
5330 WORD recs, i;
5331 const struct VDMX_vTable *tables;
5333 if (!group) return FALSE;
5335 recs = GET_BE_WORD(group->recs);
5336 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
5338 tables = (const struct VDMX_vTable *)(group + 1);
5339 for (i = 0; i < recs; i++)
5341 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
5342 if (ppem > emsize)
5344 /* FIXME: Supposed to interpolate */
5345 trace("FIXME interpolate %d\n", emsize);
5346 return FALSE;
5349 if (ppem == emsize)
5351 *a = (SHORT)GET_BE_WORD(tables[i].yMax);
5352 *d = -(SHORT)GET_BE_WORD(tables[i].yMin);
5353 return TRUE;
5356 return FALSE;
5359 static void test_metrics_cmp(FLOAT emsize, const DWRITE_FONT_METRICS *metrics, const DWRITE_FONT_METRICS1 *expected)
5361 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
5362 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
5363 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
5364 emsize, metrics->ascent, expected->ascent);
5365 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
5366 emsize, metrics->descent, expected->descent);
5367 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
5368 emsize, metrics->lineGap, expected->lineGap);
5369 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
5370 emsize, metrics->capHeight, expected->capHeight);
5371 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
5372 emsize, metrics->xHeight, expected->xHeight);
5373 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
5374 emsize, metrics->underlinePosition, expected->underlinePosition);
5375 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
5376 emsize, metrics->underlineThickness, expected->underlineThickness);
5377 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
5378 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
5379 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
5380 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
5383 static void test_metrics1_cmp(FLOAT emsize, const DWRITE_FONT_METRICS1 *metrics, const DWRITE_FONT_METRICS1 *expected)
5385 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
5386 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
5387 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
5388 emsize, metrics->ascent, expected->ascent);
5389 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
5390 emsize, metrics->descent, expected->descent);
5391 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
5392 emsize, metrics->lineGap, expected->lineGap);
5393 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
5394 emsize, metrics->capHeight, expected->capHeight);
5395 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
5396 emsize, metrics->xHeight, expected->xHeight);
5397 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
5398 emsize, metrics->underlinePosition, expected->underlinePosition);
5399 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
5400 emsize, metrics->underlineThickness, expected->underlineThickness);
5401 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
5402 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
5403 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
5404 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
5405 ok(metrics->glyphBoxLeft == expected->glyphBoxLeft, "%.2f box left: got %d expect %d\n",
5406 emsize, metrics->glyphBoxLeft, expected->glyphBoxLeft);
5407 if (0) { /* this is not consistent */
5408 ok(metrics->glyphBoxTop == expected->glyphBoxTop, "%.2f box top: got %d expect %d\n",
5409 emsize, metrics->glyphBoxTop, expected->glyphBoxTop);
5410 ok(metrics->glyphBoxRight == expected->glyphBoxRight, "%.2f box right: got %d expect %d\n",
5411 emsize, metrics->glyphBoxRight, expected->glyphBoxRight);
5413 ok(metrics->glyphBoxBottom == expected->glyphBoxBottom, "%.2f box bottom: got %d expect %d\n",
5414 emsize, metrics->glyphBoxBottom, expected->glyphBoxBottom);
5415 ok(metrics->subscriptPositionX == expected->subscriptPositionX, "%.2f subX: got %d expect %d\n",
5416 emsize, metrics->subscriptPositionX, expected->subscriptPositionX);
5417 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subY: got %d expect %d\n",
5418 emsize, metrics->subscriptPositionY, expected->subscriptPositionY);
5419 ok(metrics->subscriptSizeX == expected->subscriptSizeX, "%.2f subsizeX: got %d expect %d\n",
5420 emsize, metrics->subscriptSizeX, expected->subscriptSizeX);
5421 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subsizeY: got %d expect %d\n",
5422 emsize, metrics->subscriptSizeY, expected->subscriptSizeY);
5423 ok(metrics->superscriptPositionX == expected->superscriptPositionX, "%.2f supX: got %d expect %d\n",
5424 emsize, metrics->superscriptPositionX, expected->superscriptPositionX);
5425 if (0)
5426 ok(metrics->superscriptPositionY == expected->superscriptPositionY, "%.2f supY: got %d expect %d\n",
5427 emsize, metrics->superscriptPositionY, expected->superscriptPositionY);
5428 ok(metrics->superscriptSizeX == expected->superscriptSizeX, "%.2f supsizeX: got %d expect %d\n",
5429 emsize, metrics->superscriptSizeX, expected->superscriptSizeX);
5430 ok(metrics->superscriptSizeY == expected->superscriptSizeY, "%.2f supsizeY: got %d expect %d\n",
5431 emsize, metrics->superscriptSizeY, expected->superscriptSizeY);
5432 ok(metrics->hasTypographicMetrics == expected->hasTypographicMetrics, "%.2f hastypo: got %d expect %d\n",
5433 emsize, metrics->hasTypographicMetrics, expected->hasTypographicMetrics);
5436 struct compatmetrics_test {
5437 DWRITE_MATRIX m;
5438 FLOAT ppdip;
5439 FLOAT emsize;
5442 static struct compatmetrics_test compatmetrics_tests[] = {
5443 { { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0, 5.0 },
5444 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 1.0, 5.0 },
5445 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 2.0, 5.0 },
5446 { { 0.0, 0.0, 0.0, 3.0, 0.0, 0.0 }, 2.0, 5.0 },
5447 { { 0.0, 0.0, 0.0, -3.0, 0.0, 0.0 }, 2.0, 5.0 },
5448 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 2.0, 5.0 },
5449 { { 1.0, 0.0, 0.0, 1.0, 5.0, 0.0 }, 2.0, 5.0 },
5450 { { 1.0, 0.0, 0.0, 1.0, 0.0, 5.0 }, 2.0, 5.0 },
5453 static void get_expected_metrics(IDWriteFontFace *fontface, struct compatmetrics_test *ptr,
5454 DWRITE_FONT_METRICS *expected)
5456 HRESULT hr;
5458 memset(expected, 0, sizeof(*expected));
5459 hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, ptr->ppdip * fabsf(ptr->m.m22) * ptr->emsize, 1.0, NULL, expected);
5460 ok(hr == S_OK, "got %08x\n", hr);
5463 static void test_gdicompat_metrics(IDWriteFontFace *face)
5465 IDWriteFontFace1 *fontface1 = NULL;
5466 HRESULT hr;
5467 DWRITE_FONT_METRICS design_metrics, comp_metrics;
5468 DWRITE_FONT_METRICS1 design_metrics1, expected;
5469 FLOAT emsize, scale;
5470 int ascent, descent;
5471 const struct VDMX_Header *vdmx;
5472 UINT32 vdmx_len;
5473 void *vdmx_ctx;
5474 BOOL exists;
5475 const struct VDMX_group *vdmx_group = NULL;
5476 int i;
5478 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace1, (void**)&fontface1);
5479 if (hr != S_OK)
5480 win_skip("gdi compatible DWRITE_FONT_METRICS1 are not supported.\n");
5482 if (fontface1) {
5483 IDWriteFontFace1_GetMetrics(fontface1, &design_metrics1);
5484 memcpy(&design_metrics, &design_metrics1, sizeof(design_metrics));
5486 else
5487 IDWriteFontFace_GetMetrics(face, &design_metrics);
5489 hr = IDWriteFontFace_TryGetFontTable(face, MS_VDMX_TAG, (const void **)&vdmx,
5490 &vdmx_len, &vdmx_ctx, &exists);
5491 if (hr != S_OK || !exists)
5492 vdmx = NULL;
5493 else
5494 vdmx_group = find_vdmx_group(vdmx);
5496 /* negative emsize */
5497 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5498 memset(&expected, 0, sizeof(expected));
5499 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, -10.0, 1.0, NULL, &comp_metrics);
5500 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5501 test_metrics_cmp(0.0, &comp_metrics, &expected);
5503 /* zero emsize */
5504 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5505 memset(&expected, 0, sizeof(expected));
5506 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 0.0, 1.0, NULL, &comp_metrics);
5507 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5508 test_metrics_cmp(0.0, &comp_metrics, &expected);
5510 /* zero pixels per dip */
5511 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5512 memset(&expected, 0, sizeof(expected));
5513 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, 0.0, NULL, &comp_metrics);
5514 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5515 test_metrics_cmp(5.0, &comp_metrics, &expected);
5517 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5518 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, -1.0, NULL, &comp_metrics);
5519 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5520 test_metrics_cmp(5.0, &comp_metrics, &expected);
5522 for (i = 0; i < ARRAY_SIZE(compatmetrics_tests); i++) {
5523 struct compatmetrics_test *ptr = &compatmetrics_tests[i];
5525 get_expected_metrics(face, ptr, (DWRITE_FONT_METRICS*)&expected);
5526 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, ptr->emsize, ptr->ppdip, &ptr->m, &comp_metrics);
5527 ok(hr == S_OK, "got %08x\n", hr);
5528 test_metrics_cmp(ptr->emsize, &comp_metrics, &expected);
5531 for (emsize = 5; emsize <= design_metrics.designUnitsPerEm; emsize++)
5533 DWRITE_FONT_METRICS1 comp_metrics1, expected;
5535 if (fontface1) {
5536 hr = IDWriteFontFace1_GetGdiCompatibleMetrics(fontface1, emsize, 1.0, NULL, &comp_metrics1);
5537 ok(hr == S_OK, "got %08x\n", hr);
5539 else {
5540 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, emsize, 1.0, NULL, &comp_metrics);
5541 ok(hr == S_OK, "got %08x\n", hr);
5544 scale = emsize / design_metrics.designUnitsPerEm;
5545 if (!get_vdmx_size(vdmx_group, emsize, &ascent, &descent))
5547 ascent = round(design_metrics.ascent * scale);
5548 descent = round(design_metrics.descent * scale);
5551 expected.designUnitsPerEm = design_metrics.designUnitsPerEm;
5552 expected.ascent = round(ascent / scale );
5553 expected.descent = round(descent / scale );
5554 expected.lineGap = round(round(design_metrics.lineGap * scale) / scale);
5555 expected.capHeight = round(round(design_metrics.capHeight * scale) / scale);
5556 expected.xHeight = round(round(design_metrics.xHeight * scale) / scale);
5557 expected.underlinePosition = round(round(design_metrics.underlinePosition * scale) / scale);
5558 expected.underlineThickness = round(round(design_metrics.underlineThickness * scale) / scale);
5559 expected.strikethroughPosition = round(round(design_metrics.strikethroughPosition * scale) / scale);
5560 expected.strikethroughThickness = round(round(design_metrics.strikethroughThickness * scale) / scale);
5562 if (fontface1) {
5563 expected.glyphBoxLeft = round(round(design_metrics1.glyphBoxLeft * scale) / scale);
5565 if (0) { /* those two fail on Tahoma and Win7 */
5566 expected.glyphBoxTop = round(round(design_metrics1.glyphBoxTop * scale) / scale);
5567 expected.glyphBoxRight = round(round(design_metrics1.glyphBoxRight * scale) / scale);
5569 expected.glyphBoxBottom = round(round(design_metrics1.glyphBoxBottom * scale) / scale);
5570 expected.subscriptPositionX = round(round(design_metrics1.subscriptPositionX * scale) / scale);
5571 expected.subscriptPositionY = round(round(design_metrics1.subscriptPositionY * scale) / scale);
5572 expected.subscriptSizeX = round(round(design_metrics1.subscriptSizeX * scale) / scale);
5573 expected.subscriptSizeY = round(round(design_metrics1.subscriptSizeY * scale) / scale);
5574 expected.superscriptPositionX = round(round(design_metrics1.superscriptPositionX * scale) / scale);
5575 if (0) /* this fails for 3 emsizes, Tahoma from [5, 2048] range */ {
5576 expected.superscriptPositionY = round(round(design_metrics1.superscriptPositionY * scale) / scale);
5578 expected.superscriptSizeX = round(round(design_metrics1.superscriptSizeX * scale) / scale);
5579 expected.superscriptSizeY = round(round(design_metrics1.superscriptSizeY * scale) / scale);
5580 expected.hasTypographicMetrics = design_metrics1.hasTypographicMetrics;
5582 test_metrics1_cmp(emsize, &comp_metrics1, &expected);
5584 else
5585 test_metrics_cmp(emsize, &comp_metrics, &expected);
5589 if (fontface1)
5590 IDWriteFontFace1_Release(fontface1);
5591 if (vdmx) IDWriteFontFace_ReleaseFontTable(face, vdmx_ctx);
5594 static void test_GetGdiCompatibleMetrics(void)
5596 IDWriteFactory *factory;
5597 IDWriteFont *font;
5598 IDWriteFontFace *fontface;
5599 HRESULT hr;
5600 ULONG ref;
5602 factory = create_factory();
5604 font = get_font(factory, tahomaW, DWRITE_FONT_STYLE_NORMAL);
5605 hr = IDWriteFont_CreateFontFace(font, &fontface);
5606 ok(hr == S_OK, "got 0x%08x\n", hr);
5607 IDWriteFont_Release(font);
5608 test_gdicompat_metrics(fontface);
5609 IDWriteFontFace_Release(fontface);
5611 font = get_font(factory, arialW, DWRITE_FONT_STYLE_NORMAL);
5612 if (!font)
5613 skip("Skipping tests with Arial\n");
5614 else
5616 hr = IDWriteFont_CreateFontFace(font, &fontface);
5617 ok(hr == S_OK, "got 0x%08x\n", hr);
5618 IDWriteFont_Release(font);
5620 test_gdicompat_metrics(fontface);
5621 IDWriteFontFace_Release(fontface);
5624 ref = IDWriteFactory_Release(factory);
5625 ok(ref == 0, "factory not released, %u\n", ref);
5628 static void get_expected_panose(IDWriteFont1 *font, DWRITE_PANOSE *panose)
5630 IDWriteFontFace *fontface;
5631 const TT_OS2_V2 *tt_os2;
5632 void *os2_context;
5633 UINT32 size;
5634 BOOL exists;
5635 HRESULT hr;
5637 memset(panose, 0, sizeof(*panose));
5639 hr = IDWriteFont1_CreateFontFace(font, &fontface);
5640 ok(hr == S_OK, "got 0x%08x\n", hr);
5642 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
5643 ok(hr == S_OK, "got 0x%08x\n", hr);
5645 if (tt_os2) {
5646 memcpy(panose, &tt_os2->panose, sizeof(*panose));
5647 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
5650 IDWriteFontFace_Release(fontface);
5653 static void test_GetPanose(void)
5655 IDWriteFontCollection *syscollection;
5656 IDWriteFactory *factory;
5657 IDWriteFont1 *font1;
5658 IDWriteFont *font;
5659 UINT count, i;
5660 HRESULT hr;
5661 ULONG ref;
5663 factory = create_factory();
5664 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5666 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
5667 IDWriteFont_Release(font);
5669 if (FAILED(hr)) {
5670 ref = IDWriteFactory_Release(factory);
5671 ok(ref == 0, "factory not released, %u\n", ref);
5672 win_skip("GetPanose() is not supported.\n");
5673 return;
5675 IDWriteFont1_Release(font1);
5677 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
5678 ok(hr == S_OK, "got 0x%08x\n", hr);
5679 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
5681 for (i = 0; i < count; i++) {
5682 DWRITE_PANOSE panose, expected_panose;
5683 IDWriteLocalizedStrings *names;
5684 IDWriteFontFace3 *fontface3;
5685 IDWriteFontFace *fontface;
5686 IDWriteFontFamily *family;
5687 IDWriteFont1 *font1;
5688 IDWriteFont *font;
5689 WCHAR nameW[256];
5691 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
5692 ok(hr == S_OK, "got 0x%08x\n", hr);
5694 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
5695 DWRITE_FONT_STYLE_NORMAL, &font);
5696 ok(hr == S_OK, "got 0x%08x\n", hr);
5698 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
5699 ok(hr == S_OK, "got 0x%08x\n", hr);
5700 IDWriteFont_Release(font);
5702 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
5703 ok(hr == S_OK, "got 0x%08x\n", hr);
5705 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
5707 IDWriteLocalizedStrings_Release(names);
5709 IDWriteFont1_GetPanose(font1, &panose);
5710 get_expected_panose(font1, &expected_panose);
5712 ok(panose.values[0] == expected_panose.values[0], "%s: values[0] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5713 panose.values[0], expected_panose.values[0]);
5714 ok(panose.values[1] == expected_panose.values[1], "%s: values[1] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5715 panose.values[1], expected_panose.values[1]);
5716 ok(panose.values[2] == expected_panose.values[2], "%s: values[2] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5717 panose.values[2], expected_panose.values[2]);
5718 ok(panose.values[3] == expected_panose.values[3], "%s: values[3] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5719 panose.values[3], expected_panose.values[3]);
5720 ok(panose.values[4] == expected_panose.values[4], "%s: values[4] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5721 panose.values[4], expected_panose.values[4]);
5722 ok(panose.values[5] == expected_panose.values[5], "%s: values[5] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5723 panose.values[5], expected_panose.values[5]);
5724 ok(panose.values[6] == expected_panose.values[6], "%s: values[6] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5725 panose.values[6], expected_panose.values[6]);
5726 ok(panose.values[7] == expected_panose.values[7], "%s: values[7] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5727 panose.values[7], expected_panose.values[7]);
5728 ok(panose.values[8] == expected_panose.values[8], "%s: values[8] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5729 panose.values[8], expected_panose.values[8]);
5730 ok(panose.values[9] == expected_panose.values[9], "%s: values[9] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5731 panose.values[9], expected_panose.values[9]);
5733 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
5734 ok(hr == S_OK, "Failed to create a font face, %#x.\n", hr);
5735 if (IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3) == S_OK) {
5736 ok(!memcmp(&panose, &expected_panose, sizeof(panose)), "%s: Unexpected panose from font face.\n",
5737 wine_dbgstr_w(nameW));
5738 IDWriteFontFace3_Release(fontface3);
5740 IDWriteFontFace_Release(fontface);
5742 IDWriteFont1_Release(font1);
5743 IDWriteFontFamily_Release(family);
5746 IDWriteFontCollection_Release(syscollection);
5747 ref = IDWriteFactory_Release(factory);
5748 ok(ref == 0, "factory not released, %u\n", ref);
5751 static INT32 get_gdi_font_advance(HDC hdc, FLOAT emsize)
5753 LOGFONTW logfont;
5754 HFONT hfont;
5755 BOOL ret;
5756 ABC abc;
5758 memset(&logfont, 0, sizeof(logfont));
5759 logfont.lfHeight = (LONG)-emsize;
5760 logfont.lfWeight = FW_NORMAL;
5761 logfont.lfQuality = CLEARTYPE_QUALITY;
5762 lstrcpyW(logfont.lfFaceName, tahomaW);
5764 hfont = CreateFontIndirectW(&logfont);
5765 SelectObject(hdc, hfont);
5767 ret = GetCharABCWidthsW(hdc, 'A', 'A', &abc);
5768 ok(ret, "got %d\n", ret);
5770 DeleteObject(hfont);
5772 return abc.abcA + abc.abcB + abc.abcC;
5775 static void test_GetGdiCompatibleGlyphAdvances(void)
5777 IDWriteFontFace1 *fontface1;
5778 IDWriteFontFace *fontface;
5779 IDWriteFactory *factory;
5780 IDWriteFont *font;
5781 HRESULT hr;
5782 HDC hdc;
5783 UINT32 codepoint;
5784 UINT16 glyph;
5785 FLOAT emsize;
5786 DWRITE_FONT_METRICS1 fm;
5787 INT32 advance;
5788 ULONG ref;
5790 factory = create_factory();
5791 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5793 hr = IDWriteFont_CreateFontFace(font, &fontface);
5794 ok(hr == S_OK, "got 0x%08x\n", hr);
5795 IDWriteFont_Release(font);
5797 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
5798 IDWriteFontFace_Release(fontface);
5800 if (hr != S_OK) {
5801 ref = IDWriteFactory_Release(factory);
5802 ok(ref == 0, "factory not released, %u\n", ref);
5803 win_skip("GetGdiCompatibleGlyphAdvances() is not supported\n");
5804 return;
5807 codepoint = 'A';
5808 glyph = 0;
5809 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &glyph);
5810 ok(hr == S_OK, "got 0x%08x\n", hr);
5811 ok(glyph > 0, "got %u\n", glyph);
5813 /* zero emsize */
5814 advance = 1;
5815 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 0.0,
5816 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5817 ok(hr == S_OK, "got 0x%08x\n", hr);
5818 ok(advance == 0, "got %d\n", advance);
5820 /* negative emsize */
5821 advance = 1;
5822 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, -1.0,
5823 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5824 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5825 ok(advance == 0, "got %d\n", advance);
5827 /* zero ppdip */
5828 advance = 1;
5829 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
5830 0.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5831 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5832 ok(advance == 0, "got %d\n", advance);
5834 /* negative ppdip */
5835 advance = 1;
5836 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
5837 -1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5838 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5839 ok(advance == 0, "got %d\n", advance);
5841 IDWriteFontFace1_GetMetrics(fontface1, &fm);
5843 hdc = CreateCompatibleDC(0);
5845 for (emsize = 1.0; emsize <= fm.designUnitsPerEm; emsize += 1.0) {
5846 INT32 gdi_advance;
5848 gdi_advance = get_gdi_font_advance(hdc, emsize);
5849 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emsize,
5850 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5851 ok(hr == S_OK, "got 0x%08x\n", hr);
5853 /* advance is in design units */
5854 advance = (int)floorf(emsize * advance / fm.designUnitsPerEm + 0.5f);
5855 ok((advance - gdi_advance) <= 2, "%.0f: got advance %d, expected %d\n", emsize, advance, gdi_advance);
5858 DeleteObject(hdc);
5860 IDWriteFontFace1_Release(fontface1);
5861 ref = IDWriteFactory_Release(factory);
5862 ok(ref == 0, "factory not released, %u\n", ref);
5865 static WORD get_gasp_flags(IDWriteFontFace *fontface, FLOAT emsize, FLOAT ppdip)
5867 WORD num_recs, version;
5868 const WORD *ptr;
5869 WORD flags = 0;
5870 UINT32 size;
5871 BOOL exists;
5872 void *ctxt;
5873 HRESULT hr;
5875 emsize *= ppdip;
5877 exists = FALSE;
5878 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GASP_TAG,
5879 (const void**)&ptr, &size, &ctxt, &exists);
5880 ok(hr == S_OK, "got 0x%08x\n", hr);
5882 if (!exists)
5883 goto done;
5885 version = GET_BE_WORD( *ptr++ );
5886 num_recs = GET_BE_WORD( *ptr++ );
5887 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
5888 ok(0, "unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
5889 goto done;
5892 while (num_recs--)
5894 flags = GET_BE_WORD( *(ptr + 1) );
5895 if (emsize <= GET_BE_WORD( *ptr )) break;
5896 ptr += 2;
5899 done:
5900 IDWriteFontFace_ReleaseFontTable(fontface, ctxt);
5901 return flags;
5904 #define GASP_GRIDFIT 0x0001
5905 #define GASP_DOGRAY 0x0002
5906 #define GASP_SYMMETRIC_GRIDFIT 0x0004
5907 #define GASP_SYMMETRIC_SMOOTHING 0x0008
5909 static BOOL g_is_vista;
5910 static DWRITE_RENDERING_MODE get_expected_rendering_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
5911 DWRITE_OUTLINE_THRESHOLD threshold)
5913 static const FLOAT aa_threshold = 100.0f;
5914 static const FLOAT a_threshold = 350.0f;
5915 static const FLOAT naturalemsize = 20.0f;
5916 FLOAT v;
5918 /* outline threshold */
5919 if (g_is_vista)
5920 v = mode == DWRITE_MEASURING_MODE_NATURAL ? aa_threshold : a_threshold;
5921 else
5922 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
5924 if (emsize >= v)
5925 return DWRITE_RENDERING_MODE_OUTLINE;
5927 switch (mode)
5929 case DWRITE_MEASURING_MODE_NATURAL:
5930 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (emsize <= naturalemsize))
5931 return DWRITE_RENDERING_MODE_NATURAL;
5932 else
5933 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
5934 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5935 return DWRITE_RENDERING_MODE_GDI_CLASSIC;
5936 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5937 return DWRITE_RENDERING_MODE_GDI_NATURAL;
5938 default:
5942 /* should be unreachable */
5943 return DWRITE_RENDERING_MODE_DEFAULT;
5946 static DWRITE_GRID_FIT_MODE get_expected_gridfit_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
5947 DWRITE_OUTLINE_THRESHOLD threshold)
5949 static const FLOAT aa_threshold = 100.0f;
5950 static const FLOAT a_threshold = 350.0f;
5951 FLOAT v;
5953 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
5954 if (emsize >= v)
5955 return DWRITE_GRID_FIT_MODE_DISABLED;
5957 if (mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
5958 return DWRITE_GRID_FIT_MODE_ENABLED;
5960 return (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
5963 struct recommendedmode_test
5965 DWRITE_MEASURING_MODE measuring;
5966 DWRITE_OUTLINE_THRESHOLD threshold;
5969 static const struct recommendedmode_test recmode_tests[] = {
5970 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5971 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5972 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5975 static const struct recommendedmode_test recmode_tests1[] = {
5976 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5977 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5978 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5979 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5980 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5981 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5984 static void test_GetRecommendedRenderingMode(void)
5986 IDWriteRenderingParams *params;
5987 IDWriteFontFace3 *fontface3;
5988 IDWriteFontFace2 *fontface2;
5989 IDWriteFontFace1 *fontface1;
5990 IDWriteFontFace *fontface;
5991 DWRITE_RENDERING_MODE mode;
5992 IDWriteFactory *factory;
5993 FLOAT emsize;
5994 HRESULT hr;
5995 ULONG ref;
5997 factory = create_factory();
5998 fontface = create_fontface(factory);
6000 fontface1 = NULL;
6001 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
6002 if (hr != S_OK)
6003 win_skip("IDWriteFontFace1::GetRecommendedRenderingMode() is not supported.\n");
6005 fontface2 = NULL;
6006 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6007 if (hr != S_OK)
6008 win_skip("IDWriteFontFace2::GetRecommendedRenderingMode() is not supported.\n");
6010 fontface3 = NULL;
6011 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
6012 if (hr != S_OK)
6013 win_skip("IDWriteFontFace3::GetRecommendedRenderingMode() is not supported.\n");
6015 if (0) /* crashes on native */
6016 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6017 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, NULL);
6019 mode = 10;
6020 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6021 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode);
6022 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6023 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
6025 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
6026 ok(hr == S_OK, "got 0x%08x\n", hr);
6028 /* detect old dwrite version, that is using higher threshold value */
6029 g_is_vista = fontface1 == NULL;
6031 for (emsize = 1.0; emsize < 500.0; emsize += 1.0) {
6032 DWRITE_RENDERING_MODE expected;
6033 FLOAT ppdip;
6034 WORD gasp;
6035 int i;
6037 for (i = 0; i < ARRAY_SIZE(recmode_tests); i++) {
6038 ppdip = 1.0f;
6039 mode = 10;
6040 gasp = get_gasp_flags(fontface, emsize, ppdip);
6041 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6042 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6043 ok(hr == S_OK, "got 0x%08x\n", hr);
6044 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6046 /* some ppdip variants */
6047 ppdip = 0.5f;
6048 mode = 10;
6049 gasp = get_gasp_flags(fontface, emsize, ppdip);
6050 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6051 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6052 ok(hr == S_OK, "got 0x%08x\n", hr);
6053 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6055 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6056 Win8 and Win10 handle this as expected. */
6057 if (emsize > 20.0f) {
6058 ppdip = 1.5f;
6059 mode = 10;
6060 gasp = get_gasp_flags(fontface, emsize, ppdip);
6061 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6062 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6063 ok(hr == S_OK, "got 0x%08x\n", hr);
6064 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6066 ppdip = 2.0f;
6067 mode = 10;
6068 gasp = get_gasp_flags(fontface, emsize, ppdip);
6069 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6070 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6071 ok(hr == S_OK, "got 0x%08x\n", hr);
6072 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6076 /* IDWriteFontFace1 offers another variant of this method */
6077 if (fontface1) {
6078 for (i = 0; i < ARRAY_SIZE(recmode_tests1); i++) {
6079 FLOAT dpi;
6081 ppdip = 1.0f;
6082 dpi = 96.0f * ppdip;
6083 mode = 10;
6084 gasp = get_gasp_flags(fontface, emsize, ppdip);
6085 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6086 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6087 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6088 ok(hr == S_OK, "got 0x%08x\n", hr);
6089 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6091 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6092 Win8 and Win10 handle this as expected. */
6093 if (emsize > 20.0f) {
6094 ppdip = 2.0f;
6095 dpi = 96.0f * ppdip;
6096 mode = 10;
6097 gasp = get_gasp_flags(fontface, emsize, ppdip);
6098 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6099 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6100 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6101 ok(hr == S_OK, "got 0x%08x\n", hr);
6102 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6104 ppdip = 0.5f;
6105 dpi = 96.0f * ppdip;
6106 mode = 10;
6107 gasp = get_gasp_flags(fontface, emsize, ppdip);
6108 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6109 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6110 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6111 ok(hr == S_OK, "got 0x%08x\n", hr);
6112 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6114 /* try different dpis for X and Y direction */
6115 ppdip = 1.0f;
6116 dpi = 96.0f * ppdip;
6117 mode = 10;
6118 gasp = get_gasp_flags(fontface, emsize, ppdip);
6119 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6120 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6121 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6122 ok(hr == S_OK, "got 0x%08x\n", hr);
6123 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6125 ppdip = 1.0f;
6126 dpi = 96.0f * ppdip;
6127 mode = 10;
6128 gasp = get_gasp_flags(fontface, emsize, ppdip);
6129 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6130 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
6131 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6132 ok(hr == S_OK, "got 0x%08x\n", hr);
6133 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6135 ppdip = 2.0f;
6136 dpi = 96.0f * ppdip;
6137 mode = 10;
6138 gasp = get_gasp_flags(fontface, emsize, ppdip);
6139 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6140 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6141 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6142 ok(hr == S_OK, "got 0x%08x\n", hr);
6143 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6145 ppdip = 2.0f;
6146 dpi = 96.0f * ppdip;
6147 mode = 10;
6148 gasp = get_gasp_flags(fontface, emsize, ppdip);
6149 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6150 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
6151 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6152 ok(hr == S_OK, "got 0x%08x\n", hr);
6153 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6158 /* IDWriteFontFace2 - another one */
6159 if (fontface2) {
6160 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
6162 gasp = get_gasp_flags(fontface, emsize, 1.0f);
6163 for (i = 0; i < ARRAY_SIZE(recmode_tests1); i++) {
6164 mode = 10;
6165 expected = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6166 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6167 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, emsize, 96.0f, 96.0f,
6168 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode, &gridfit);
6169 ok(hr == S_OK, "got 0x%08x\n", hr);
6170 ok(mode == expected, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode, gasp, expected);
6171 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
6172 gasp, expected_gridfit);
6176 /* IDWriteFontFace3 - and another one */
6177 if (fontface3) {
6178 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
6179 DWRITE_RENDERING_MODE1 mode1, expected1;
6181 gasp = get_gasp_flags(fontface, emsize, 1.0f);
6182 for (i = 0; i < ARRAY_SIZE(recmode_tests1); i++) {
6183 mode1 = 10;
6184 expected1 = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6185 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6186 hr = IDWriteFontFace3_GetRecommendedRenderingMode(fontface3, emsize, 96.0f, 96.0f,
6187 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode1, &gridfit);
6188 ok(hr == S_OK, "got 0x%08x\n", hr);
6189 ok(mode1 == expected1, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode1, gasp, expected1);
6190 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
6191 gasp, expected_gridfit);
6196 IDWriteRenderingParams_Release(params);
6198 /* test how parameters override returned modes */
6199 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
6200 DWRITE_RENDERING_MODE_GDI_CLASSIC, &params);
6201 ok(hr == S_OK, "got 0x%08x\n", hr);
6203 mode = 10;
6204 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode);
6205 ok(hr == S_OK, "got 0x%08x\n", hr);
6206 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
6208 IDWriteRenderingParams_Release(params);
6210 if (fontface2) {
6211 IDWriteRenderingParams2 *params2;
6212 IDWriteFactory2 *factory2;
6213 DWRITE_GRID_FIT_MODE gridfit;
6215 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
6216 ok(hr == S_OK, "got 0x%08x\n", hr);
6218 hr = IDWriteFactory2_CreateCustomRenderingParams(factory2, 1.0, 0.0, 0.0, 0.5, DWRITE_PIXEL_GEOMETRY_FLAT,
6219 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_GRID_FIT_MODE_ENABLED, &params2);
6220 ok(hr == S_OK, "got 0x%08x\n", hr);
6222 mode = 10;
6223 gridfit = 10;
6224 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
6225 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6226 NULL, &mode, &gridfit);
6227 ok(hr == S_OK, "got 0x%08x\n", hr);
6228 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
6229 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6231 mode = 10;
6232 gridfit = 10;
6233 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
6234 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6235 (IDWriteRenderingParams*)params2, &mode, &gridfit);
6236 ok(hr == S_OK, "got 0x%08x\n", hr);
6237 ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode);
6238 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6240 IDWriteRenderingParams2_Release(params2);
6241 IDWriteFactory2_Release(factory2);
6244 if (fontface3) {
6245 IDWriteRenderingParams3 *params3;
6246 IDWriteRenderingParams2 *params2;
6247 IDWriteRenderingParams *params;
6248 IDWriteFactory3 *factory3;
6249 DWRITE_GRID_FIT_MODE gridfit;
6250 DWRITE_RENDERING_MODE1 mode1;
6252 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
6253 ok(hr == S_OK, "got 0x%08x\n", hr);
6255 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 0.5f, DWRITE_PIXEL_GEOMETRY_FLAT,
6256 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_ENABLED, &params3);
6257 ok(hr == S_OK, "got 0x%08x\n", hr);
6259 mode1 = IDWriteRenderingParams3_GetRenderingMode1(params3);
6260 ok(mode1 == DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, "got %d\n", mode1);
6262 mode = IDWriteRenderingParams3_GetRenderingMode(params3);
6263 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6265 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
6266 ok(hr == S_OK, "got 0x%08x\n", hr);
6267 ok(params == (IDWriteRenderingParams*)params3, "got %p, %p\n", params3, params);
6268 mode = IDWriteRenderingParams_GetRenderingMode(params);
6269 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6270 IDWriteRenderingParams_Release(params);
6272 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams2, (void**)&params2);
6273 ok(hr == S_OK, "got 0x%08x\n", hr);
6274 ok(params2 == (IDWriteRenderingParams2*)params3, "got %p, %p\n", params3, params2);
6275 mode = IDWriteRenderingParams2_GetRenderingMode(params2);
6276 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6277 IDWriteRenderingParams2_Release(params2);
6279 mode = 10;
6280 gridfit = 10;
6281 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
6282 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6283 NULL, &mode, &gridfit);
6284 ok(hr == S_OK, "got 0x%08x\n", hr);
6285 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
6286 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6288 mode = 10;
6289 gridfit = 10;
6290 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
6291 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6292 (IDWriteRenderingParams*)params3, &mode, &gridfit);
6293 ok(hr == S_OK, "got 0x%08x\n", hr);
6294 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6295 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6297 IDWriteRenderingParams3_Release(params3);
6298 IDWriteFactory3_Release(factory3);
6301 if (fontface3)
6302 IDWriteFontFace3_Release(fontface3);
6303 if (fontface2)
6304 IDWriteFontFace2_Release(fontface2);
6305 if (fontface1)
6306 IDWriteFontFace1_Release(fontface1);
6307 IDWriteFontFace_Release(fontface);
6308 ref = IDWriteFactory_Release(factory);
6309 ok(ref == 0, "factory not released, %u\n", ref);
6312 static inline BOOL float_eq(FLOAT left, FLOAT right)
6314 int x = *(int *)&left;
6315 int y = *(int *)&right;
6317 if (x < 0)
6318 x = INT_MIN - x;
6319 if (y < 0)
6320 y = INT_MIN - y;
6322 return abs(x - y) <= 8;
6325 static void test_GetAlphaBlendParams(void)
6327 static const DWRITE_RENDERING_MODE rendermodes[] = {
6328 DWRITE_RENDERING_MODE_ALIASED,
6329 DWRITE_RENDERING_MODE_GDI_CLASSIC,
6330 DWRITE_RENDERING_MODE_GDI_NATURAL,
6331 DWRITE_RENDERING_MODE_NATURAL,
6332 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
6335 IDWriteGlyphRunAnalysis *analysis;
6336 FLOAT gamma, contrast, ctlevel;
6337 IDWriteRenderingParams *params;
6338 DWRITE_GLYPH_METRICS metrics;
6339 DWRITE_GLYPH_OFFSET offset;
6340 IDWriteFontFace *fontface;
6341 IDWriteFactory *factory;
6342 DWRITE_GLYPH_RUN run;
6343 FLOAT advance, expected_gdi_gamma;
6344 UINT value = 0;
6345 UINT16 glyph;
6346 UINT32 ch, i;
6347 HRESULT hr;
6348 ULONG ref;
6349 BOOL ret;
6351 factory = create_factory();
6352 fontface = create_fontface(factory);
6354 ch = 'A';
6355 glyph = 0;
6356 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
6357 ok(hr == S_OK, "got 0x%08x\n", hr);
6358 ok(glyph > 0, "got %u\n", glyph);
6360 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
6361 ok(hr == S_OK, "got 0x%08x\n", hr);
6362 advance = metrics.advanceWidth;
6364 offset.advanceOffset = 0.0;
6365 offset.ascenderOffset = 0.0;
6367 run.fontFace = fontface;
6368 run.fontEmSize = 24.0;
6369 run.glyphCount = 1;
6370 run.glyphIndices = &glyph;
6371 run.glyphAdvances = &advance;
6372 run.glyphOffsets = &offset;
6373 run.isSideways = FALSE;
6374 run.bidiLevel = 0;
6376 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.9, 0.3, 0.1, DWRITE_PIXEL_GEOMETRY_RGB,
6377 DWRITE_RENDERING_MODE_DEFAULT, &params);
6378 ok(hr == S_OK, "got 0x%08x\n", hr);
6380 value = 0;
6381 ret = SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
6382 ok(ret, "got %d\n", ret);
6383 expected_gdi_gamma = (FLOAT)(value / 1000.0);
6385 for (i = 0; i < ARRAY_SIZE(rendermodes); i++) {
6386 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
6387 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
6388 0.0, 0.0, &analysis);
6389 ok(hr == S_OK, "got 0x%08x\n", hr);
6391 gamma = contrast = ctlevel = -1.0;
6392 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, NULL, &gamma, &contrast, &ctlevel);
6393 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6394 ok(gamma == -1.0, "got %.2f\n", gamma);
6395 ok(contrast == -1.0, "got %.2f\n", contrast);
6396 ok(ctlevel == -1.0, "got %.2f\n", ctlevel);
6398 gamma = contrast = ctlevel = -1.0;
6399 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &ctlevel);
6400 ok(hr == S_OK, "got 0x%08x\n", hr);
6402 if (rendermodes[i] == DWRITE_RENDERING_MODE_GDI_CLASSIC || rendermodes[i] == DWRITE_RENDERING_MODE_GDI_NATURAL) {
6403 ok(float_eq(gamma, expected_gdi_gamma), "got %.2f, expected %.2f\n", gamma, expected_gdi_gamma);
6404 ok(contrast == 0.0f, "got %.2f\n", contrast);
6405 ok(ctlevel == 1.0f, "got %.2f\n", ctlevel);
6407 else {
6408 ok(gamma == 0.9f, "got %.2f\n", gamma);
6409 ok(contrast == 0.3f, "got %.2f\n", contrast);
6410 ok(ctlevel == 0.1f, "got %.2f\n", ctlevel);
6413 IDWriteGlyphRunAnalysis_Release(analysis);
6416 IDWriteRenderingParams_Release(params);
6417 IDWriteFontFace_Release(fontface);
6418 ref = IDWriteFactory_Release(factory);
6419 ok(ref == 0, "factory not released, %u\n", ref);
6422 static void test_CreateAlphaTexture(void)
6424 IDWriteGlyphRunAnalysis *analysis;
6425 DWRITE_GLYPH_METRICS metrics;
6426 DWRITE_GLYPH_OFFSET offset;
6427 IDWriteFontFace *fontface;
6428 IDWriteFactory *factory;
6429 DWRITE_GLYPH_RUN run;
6430 UINT32 ch, size;
6431 BYTE buff[1024];
6432 RECT bounds, r;
6433 FLOAT advance;
6434 UINT16 glyph;
6435 HRESULT hr;
6436 ULONG ref;
6438 factory = create_factory();
6439 fontface = create_fontface(factory);
6441 ch = 'A';
6442 glyph = 0;
6443 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
6444 ok(hr == S_OK, "got 0x%08x\n", hr);
6445 ok(glyph > 0, "got %u\n", glyph);
6447 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
6448 ok(hr == S_OK, "got 0x%08x\n", hr);
6449 advance = metrics.advanceWidth;
6451 offset.advanceOffset = 0.0;
6452 offset.ascenderOffset = 0.0;
6454 run.fontFace = fontface;
6455 run.fontEmSize = 24.0;
6456 run.glyphCount = 1;
6457 run.glyphIndices = &glyph;
6458 run.glyphAdvances = &advance;
6459 run.glyphOffsets = &offset;
6460 run.isSideways = FALSE;
6461 run.bidiLevel = 0;
6463 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
6464 DWRITE_RENDERING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
6465 0.0, 0.0, &analysis);
6466 ok(hr == S_OK, "got 0x%08x\n", hr);
6468 SetRectEmpty(&bounds);
6469 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
6470 ok(hr == S_OK, "got 0x%08x\n", hr);
6471 ok(!IsRectEmpty(&bounds), "got empty rect\n");
6472 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top)*3;
6473 ok(sizeof(buff) >= size, "required %u\n", size);
6475 /* invalid type value */
6476 memset(buff, 0xcf, sizeof(buff));
6477 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &bounds, buff, sizeof(buff));
6478 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6479 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6481 memset(buff, 0xcf, sizeof(buff));
6482 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, 2);
6483 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6484 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6486 /* vista version allows texture type mismatch, mark it broken for now */
6487 memset(buff, 0xcf, sizeof(buff));
6488 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, sizeof(buff));
6489 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
6490 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
6492 memset(buff, 0xcf, sizeof(buff));
6493 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, size-1);
6494 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6495 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6497 IDWriteGlyphRunAnalysis_Release(analysis);
6499 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
6500 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6501 0.0, 0.0, &analysis);
6502 ok(hr == S_OK, "got 0x%08x\n", hr);
6504 SetRectEmpty(&bounds);
6505 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
6506 ok(hr == S_OK, "got 0x%08x\n", hr);
6507 ok(!IsRectEmpty(&bounds), "got empty rect\n");
6508 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
6509 ok(sizeof(buff) >= size, "required %u\n", size);
6511 memset(buff, 0xcf, sizeof(buff));
6512 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, sizeof(buff));
6513 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6514 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6516 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, NULL, sizeof(buff));
6517 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6519 memset(buff, 0xcf, sizeof(buff));
6520 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, 0);
6521 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6522 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6524 /* buffer size is not enough */
6525 memset(buff, 0xcf, sizeof(buff));
6526 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, size-1);
6527 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6528 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6530 /* request texture for rectangle that doesn't intersect */
6531 memset(buff, 0xcf, sizeof(buff));
6532 r = bounds;
6533 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
6534 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
6535 ok(hr == S_OK, "got 0x%08x\n", hr);
6536 ok(buff[0] == 0, "got %1x\n", buff[0]);
6538 memset(buff, 0xcf, sizeof(buff));
6539 r = bounds;
6540 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
6541 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
6542 ok(hr == S_OK, "got 0x%08x\n", hr);
6543 ok(buff[0] == 0, "got %1x\n", buff[0]);
6545 /* request texture for rectangle that doesn't intersect, small buffer */
6546 memset(buff, 0xcf, sizeof(buff));
6547 r = bounds;
6548 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
6549 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, size-1);
6550 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6551 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6553 /* vista version allows texture type mismatch, mark it broken for now */
6554 memset(buff, 0xcf, sizeof(buff));
6555 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, sizeof(buff));
6556 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
6557 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
6559 IDWriteGlyphRunAnalysis_Release(analysis);
6560 IDWriteFontFace_Release(fontface);
6561 ref = IDWriteFactory_Release(factory);
6562 ok(ref == 0, "factory not released, %u\n", ref);
6565 static void test_IsSymbolFont(void)
6567 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
6568 IDWriteFontCollection *collection;
6569 IDWriteFontFace *fontface;
6570 IDWriteFactory *factory;
6571 IDWriteFont *font;
6572 HRESULT hr;
6573 ULONG ref;
6574 BOOL ret;
6576 factory = create_factory();
6578 /* Tahoma */
6579 fontface = create_fontface(factory);
6580 ret = IDWriteFontFace_IsSymbolFont(fontface);
6581 ok(!ret, "got %d\n", ret);
6583 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
6584 ok(hr == S_OK, "got 0x%08x\n", hr);
6586 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font);
6587 ok(hr == S_OK, "got 0x%08x\n", hr);
6589 ret = IDWriteFont_IsSymbolFont(font);
6590 ok(!ret, "got %d\n", ret);
6592 IDWriteFontCollection_Release(collection);
6593 IDWriteFont_Release(font);
6594 IDWriteFontFace_Release(fontface);
6596 /* Symbol */
6597 font = get_font(factory, symbolW, DWRITE_FONT_STYLE_NORMAL);
6598 ret = IDWriteFont_IsSymbolFont(font);
6599 ok(ret, "got %d\n", ret);
6601 hr = IDWriteFont_CreateFontFace(font, &fontface);
6602 ok(hr == S_OK, "got 0x%08x\n", hr);
6603 ret = IDWriteFontFace_IsSymbolFont(fontface);
6604 ok(ret, "got %d\n", ret);
6605 IDWriteFontFace_Release(fontface);
6606 IDWriteFont_Release(font);
6608 ref = IDWriteFactory_Release(factory);
6609 ok(ref == 0, "factory not released, %u\n", ref);
6612 struct CPAL_Header_0
6614 USHORT version;
6615 USHORT numPaletteEntries;
6616 USHORT numPalette;
6617 USHORT numColorRecords;
6618 ULONG offsetFirstColorRecord;
6619 USHORT colorRecordIndices[1];
6622 static void test_GetPaletteEntries(void)
6624 IDWriteFontFace2 *fontface2;
6625 IDWriteFontFace *fontface;
6626 IDWriteFactory *factory;
6627 IDWriteFont *font;
6628 DWRITE_COLOR_F color;
6629 UINT32 palettecount, entrycount, size, colorrecords;
6630 void *ctxt;
6631 const struct CPAL_Header_0 *cpal_header;
6632 HRESULT hr;
6633 BOOL exists;
6634 ULONG ref;
6636 factory = create_factory();
6638 /* Tahoma, no color support */
6639 fontface = create_fontface(factory);
6640 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6641 IDWriteFontFace_Release(fontface);
6642 if (hr != S_OK) {
6643 ref = IDWriteFactory_Release(factory);
6644 ok(ref == 0, "factory not released, %u\n", ref);
6645 win_skip("GetPaletteEntries() is not supported.\n");
6646 return;
6649 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 1, &color);
6650 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6651 IDWriteFontFace2_Release(fontface2);
6653 /* Segoe UI Emoji, with color support */
6654 font = get_font(factory, emojiW, DWRITE_FONT_STYLE_NORMAL);
6655 if (!font) {
6656 ref = IDWriteFactory_Release(factory);
6657 ok(ref == 0, "factory not released, %u\n", ref);
6658 skip("Segoe UI Emoji font not found.\n");
6659 return;
6662 hr = IDWriteFont_CreateFontFace(font, &fontface);
6663 ok(hr == S_OK, "got 0x%08x\n", hr);
6664 IDWriteFont_Release(font);
6666 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6667 ok(hr == S_OK, "got 0x%08x\n", hr);
6668 IDWriteFontFace_Release(fontface);
6670 palettecount = IDWriteFontFace2_GetColorPaletteCount(fontface2);
6671 ok(palettecount >= 1, "got %u\n", palettecount);
6673 entrycount = IDWriteFontFace2_GetPaletteEntryCount(fontface2);
6674 ok(entrycount >= 1, "got %u\n", entrycount);
6676 exists = FALSE;
6677 hr = IDWriteFontFace2_TryGetFontTable(fontface2, MS_CPAL_TAG, (const void**)&cpal_header, &size, &ctxt, &exists);
6678 ok(hr == S_OK, "got 0x%08x\n", hr);
6679 ok(exists, "got %d\n", exists);
6680 colorrecords = GET_BE_WORD(cpal_header->numColorRecords);
6681 ok(colorrecords >= 1, "got %u\n", colorrecords);
6683 /* invalid palette index */
6684 color.r = color.g = color.b = color.a = 123.0;
6685 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, palettecount, 0, 1, &color);
6686 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6687 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6688 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6690 /* invalid entry index */
6691 color.r = color.g = color.b = color.a = 123.0;
6692 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount, 1, &color);
6693 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6694 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6695 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6697 color.r = color.g = color.b = color.a = 123.0;
6698 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount - 1, 1, &color);
6699 ok(hr == S_OK, "got 0x%08x\n", hr);
6700 ok(color.r != 123.0 && color.g != 123.0 && color.b != 123.0 && color.a != 123.0,
6701 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6703 /* zero return length */
6704 color.r = color.g = color.b = color.a = 123.0;
6705 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 0, &color);
6706 ok(hr == S_OK, "got 0x%08x\n", hr);
6707 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6708 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6710 IDWriteFontFace2_Release(fontface2);
6711 ref = IDWriteFactory_Release(factory);
6712 ok(ref == 0, "factory not released, %u\n", ref);
6715 static void test_TranslateColorGlyphRun(void)
6717 IDWriteColorGlyphRunEnumerator *layers;
6718 const DWRITE_COLOR_GLYPH_RUN *colorrun;
6719 IDWriteFontFace2 *fontface2;
6720 IDWriteFontFace *fontface;
6721 IDWriteFactory2 *factory;
6722 DWRITE_GLYPH_RUN run;
6723 UINT32 codepoints[2];
6724 IDWriteFont *font;
6725 UINT16 glyphs[2];
6726 BOOL hasrun;
6727 HRESULT hr;
6728 ULONG ref;
6730 factory = create_factory_iid(&IID_IDWriteFactory2);
6731 if (!factory) {
6732 win_skip("TranslateColorGlyphRun() is not supported.\n");
6733 return;
6736 /* Tahoma, no color support */
6737 fontface = create_fontface((IDWriteFactory *)factory);
6739 codepoints[0] = 'A';
6740 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6741 ok(hr == S_OK, "got 0x%08x\n", hr);
6743 run.fontFace = fontface;
6744 run.fontEmSize = 20.0f;
6745 run.glyphCount = 1;
6746 run.glyphIndices = glyphs;
6747 run.glyphAdvances = NULL;
6748 run.glyphOffsets = NULL;
6749 run.isSideways = FALSE;
6750 run.bidiLevel = 0;
6752 layers = (void*)0xdeadbeef;
6753 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6754 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6755 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6756 ok(layers == NULL, "got %p\n", layers);
6757 IDWriteFontFace_Release(fontface);
6759 /* Segoe UI Emoji, with color support */
6760 font = get_font((IDWriteFactory *)factory, emojiW, DWRITE_FONT_STYLE_NORMAL);
6761 if (!font) {
6762 IDWriteFactory2_Release(factory);
6763 skip("Segoe UI Emoji font not found.\n");
6764 return;
6767 hr = IDWriteFont_CreateFontFace(font, &fontface);
6768 ok(hr == S_OK, "got 0x%08x\n", hr);
6769 IDWriteFont_Release(font);
6771 codepoints[0] = 0x26c4;
6772 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6773 ok(hr == S_OK, "got 0x%08x\n", hr);
6775 run.fontFace = fontface;
6777 layers = NULL;
6778 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6779 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6780 ok(hr == S_OK, "got 0x%08x\n", hr);
6781 ok(layers != NULL, "got %p\n", layers);
6783 for (;;) {
6784 hasrun = FALSE;
6785 hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &hasrun);
6786 ok(hr == S_OK, "got 0x%08x\n", hr);
6788 if (!hasrun)
6789 break;
6791 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
6792 ok(hr == S_OK, "got 0x%08x\n", hr);
6793 ok(colorrun->glyphRun.fontFace != NULL, "got fontface %p\n", colorrun->glyphRun.fontFace);
6794 ok(colorrun->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun->glyphRun.fontEmSize);
6795 ok(colorrun->glyphRun.glyphCount > 0, "got wrong glyph count %u\n", colorrun->glyphRun.glyphCount);
6796 ok(colorrun->glyphRun.glyphIndices != NULL, "got null glyph indices %p\n", colorrun->glyphRun.glyphIndices);
6797 ok(colorrun->glyphRun.glyphAdvances != NULL, "got null glyph advances %p\n", colorrun->glyphRun.glyphAdvances);
6800 /* iterated all way through */
6801 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
6802 ok(hr == E_NOT_VALID_STATE, "got 0x%08x\n", hr);
6804 IDWriteColorGlyphRunEnumerator_Release(layers);
6806 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6807 ok(hr == S_OK, "got 0x%08x\n", hr);
6809 /* invalid palette index */
6810 layers = (void*)0xdeadbeef;
6811 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6812 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2),
6813 &layers);
6814 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6815 ok(layers == NULL, "got %p\n", layers);
6817 layers = NULL;
6818 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6819 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2) - 1,
6820 &layers);
6821 ok(hr == S_OK, "got 0x%08x\n", hr);
6822 IDWriteColorGlyphRunEnumerator_Release(layers);
6824 /* color font, glyph without color info */
6825 codepoints[0] = 'A';
6826 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6827 ok(hr == S_OK, "got 0x%08x\n", hr);
6829 layers = (void*)0xdeadbeef;
6830 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6831 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6832 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6833 ok(layers == NULL, "got %p\n", layers);
6835 /* one glyph with, one without */
6836 codepoints[0] = 'A';
6837 codepoints[1] = 0x26c4;
6839 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 2, glyphs);
6840 ok(hr == S_OK, "got 0x%08x\n", hr);
6842 run.glyphCount = 2;
6844 layers = NULL;
6845 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6846 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6847 ok(hr == S_OK, "got 0x%08x\n", hr);
6848 ok(layers != NULL, "got %p\n", layers);
6849 IDWriteColorGlyphRunEnumerator_Release(layers);
6851 IDWriteFontFace2_Release(fontface2);
6852 IDWriteFontFace_Release(fontface);
6853 ref = IDWriteFactory2_Release(factory);
6854 ok(ref == 0, "factory not released, %u\n", ref);
6857 static void test_HasCharacter(void)
6859 IDWriteFactory3 *factory3;
6860 IDWriteFactory *factory;
6861 IDWriteFont3 *font3;
6862 IDWriteFont *font;
6863 HRESULT hr;
6864 ULONG ref;
6865 BOOL ret;
6867 factory = create_factory();
6869 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6870 ok(font != NULL, "failed to create font\n");
6872 /* Win8 is broken, QI claims to support IDWriteFont3, but in fact it does not */
6873 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
6874 if (hr == S_OK) {
6875 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
6876 ok(hr == S_OK, "got 0x%08x\n", hr);
6878 ret = IDWriteFont3_HasCharacter(font3, 'A');
6879 ok(ret, "got %d\n", ret);
6881 IDWriteFont3_Release(font3);
6882 IDWriteFactory3_Release(factory3);
6884 else
6885 win_skip("IDWriteFont3 is not supported.\n");
6887 IDWriteFont_Release(font);
6888 ref = IDWriteFactory_Release(factory);
6889 ok(ref == 0, "factory not released, %u\n", ref);
6892 static void test_CreateFontFaceReference(void)
6894 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
6895 IDWriteFontFace3 *fontface, *fontface1;
6896 IDWriteFontFaceReference *ref, *ref1;
6897 IDWriteFontFile *file, *file1;
6898 IDWriteFactory3 *factory;
6899 IDWriteFont3 *font3;
6900 IDWriteFont *font;
6901 ULONG refcount;
6902 UINT32 index;
6903 WCHAR *path;
6904 HRESULT hr;
6905 BOOL ret;
6907 factory = create_factory_iid(&IID_IDWriteFactory3);
6908 if (!factory) {
6909 win_skip("CreateFontFaceReference() is not supported.\n");
6910 return;
6913 path = create_testfontfile(test_fontfile);
6915 hr = IDWriteFactory3_CreateFontFaceReference(factory, NULL, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6916 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6918 /* out of range simulation flags */
6919 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, ~0u, &ref);
6920 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6922 /* test file is not a collection, but reference could still be created with non-zero face index */
6923 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6924 ok(hr == S_OK, "got 0x%08x\n", hr);
6926 index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
6927 ok(index == 1, "got %u\n", index);
6929 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
6930 ok(hr == S_OK, "got 0x%08x\n", hr);
6931 IDWriteFontFile_Release(file);
6933 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
6934 todo_wine
6935 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
6937 IDWriteFontFaceReference_Release(ref);
6939 /* path however has to be valid */
6940 hr = IDWriteFactory3_CreateFontFaceReference(factory, dummyW, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6941 todo_wine
6942 ok(hr == DWRITE_E_FILENOTFOUND, "got 0x%08x\n", hr);
6943 if (hr == S_OK)
6944 IDWriteFontFaceReference_Release(ref);
6946 EXPECT_REF(factory, 1);
6947 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6948 ok(hr == S_OK, "got 0x%08x\n", hr);
6949 EXPECT_REF(factory, 2);
6951 /* new file is returned */
6952 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
6953 ok(hr == S_OK, "got 0x%08x\n", hr);
6955 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
6956 ok(hr == S_OK, "got 0x%08x\n", hr);
6957 ok(file != file1, "got %p, previous file %p\n", file1, file);
6959 IDWriteFontFile_Release(file);
6960 IDWriteFontFile_Release(file1);
6962 /* references are not reused */
6963 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
6964 ok(hr == S_OK, "got 0x%08x\n", hr);
6965 ok(ref1 != ref, "got %p, previous ref %p\n", ref1, ref);
6967 /* created fontfaces are cached */
6968 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
6969 ok(hr == S_OK, "got 0x%08x\n", hr);
6971 hr = IDWriteFontFaceReference_CreateFontFace(ref1, &fontface1);
6972 ok(hr == S_OK, "got 0x%08x\n", hr);
6973 ok(fontface == fontface1, "got %p, expected %p\n", fontface1, fontface);
6974 IDWriteFontFace3_Release(fontface);
6975 IDWriteFontFace3_Release(fontface1);
6977 /* reference equality */
6978 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6979 ok(ret, "got %d\n", ret);
6980 IDWriteFontFaceReference_Release(ref1);
6982 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
6983 ok(hr == S_OK, "got 0x%08x\n", hr);
6984 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6985 ok(!ret, "got %d\n", ret);
6986 IDWriteFontFaceReference_Release(ref1);
6988 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_BOLD, &ref1);
6989 ok(hr == S_OK, "got 0x%08x\n", hr);
6990 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6991 ok(!ret, "got %d\n", ret);
6992 IDWriteFontFaceReference_Release(ref1);
6994 IDWriteFontFaceReference_Release(ref);
6996 /* create reference from a file */
6997 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
6998 ok(hr == S_OK, "got 0x%08x\n", hr);
7000 hr = IDWriteFactory3_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
7001 ok(hr == S_OK, "got 0x%08x\n", hr);
7003 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
7004 ok(hr == S_OK, "got 0x%08x\n", hr);
7005 ok(file != file1, "got %p, previous file %p\n", file1, file);
7007 IDWriteFontFaceReference_Release(ref);
7008 IDWriteFontFile_Release(file);
7009 IDWriteFontFile_Release(file1);
7011 /* references returned from IDWriteFont3 */
7012 font = get_tahoma_instance((IDWriteFactory *)factory, DWRITE_FONT_STYLE_NORMAL);
7013 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
7014 ok(hr == S_OK, "got 0x%08x\n", hr);
7015 IDWriteFont_Release(font);
7017 hr = IDWriteFont3_GetFontFaceReference(font3, &ref);
7018 ok(hr == S_OK, "got 0x%08x\n", hr);
7020 hr = IDWriteFont3_GetFontFaceReference(font3, &ref1);
7021 ok(hr == S_OK, "got 0x%08x\n", hr);
7022 ok(ref != ref1, "got %p, %p\n", ref1, ref);
7024 IDWriteFontFaceReference_Release(ref);
7025 IDWriteFontFaceReference_Release(ref1);
7027 /* references returned from IDWriteFontFace3 */
7028 hr = IDWriteFont3_CreateFontFace(font3, &fontface);
7029 ok(hr == S_OK, "got 0x%08x\n", hr);
7031 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref);
7032 todo_wine
7033 ok(hr == S_OK, "got 0x%08x\n", hr);
7035 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref1);
7036 todo_wine
7037 ok(hr == S_OK, "got 0x%08x\n", hr);
7038 if (hr == S_OK)
7039 ok(ref == ref1, "got %p, %p\n", ref1, ref);
7041 if (hr == S_OK) {
7042 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface1);
7043 ok(hr == S_OK, "got 0x%08x\n", hr);
7044 ok(fontface1 == fontface, "got %p, %p\n", fontface1, fontface);
7045 IDWriteFontFace3_Release(fontface1);
7047 IDWriteFontFaceReference_Release(ref);
7048 IDWriteFontFaceReference_Release(ref1);
7050 IDWriteFontFace3_Release(fontface);
7051 IDWriteFont3_Release(font3);
7053 refcount = IDWriteFactory3_Release(factory);
7054 ok(refcount == 0, "factory not released, %u\n", refcount);
7055 DELETE_FONTFILE(path);
7058 static void get_expected_fontsig(IDWriteFont *font, FONTSIGNATURE *fontsig)
7060 void *os2_context;
7061 IDWriteFontFace *fontface;
7062 const TT_OS2_V2 *tt_os2;
7063 UINT32 size;
7064 BOOL exists;
7065 HRESULT hr;
7067 memset(fontsig, 0, sizeof(*fontsig));
7069 hr = IDWriteFont_CreateFontFace(font, &fontface);
7070 ok(hr == S_OK, "got 0x%08x\n", hr);
7072 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void**)&tt_os2, &size, &os2_context, &exists);
7073 ok(hr == S_OK, "got 0x%08x\n", hr);
7075 if (tt_os2) {
7076 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
7077 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
7078 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
7079 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
7081 if (GET_BE_WORD(tt_os2->version) == 0) {
7082 fontsig->fsCsb[0] = 0;
7083 fontsig->fsCsb[1] = 0;
7085 else {
7086 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
7087 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
7090 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
7093 IDWriteFontFace_Release(fontface);
7096 static void test_GetFontSignature(void)
7098 IDWriteFontCollection *syscollection;
7099 IDWriteGdiInterop1 *interop1;
7100 IDWriteGdiInterop *interop;
7101 IDWriteFactory *factory;
7102 FONTSIGNATURE fontsig;
7103 UINT count, i;
7104 HRESULT hr;
7105 ULONG ref;
7107 factory = create_factory();
7109 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
7110 ok(hr == S_OK, "got 0x%08x\n", hr);
7112 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
7113 IDWriteGdiInterop_Release(interop);
7114 if (FAILED(hr)) {
7115 win_skip("GetFontSignature() is not supported.\n");
7116 IDWriteGdiInterop_Release(interop);
7117 IDWriteFactory_Release(factory);
7118 return;
7120 ok(hr == S_OK, "got 0x%08x\n", hr);
7122 hr = IDWriteGdiInterop1_GetFontSignature(interop1, NULL, &fontsig);
7123 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7125 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
7126 ok(hr == S_OK, "got 0x%08x\n", hr);
7127 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
7129 for (i = 0; i < count; i++) {
7130 FONTSIGNATURE expected_signature;
7131 IDWriteLocalizedStrings *names;
7132 IDWriteFontFamily *family;
7133 IDWriteFont *font;
7134 WCHAR nameW[256];
7136 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
7137 ok(hr == S_OK, "got 0x%08x\n", hr);
7139 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
7140 DWRITE_FONT_STYLE_NORMAL, &font);
7141 ok(hr == S_OK, "got 0x%08x\n", hr);
7143 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7144 ok(hr == S_OK, "got 0x%08x\n", hr);
7146 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
7148 IDWriteLocalizedStrings_Release(names);
7150 hr = IDWriteGdiInterop1_GetFontSignature(interop1, font, &fontsig);
7151 ok(hr == S_OK, "got 0x%08x\n", hr);
7153 get_expected_fontsig(font, &expected_signature);
7155 ok(fontsig.fsUsb[0] == expected_signature.fsUsb[0], "%s: fsUsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7156 fontsig.fsUsb[0], expected_signature.fsUsb[0]);
7157 ok(fontsig.fsUsb[1] == expected_signature.fsUsb[1], "%s: fsUsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7158 fontsig.fsUsb[1], expected_signature.fsUsb[1]);
7159 ok(fontsig.fsUsb[2] == expected_signature.fsUsb[2], "%s: fsUsb[2] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7160 fontsig.fsUsb[2], expected_signature.fsUsb[2]);
7161 ok(fontsig.fsUsb[3] == expected_signature.fsUsb[3], "%s: fsUsb[3] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7162 fontsig.fsUsb[3], expected_signature.fsUsb[3]);
7164 ok(fontsig.fsCsb[0] == expected_signature.fsCsb[0], "%s: fsCsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7165 fontsig.fsCsb[0], expected_signature.fsCsb[0]);
7166 ok(fontsig.fsCsb[1] == expected_signature.fsCsb[1], "%s: fsCsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7167 fontsig.fsCsb[1], expected_signature.fsCsb[1]);
7169 IDWriteFont_Release(font);
7170 IDWriteFontFamily_Release(family);
7173 IDWriteGdiInterop1_Release(interop1);
7174 IDWriteFontCollection_Release(syscollection);
7175 ref = IDWriteFactory_Release(factory);
7176 ok(ref == 0, "factory not released, %u\n", ref);
7179 static void test_font_properties(void)
7181 IDWriteFontFace3 *fontface3;
7182 IDWriteFontFace *fontface;
7183 IDWriteFactory *factory;
7184 DWRITE_FONT_STYLE style;
7185 IDWriteFont *font;
7186 HRESULT hr;
7187 ULONG ref;
7189 factory = create_factory();
7191 /* this creates simulated font */
7192 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
7194 style = IDWriteFont_GetStyle(font);
7195 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
7197 hr = IDWriteFont_CreateFontFace(font, &fontface);
7198 ok(hr == S_OK, "got 0x%08x\n", hr);
7200 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
7201 IDWriteFontFace_Release(fontface);
7202 if (hr == S_OK) {
7203 style = IDWriteFontFace3_GetStyle(fontface3);
7204 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
7206 IDWriteFontFace3_Release(fontface3);
7209 IDWriteFont_Release(font);
7210 ref = IDWriteFactory_Release(factory);
7211 ok(ref == 0, "factory not released, %u\n", ref);
7214 static BOOL has_vertical_glyph_variants(IDWriteFontFace1 *fontface)
7216 const OT_FeatureList *featurelist;
7217 const OT_LookupList *lookup_list;
7218 BOOL exists = FALSE, ret = FALSE;
7219 const GSUB_Header *header;
7220 const void *data;
7221 void *context;
7222 UINT32 size;
7223 HRESULT hr;
7224 UINT16 i;
7226 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
7227 ok(hr == S_OK, "got 0x%08x\n", hr);
7229 if (!exists)
7230 return FALSE;
7232 header = data;
7233 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
7234 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
7236 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
7237 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
7238 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
7239 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
7240 const GSUB_SingleSubstFormat2 *subst2;
7241 const OT_LookupTable *lookup_table;
7242 UINT32 offset;
7244 if (lookup_count == 0)
7245 continue;
7247 for (i = 0; i < lookup_count; i++) {
7248 /* check if lookup is empty */
7249 index = GET_BE_WORD(feature->LookupListIndex[i]);
7250 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
7252 type = GET_BE_WORD(lookup_table->LookupType);
7253 ok(type == 1 || type == 7, "got unexpected lookup type %u\n", type);
7255 count = GET_BE_WORD(lookup_table->SubTableCount);
7256 if (count == 0)
7257 continue;
7259 ok(count > 0, "got unexpected subtable count %u\n", count);
7261 offset = GET_BE_WORD(lookup_table->SubTable[0]);
7262 if (type == 7) {
7263 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
7264 if (GET_BE_WORD(ext->SubstFormat) == 1)
7265 offset += GET_BE_DWORD(ext->ExtensionOffset);
7266 else
7267 ok(0, "Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
7270 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
7271 index = GET_BE_WORD(subst2->SubstFormat);
7272 if (index == 1)
7273 ok(0, "validate Single Substitution Format 1\n");
7274 else if (index == 2) {
7275 /* SimSun-ExtB has 0 glyph count for this substitution */
7276 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
7277 ret = TRUE;
7278 break;
7281 else
7282 ok(0, "unknown Single Substitution Format, %u\n", index);
7287 IDWriteFontFace1_ReleaseFontTable(fontface, context);
7289 return ret;
7292 static void test_HasVerticalGlyphVariants(void)
7294 IDWriteFontCollection *syscollection;
7295 IDWriteFontFace1 *fontface1;
7296 IDWriteFontFace *fontface;
7297 IDWriteFactory *factory;
7298 UINT32 count, i;
7299 HRESULT hr;
7300 ULONG ref;
7302 factory = create_factory();
7303 fontface = create_fontface(factory);
7305 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
7306 IDWriteFontFace_Release(fontface);
7307 if (hr != S_OK) {
7308 win_skip("HasVerticalGlyphVariants() is not supported.\n");
7309 IDWriteFactory_Release(factory);
7310 return;
7312 IDWriteFontFace1_Release(fontface1);
7314 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
7315 ok(hr == S_OK, "got 0x%08x\n", hr);
7316 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
7318 for (i = 0; i < count; i++) {
7319 IDWriteLocalizedStrings *names;
7320 BOOL expected_vert, has_vert;
7321 IDWriteFontFamily *family;
7322 IDWriteFont *font;
7323 WCHAR nameW[256];
7325 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
7326 ok(hr == S_OK, "got 0x%08x\n", hr);
7328 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
7329 DWRITE_FONT_STYLE_NORMAL, &font);
7330 ok(hr == S_OK, "got 0x%08x\n", hr);
7332 hr = IDWriteFont_CreateFontFace(font, &fontface);
7333 ok(hr == S_OK, "got 0x%08x\n", hr);
7335 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
7336 ok(hr == S_OK, "got 0x%08x\n", hr);
7338 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7339 ok(hr == S_OK, "got 0x%08x\n", hr);
7341 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
7343 expected_vert = has_vertical_glyph_variants(fontface1);
7344 has_vert = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
7346 ok(expected_vert == has_vert, "%s: expected vertical feature %d, got %d\n",
7347 wine_dbgstr_w(nameW), expected_vert, has_vert);
7349 IDWriteLocalizedStrings_Release(names);
7350 IDWriteFont_Release(font);
7352 IDWriteFontFace1_Release(fontface1);
7353 IDWriteFontFace_Release(fontface);
7354 IDWriteFontFamily_Release(family);
7357 IDWriteFontCollection_Release(syscollection);
7358 ref = IDWriteFactory_Release(factory);
7359 ok(ref == 0, "factory not released, %u\n", ref);
7362 static void test_HasKerningPairs(void)
7364 IDWriteFontCollection *syscollection;
7365 IDWriteFontFace1 *fontface1;
7366 IDWriteFontFace *fontface;
7367 IDWriteFactory *factory;
7368 UINT32 count, i;
7369 HRESULT hr;
7370 ULONG ref;
7372 factory = create_factory();
7373 fontface = create_fontface(factory);
7375 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
7376 IDWriteFontFace_Release(fontface);
7377 if (hr != S_OK) {
7378 win_skip("HasKerningPairs() is not supported.\n");
7379 IDWriteFactory_Release(factory);
7380 return;
7382 IDWriteFontFace1_Release(fontface1);
7384 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
7385 ok(hr == S_OK, "got 0x%08x\n", hr);
7386 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
7388 for (i = 0; i < count; i++) {
7389 IDWriteLocalizedStrings *names;
7390 BOOL exists, has_kerningpairs;
7391 IDWriteFontFamily *family;
7392 IDWriteFont *font;
7393 WCHAR nameW[256];
7394 const void *data;
7395 void *context;
7396 UINT32 size;
7398 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
7399 ok(hr == S_OK, "got 0x%08x\n", hr);
7401 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
7402 DWRITE_FONT_STYLE_NORMAL, &font);
7403 ok(hr == S_OK, "got 0x%08x\n", hr);
7405 hr = IDWriteFont_CreateFontFace(font, &fontface);
7406 ok(hr == S_OK, "got 0x%08x\n", hr);
7408 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
7409 ok(hr == S_OK, "got 0x%08x\n", hr);
7411 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7412 ok(hr == S_OK, "got 0x%08x\n", hr);
7414 get_enus_string(names, nameW, ARRAY_SIZE(nameW));
7416 exists = FALSE;
7417 hr = IDWriteFontFace1_TryGetFontTable(fontface1, MS_KERN_TAG, &data, &size, &context, &exists);
7418 ok(hr == S_OK, "got 0x%08x\n", hr);
7419 IDWriteFontFace1_ReleaseFontTable(fontface1, context);
7421 has_kerningpairs = IDWriteFontFace1_HasKerningPairs(fontface1);
7422 if (!exists)
7423 ok(!has_kerningpairs, "%s: expected %d, got %d\n", wine_dbgstr_w(nameW), exists, has_kerningpairs);
7425 IDWriteLocalizedStrings_Release(names);
7426 IDWriteFont_Release(font);
7428 IDWriteFontFace1_Release(fontface1);
7429 IDWriteFontFace_Release(fontface);
7430 IDWriteFontFamily_Release(family);
7433 IDWriteFontCollection_Release(syscollection);
7434 ref = IDWriteFactory_Release(factory);
7435 ok(ref == 0, "factory not released, %u\n", ref);
7438 static void test_ComputeGlyphOrigins(void)
7440 IDWriteFactory4 *factory;
7441 DWRITE_GLYPH_RUN run;
7442 HRESULT hr;
7443 D2D1_POINT_2F origins[2];
7444 D2D1_POINT_2F baseline_origin;
7445 UINT16 glyphs[2];
7446 FLOAT advances[2];
7447 DWRITE_MATRIX m;
7448 ULONG ref;
7450 factory = create_factory_iid(&IID_IDWriteFactory4);
7451 if (!factory) {
7452 win_skip("ComputeGlyphOrigins() is not supported.\n");
7453 return;
7456 advances[0] = 10.0f;
7457 advances[1] = 20.0f;
7459 run.fontFace = NULL;
7460 run.fontEmSize = 16.0f;
7461 run.glyphCount = 2;
7462 run.glyphIndices = glyphs;
7463 run.glyphAdvances = advances;
7464 run.glyphOffsets = NULL;
7465 run.isSideways = FALSE;
7466 run.bidiLevel = 0;
7468 baseline_origin.x = 123.0f;
7469 baseline_origin.y = 321.0f;
7471 memset(origins, 0, sizeof(origins));
7472 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, baseline_origin, origins);
7473 ok(hr == S_OK, "got 0x%08x\n", hr);
7474 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
7475 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
7477 memset(origins, 0, sizeof(origins));
7478 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
7479 NULL, origins);
7480 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
7481 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
7483 /* transform is not applied to returned origins */
7484 m.m11 = 2.0f;
7485 m.m12 = 0.0f;
7486 m.m21 = 0.0f;
7487 m.m22 = 1.0f;
7488 m.dx = 0.0f;
7489 m.dy = 0.0f;
7491 memset(origins, 0, sizeof(origins));
7492 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
7493 &m, origins);
7494 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
7495 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
7497 ref = IDWriteFactory4_Release(factory);
7498 ok(ref == 0, "factory not released, %u\n", ref);
7501 static void test_object_lifetime(void)
7503 IDWriteFontCollection *collection, *collection2;
7504 IDWriteFontList *fontlist, *fontlist2;
7505 IDWriteGdiInterop *interop, *interop2;
7506 IDWriteFontFamily *family, *family2;
7507 IDWriteFontFace *fontface;
7508 IDWriteFont *font, *font2;
7509 IDWriteFactory *factory;
7510 HRESULT hr;
7511 ULONG ref;
7513 factory = create_factory();
7514 EXPECT_REF(factory, 1);
7516 /* system collection takes factory reference */
7517 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
7518 ok(hr == S_OK, "got %#x\n", hr);
7520 EXPECT_REF(collection, 1);
7521 EXPECT_REF(factory, 2);
7523 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection2, FALSE);
7524 ok(hr == S_OK, "got %#x\n", hr);
7525 ok(collection2 == collection, "expected same collection\n");
7527 EXPECT_REF(collection, 2);
7528 EXPECT_REF(factory, 2);
7530 IDWriteFontCollection_Release(collection2);
7532 IDWriteFontCollection_AddRef(collection);
7533 EXPECT_REF(collection, 2);
7534 EXPECT_REF(factory, 2);
7535 IDWriteFontCollection_Release(collection);
7537 EXPECT_REF(collection, 1);
7539 /* family takes collection reference */
7540 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
7541 ok(hr == S_OK, "got %#x\n", hr);
7543 EXPECT_REF(family, 1);
7544 EXPECT_REF(collection, 2);
7545 EXPECT_REF(factory, 2);
7547 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family2);
7548 ok(hr == S_OK, "got %#x\n", hr);
7550 EXPECT_REF(family2, 1);
7551 EXPECT_REF(collection, 3);
7552 EXPECT_REF(factory, 2);
7554 IDWriteFontFamily_Release(family2);
7556 EXPECT_REF(family, 1);
7557 EXPECT_REF(collection, 2);
7558 EXPECT_REF(factory, 2);
7560 /* font takes family reference */
7561 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
7562 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
7563 ok(hr == S_OK, "got %#x\n", hr);
7565 EXPECT_REF(family, 2);
7566 EXPECT_REF(collection, 2);
7567 EXPECT_REF(factory, 2);
7569 hr = IDWriteFont_GetFontFamily(font, &family2);
7570 ok(hr == S_OK, "got %#x\n", hr);
7571 ok(family2 == family, "unexpected family pointer\n");
7572 IDWriteFontFamily_Release(family2);
7574 EXPECT_REF(font, 1);
7575 EXPECT_REF(factory, 2);
7577 /* Fontface takes factory reference and nothing else. */
7578 hr = IDWriteFont_CreateFontFace(font, &fontface);
7579 ok(hr == S_OK, "got %#x\n", hr);
7581 EXPECT_REF(font, 1);
7582 EXPECT_REF_BROKEN(fontface, 1, 2);
7583 EXPECT_REF(family, 2);
7584 EXPECT_REF(collection, 2);
7585 EXPECT_REF_BROKEN(factory, 3, 2);
7587 /* get font from fontface */
7588 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
7589 ok(hr == S_OK, "got %#x\n", hr);
7591 EXPECT_REF(font, 1);
7592 EXPECT_REF(font2, 1);
7593 EXPECT_REF_BROKEN(fontface, 1, 2);
7594 EXPECT_REF(family, 2);
7595 EXPECT_REF(collection, 3);
7596 EXPECT_REF_BROKEN(factory, 3, 2);
7598 IDWriteFont_Release(font2);
7599 IDWriteFontFace_Release(fontface);
7601 EXPECT_REF(font, 1);
7602 EXPECT_REF(family, 2);
7603 EXPECT_REF(collection, 2);
7604 EXPECT_REF(factory, 2);
7606 IDWriteFont_Release(font);
7608 EXPECT_REF(family, 1);
7609 EXPECT_REF(collection, 2);
7610 EXPECT_REF(factory, 2);
7612 /* Matching fonts list takes family reference. */
7613 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
7614 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
7615 ok(hr == S_OK, "got %#x\n", hr);
7617 EXPECT_REF(family, 2);
7618 EXPECT_REF(collection, 2);
7619 EXPECT_REF(factory, 2);
7621 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
7622 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
7623 ok(hr == S_OK, "got %#x\n", hr);
7624 ok(fontlist2 != fontlist, "unexpected font list\n");
7625 IDWriteFontList_Release(fontlist2);
7627 IDWriteFontList_Release(fontlist);
7629 IDWriteFontFamily_Release(family);
7630 EXPECT_REF(collection, 1);
7632 EXPECT_REF(factory, 2);
7633 ref = IDWriteFontCollection_Release(collection);
7634 ok(ref == 0, "collection not released, %u\n", ref);
7635 EXPECT_REF(factory, 1);
7637 /* GDI interop object takes factory reference */
7638 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
7639 ok(hr == S_OK, "got %#x\n", hr);
7640 EXPECT_REF(interop, 1);
7641 EXPECT_REF(factory, 2);
7643 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
7644 ok(hr == S_OK, "got %#x\n", hr);
7645 ok(interop == interop2, "got unexpected interop pointer\n");
7647 EXPECT_REF(interop, 2);
7648 EXPECT_REF(factory, 2);
7650 IDWriteGdiInterop_Release(interop2);
7651 ref = IDWriteGdiInterop_Release(interop);
7652 ok(ref == 0, "interop not released, %u\n", ref);
7654 ref = IDWriteFactory_Release(factory);
7655 ok(ref == 0, "factory not released, %u\n", ref);
7658 struct testowner_object
7660 IUnknown IUnknown_iface;
7661 LONG ref;
7664 static inline struct testowner_object *impl_from_IUnknown(IUnknown *iface)
7666 return CONTAINING_RECORD(iface, struct testowner_object, IUnknown_iface);
7669 static HRESULT WINAPI testowner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
7671 if (IsEqualIID(riid, &IID_IUnknown)) {
7672 *obj = iface;
7673 IUnknown_AddRef(iface);
7674 return S_OK;
7677 *obj = NULL;
7678 return E_NOINTERFACE;
7681 static ULONG WINAPI testowner_AddRef(IUnknown *iface)
7683 struct testowner_object *object = impl_from_IUnknown(iface);
7684 return InterlockedIncrement(&object->ref);
7687 static ULONG WINAPI testowner_Release(IUnknown *iface)
7689 struct testowner_object *object = impl_from_IUnknown(iface);
7690 return InterlockedDecrement(&object->ref);
7693 static const IUnknownVtbl testownervtbl = {
7694 testowner_QueryInterface,
7695 testowner_AddRef,
7696 testowner_Release,
7699 static void testowner_init(struct testowner_object *object)
7701 object->IUnknown_iface.lpVtbl = &testownervtbl;
7702 object->ref = 1;
7705 static void test_inmemory_file_loader(void)
7707 IDWriteFontFileStream *stream, *stream2, *stream3;
7708 IDWriteFontFileLoader *loader, *loader2;
7709 IDWriteInMemoryFontFileLoader *inmemory;
7710 struct testowner_object ownerobject;
7711 const void *key, *data, *frag_start;
7712 UINT64 file_size, size, writetime;
7713 IDWriteFontFile *file, *file2;
7714 IDWriteFontFace *fontface;
7715 void *context, *context2;
7716 IDWriteFactory5 *factory;
7717 UINT32 count, key_size;
7718 DWORD ref_key;
7719 HRESULT hr;
7720 ULONG ref;
7722 factory = create_factory_iid(&IID_IDWriteFactory5);
7723 if (!factory) {
7724 win_skip("CreateInMemoryFontFileLoader() is not supported\n");
7725 return;
7728 EXPECT_REF(factory, 1);
7729 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
7730 ok(hr == S_OK, "got %#x\n", hr);
7731 EXPECT_REF(factory, 1);
7733 testowner_init(&ownerobject);
7734 fontface = create_fontface((IDWriteFactory *)factory);
7736 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader2);
7737 ok(hr == S_OK, "got %#x\n", hr);
7738 ok(loader != loader2, "unexpected pointer\n");
7739 IDWriteFontFileLoader_Release(loader2);
7741 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&inmemory);
7742 ok(hr == S_OK, "got %#x\n", hr);
7743 IDWriteFontFileLoader_Release(loader);
7744 EXPECT_REF(inmemory, 1);
7746 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7747 ok(!count, "Unexpected file count %u.\n", count);
7749 /* Use whole font blob to construct in-memory file. */
7750 count = 1;
7751 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
7752 ok(hr == S_OK, "got %#x\n", hr);
7754 hr = IDWriteFontFile_GetLoader(file, &loader);
7755 ok(hr == S_OK, "got %#x\n", hr);
7757 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
7758 ok(hr == S_OK, "got %#x\n", hr);
7760 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, &stream);
7761 ok(hr == S_OK, "got %#x\n", hr);
7762 IDWriteFontFileLoader_Release(loader);
7763 IDWriteFontFile_Release(file);
7765 hr = IDWriteFontFileStream_GetFileSize(stream, &file_size);
7766 ok(hr == S_OK, "got %#x\n", hr);
7768 hr = IDWriteFontFileStream_ReadFileFragment(stream, &data, 0, file_size, &context);
7769 ok(hr == S_OK, "got %#x\n", hr);
7771 /* Not registered yet. */
7772 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7773 file_size, NULL, &file);
7774 ok(hr == E_INVALIDARG, "got %#x\n", hr);
7776 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7777 ok(count == 1, "Unexpected file count %u.\n", count);
7779 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7780 ok(hr == S_OK, "got %#x\n", hr);
7781 EXPECT_REF(inmemory, 2);
7783 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
7784 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7785 file_size, &ownerobject.IUnknown_iface, &file);
7786 ok(hr == S_OK, "got %#x\n", hr);
7787 EXPECT_REF(&ownerobject.IUnknown_iface, 2);
7788 EXPECT_REF(inmemory, 3);
7790 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7791 ok(count == 2, "Unexpected file count %u.\n", count);
7793 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7794 file_size, &ownerobject.IUnknown_iface, &file2);
7795 ok(hr == S_OK, "got %#x\n", hr);
7796 ok(file2 != file, "got unexpected file\n");
7797 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7798 EXPECT_REF(inmemory, 4);
7800 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7801 ok(count == 3, "Unexpected file count %u.\n", count);
7803 /* Check in-memory reference key format. */
7804 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
7805 ok(hr == S_OK, "got %#x\n", hr);
7807 ok(key && *(DWORD*)key == 1, "got wrong ref key\n");
7808 ok(key_size == 4, "ref key size %u\n", key_size);
7810 hr = IDWriteFontFile_GetReferenceKey(file2, &key, &key_size);
7811 ok(hr == S_OK, "got %#x\n", hr);
7813 ok(key && *(DWORD*)key == 2, "got wrong ref key\n");
7814 ok(key_size == 4, "ref key size %u\n", key_size);
7816 EXPECT_REF(inmemory, 4);
7817 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream2);
7818 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
7819 EXPECT_REF(stream2, 1);
7820 EXPECT_REF(inmemory, 4);
7822 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream3);
7823 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
7825 ok(stream2 != stream3, "Unexpected stream.\n");
7827 IDWriteFontFileStream_Release(stream2);
7828 IDWriteFontFileStream_Release(stream3);
7830 /* Release file at index 1, create new one to see if index is reused. */
7831 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7832 ref = IDWriteFontFile_Release(file);
7833 ok(ref == 0, "File object not released, %u.\n", ref);
7834 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7836 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7837 ok(count == 3, "Unexpected file count %u.\n", count);
7839 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7840 ref = IDWriteFontFile_Release(file2);
7841 ok(ref == 0, "File object not released, %u.\n", ref);
7842 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7844 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7845 ok(count == 3, "Unexpected file count %u.\n", count);
7847 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7848 ok(hr == S_OK, "got %#x\n", hr);
7849 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7851 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7852 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
7853 ok(ref == 0, "loader not released, %u.\n", ref);
7854 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
7856 /* Test reference key for first added file. */
7857 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
7858 ok(hr == S_OK, "Failed to create loader, hr %#x.\n", hr);
7860 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&inmemory);
7861 ok(hr == S_OK, "Failed to get in-memory interface, hr %#x.\n", hr);
7862 IDWriteFontFileLoader_Release(loader);
7864 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7865 ok(hr == S_OK, "Failed to register loader, hr %#x.\n", hr);
7867 ref_key = 0;
7868 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
7869 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7871 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7872 file_size, &ownerobject.IUnknown_iface, &file);
7873 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#x.\n", hr);
7875 ref_key = 0;
7876 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
7877 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
7879 context2 = (void *)0xdeadbeef;
7880 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
7881 ok(hr == S_OK, "Failed to read a fragment, hr %#x.\n", hr);
7882 ok(context == NULL, "Unexpected context %p.\n", context2);
7883 ok(frag_start == data, "Unexpected fragment pointer %p.\n", frag_start);
7885 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
7886 ok(hr == S_OK, "Failed to get file size, hr %#x.\n", hr);
7887 ok(size == file_size, "Unexpected file size.\n");
7889 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
7891 writetime = 1;
7892 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
7893 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
7894 ok(writetime == 0, "Unexpected writetime.\n");
7896 IDWriteFontFileStream_Release(stream2);
7898 ref_key = 0;
7899 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, NULL, sizeof(ref_key) - 1, &stream2);
7900 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7902 ref_key = 0;
7903 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) - 1, &stream2);
7904 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7906 ref_key = 0;
7907 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) + 1, &stream2);
7908 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7910 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7911 ok(count == 1, "Unexpected file count %u.\n", count);
7913 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
7914 ok(hr == S_OK, "Failed to get reference key, hr %#x.\n", hr);
7916 ok(key && *(DWORD*)key == 0, "Unexpected reference key.\n");
7917 ok(key_size == 4, "Unexpected key size %u.\n", key_size);
7919 IDWriteFontFile_Release(file);
7921 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7922 ok(count == 1, "Unexpected file count %u.\n", count);
7924 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7925 ok(hr == S_OK, "Failed to unregister loader, hr %#x.\n", hr);
7927 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
7928 IDWriteFontFileStream_Release(stream);
7929 IDWriteFontFace_Release(fontface);
7931 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
7932 ok(ref == 0, "loader not released, %u.\n", ref);
7934 ref = IDWriteFactory5_Release(factory);
7935 ok(ref == 0, "factory not released, %u\n", ref);
7938 static BOOL face_has_table(IDWriteFontFace4 *fontface, UINT32 tag)
7940 BOOL exists = FALSE;
7941 const void *data;
7942 void *context;
7943 UINT32 size;
7944 HRESULT hr;
7946 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
7947 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
7948 if (exists)
7949 IDWriteFontFace4_ReleaseFontTable(fontface, context);
7951 return exists;
7954 static DWORD get_sbix_formats(IDWriteFontFace4 *fontface)
7956 UINT32 size, s, num_strikes;
7957 const sbix_header *header;
7958 UINT16 g, num_glyphs;
7959 BOOL exists = FALSE;
7960 const maxp *maxp;
7961 const void *data;
7962 DWORD ret = 0;
7963 void *context;
7964 HRESULT hr;
7966 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
7967 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
7968 ok(exists, "Expected maxp table\n");
7970 if (!exists)
7971 return 0;
7973 maxp = data;
7974 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
7976 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists);
7977 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
7978 ok(exists, "Expected sbix table\n");
7980 header = data;
7981 num_strikes = GET_BE_DWORD(header->numStrikes);
7983 for (s = 0; s < num_strikes; s++) {
7984 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
7986 for (g = 0; g < num_glyphs; g++) {
7987 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
7988 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
7989 sbix_glyph_data *glyph_data;
7990 DWORD format;
7992 if (offset == offset_next)
7993 continue;
7995 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
7996 switch (format = glyph_data->graphicType)
7998 case MS_PNG__TAG:
7999 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
8000 break;
8001 case MS_JPG__TAG:
8002 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
8003 break;
8004 case MS_TIFF_TAG:
8005 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
8006 break;
8007 default:
8008 ok(0, "unexpected format, %#x\n", GET_BE_DWORD(format));
8013 IDWriteFontFace4_ReleaseFontTable(fontface, context);
8015 return ret;
8018 static DWORD get_cblc_formats(IDWriteFontFace4 *fontface)
8020 CBLCBitmapSizeTable *sizes;
8021 UINT32 num_sizes, size, s;
8022 BOOL exists = FALSE;
8023 CBLCHeader *header;
8024 DWORD ret = 0;
8025 void *context;
8026 HRESULT hr;
8028 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&header, &size, &context, &exists);
8029 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
8030 ok(exists, "Expected CBLC table\n");
8032 if (!exists)
8033 return 0;
8035 num_sizes = GET_BE_DWORD(header->numSizes);
8036 sizes = (CBLCBitmapSizeTable *)(header + 1);
8038 for (s = 0; s < num_sizes; s++) {
8039 BYTE bpp = sizes->bitDepth;
8041 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
8042 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
8043 else if (bpp == 32)
8044 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
8047 IDWriteFontFace4_ReleaseFontTable(fontface, context);
8049 return ret;
8052 static DWORD get_face_glyph_image_formats(IDWriteFontFace4 *fontface)
8054 DWORD ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
8056 if (face_has_table(fontface, MS_GLYF_TAG))
8057 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
8059 if (face_has_table(fontface, MS_CFF__TAG) ||
8060 face_has_table(fontface, MS_CFF2_TAG))
8061 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
8063 if (face_has_table(fontface, MS_COLR_TAG))
8064 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
8066 if (face_has_table(fontface, MS_SVG__TAG))
8067 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
8069 if (face_has_table(fontface, MS_SBIX_TAG))
8070 ret |= get_sbix_formats(fontface);
8072 if (face_has_table(fontface, MS_CBLC_TAG))
8073 ret |= get_cblc_formats(fontface);
8075 return ret;
8078 static void test_GetGlyphImageFormats(void)
8080 IDWriteFontCollection *syscollection;
8081 IDWriteFactory *factory;
8082 UINT32 i, count;
8083 HRESULT hr;
8084 ULONG ref;
8085 IDWriteFontFace *fontface;
8086 IDWriteFontFace4 *fontface4;
8088 factory = create_factory();
8090 fontface = create_fontface(factory);
8091 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
8092 IDWriteFontFace_Release(fontface);
8093 if (FAILED(hr)) {
8094 win_skip("GetGlyphImageFormats() is not supported\n");
8095 IDWriteFactory_Release(factory);
8096 return;
8098 IDWriteFontFace4_Release(fontface4);
8100 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8101 ok(hr == S_OK, "got 0x%08x\n", hr);
8102 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8104 for (i = 0; i < count; i++) {
8105 WCHAR familynameW[256], facenameW[128];
8106 IDWriteLocalizedStrings *names;
8107 IDWriteFontFamily *family;
8108 UINT32 j, fontcount;
8109 IDWriteFont *font;
8111 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8112 ok(hr == S_OK, "got 0x%08x\n", hr);
8114 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8115 ok(hr == S_OK, "got 0x%08x\n", hr);
8117 get_enus_string(names, familynameW, ARRAY_SIZE(familynameW));
8118 IDWriteLocalizedStrings_Release(names);
8120 fontcount = IDWriteFontFamily_GetFontCount(family);
8121 for (j = 0; j < fontcount; j++) {
8122 DWORD formats, expected_formats;
8124 hr = IDWriteFontFamily_GetFont(family, j, &font);
8125 ok(hr == S_OK, "got 0x%08x\n", hr);
8127 hr = IDWriteFont_CreateFontFace(font, &fontface);
8128 ok(hr == S_OK, "got 0x%08x\n", hr);
8130 hr = IDWriteFont_GetFaceNames(font, &names);
8131 ok(hr == S_OK, "got 0x%08x\n", hr);
8133 get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
8135 IDWriteLocalizedStrings_Release(names);
8137 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
8139 /* Mask describes font as a whole. */
8140 formats = IDWriteFontFace4_GetGlyphImageFormats(fontface4);
8141 expected_formats = get_face_glyph_image_formats(fontface4);
8142 ok(formats == expected_formats, "%s - %s, expected formats %#x, got formats %#x.\n",
8143 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), expected_formats, formats);
8145 IDWriteFontFace4_Release(fontface4);
8146 IDWriteFontFace_Release(fontface);
8147 IDWriteFont_Release(font);
8150 IDWriteFontFamily_Release(family);
8153 IDWriteFontCollection_Release(syscollection);
8154 ref = IDWriteFactory_Release(factory);
8155 ok(ref == 0, "factory not released, %u\n", ref);
8158 static void test_CreateCustomRenderingParams(void)
8160 static const struct custom_params_test
8162 FLOAT gamma;
8163 FLOAT contrast;
8164 FLOAT cleartype_level;
8165 DWRITE_PIXEL_GEOMETRY geometry;
8166 DWRITE_RENDERING_MODE rendering_mode;
8167 HRESULT hr;
8168 } params_tests[] =
8170 { 0.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8171 { 0.0f, 0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8172 { 0.0f, 0.0f, 0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8173 { -0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8174 { 0.1f, -0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8175 { 0.1f, 0.0f, -0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8176 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
8177 { 0.01f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
8178 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR + 1, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8179 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_OUTLINE + 1, E_INVALIDARG },
8180 { 0.1f, 0.0f, 2.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_NATURAL },
8182 IDWriteFactory *factory;
8183 unsigned int i;
8184 HRESULT hr;
8185 ULONG ref;
8187 factory = create_factory();
8189 for (i = 0; i < ARRAY_SIZE(params_tests); i++) {
8190 IDWriteRenderingParams *params;
8192 params = (void *)0xdeadbeef;
8193 hr = IDWriteFactory_CreateCustomRenderingParams(factory, params_tests[i].gamma, params_tests[i].contrast,
8194 params_tests[i].cleartype_level, params_tests[i].geometry, params_tests[i].rendering_mode, &params);
8195 ok(hr == params_tests[i].hr, "%u: unexpected hr %#x, expected %#x.\n", i, hr, params_tests[i].hr);
8197 if (hr == S_OK) {
8198 ok(params_tests[i].gamma == IDWriteRenderingParams_GetGamma(params), "%u: unexpected gamma %f, expected %f.\n",
8199 i, IDWriteRenderingParams_GetGamma(params), params_tests[i].gamma);
8200 ok(params_tests[i].contrast == IDWriteRenderingParams_GetEnhancedContrast(params),
8201 "%u: unexpected contrast %f, expected %f.\n",
8202 i, IDWriteRenderingParams_GetEnhancedContrast(params), params_tests[i].contrast);
8203 ok(params_tests[i].cleartype_level == IDWriteRenderingParams_GetClearTypeLevel(params),
8204 "%u: unexpected ClearType level %f, expected %f.\n",
8205 i, IDWriteRenderingParams_GetClearTypeLevel(params), params_tests[i].cleartype_level);
8206 ok(params_tests[i].geometry == IDWriteRenderingParams_GetPixelGeometry(params),
8207 "%u: unexpected pixel geometry %u, expected %u.\n", i, IDWriteRenderingParams_GetPixelGeometry(params),
8208 params_tests[i].geometry);
8209 ok(params_tests[i].rendering_mode == IDWriteRenderingParams_GetRenderingMode(params),
8210 "%u: unexpected rendering mode %u, expected %u.\n", i, IDWriteRenderingParams_GetRenderingMode(params),
8211 params_tests[i].rendering_mode);
8212 IDWriteRenderingParams_Release(params);
8214 else
8215 ok(params == NULL, "%u: expected NULL interface pointer on failure.\n", i);
8218 ref = IDWriteFactory_Release(factory);
8219 ok(ref == 0, "factory not released, %u\n", ref);
8222 static void test_localfontfileloader(void)
8224 IDWriteFontFileLoader *loader, *loader2;
8225 IDWriteFactory *factory, *factory2;
8226 IDWriteFontFile *file, *file2;
8227 WCHAR *path;
8228 HRESULT hr;
8229 ULONG ref;
8231 factory = create_factory();
8232 factory2 = create_factory();
8234 path = create_testfontfile(test_fontfile);
8236 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
8237 ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
8239 hr = IDWriteFactory_CreateFontFileReference(factory2, path, NULL, &file2);
8240 ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
8241 ok(file != file2, "Unexpected file instance.\n");
8243 hr = IDWriteFontFile_GetLoader(file, &loader);
8244 ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
8246 hr = IDWriteFontFile_GetLoader(file2, &loader2);
8247 ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
8248 ok(loader == loader2, "Unexpected loader instance\n");
8250 IDWriteFontFile_Release(file);
8251 IDWriteFontFile_Release(file2);
8252 IDWriteFontFileLoader_Release(loader);
8253 IDWriteFontFileLoader_Release(loader2);
8254 ref = IDWriteFactory_Release(factory);
8255 ok(ref == 0, "factory not released, %u\n", ref);
8256 DELETE_FONTFILE(path);
8259 static void test_AnalyzeContainerType(void)
8261 struct WOFFHeader2 woff2_header;
8262 struct WOFFHeader woff_header;
8263 DWRITE_CONTAINER_TYPE type;
8264 IDWriteFactory5 *factory;
8266 factory = create_factory_iid(&IID_IDWriteFactory5);
8267 if (!factory) {
8268 win_skip("AnalyzeContainerType() is not supported.\n");
8269 return;
8272 type = IDWriteFactory5_AnalyzeContainerType(factory, NULL, 0);
8273 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8275 type = IDWriteFactory5_AnalyzeContainerType(factory, (void const *)0xdeadbeef, 0);
8276 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8278 memset(&woff_header, 0xff, sizeof(woff_header));
8279 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
8280 woff_header.length = 0;
8281 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header));
8282 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
8284 memset(&woff_header, 0xff, sizeof(woff_header));
8285 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
8286 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature));
8287 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
8289 memset(&woff_header, 0xff, sizeof(woff_header));
8290 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
8291 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature) - 1);
8292 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8294 memset(&woff2_header, 0xff, sizeof(woff2_header));
8295 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
8296 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header));
8297 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
8299 memset(&woff2_header, 0xff, sizeof(woff2_header));
8300 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
8301 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature));
8302 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
8304 memset(&woff2_header, 0xff, sizeof(woff2_header));
8305 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
8306 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature) - 1);
8307 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8309 IDWriteFactory5_Release(factory);
8312 static void test_fontsetbuilder(void)
8314 IDWriteFontCollection1 *collection;
8315 IDWriteFontSetBuilder *builder;
8316 IDWriteFactory3 *factory;
8317 UINT32 count, i, ref;
8318 HRESULT hr;
8320 factory = create_factory_iid(&IID_IDWriteFactory3);
8321 if (!factory) {
8322 skip("IDWriteFontSetBuilder is not supported.\n");
8323 return;
8326 EXPECT_REF(factory, 1);
8327 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
8328 todo_wine
8329 ok(hr == S_OK, "Failed to create font set builder, hr %#x.\n", hr);
8331 if (FAILED(hr)) {
8332 IDWriteFactory3_Release(factory);
8333 return;
8336 EXPECT_REF(factory, 2);
8337 IDWriteFontSetBuilder_Release(builder);
8339 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
8340 ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
8341 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
8343 for (i = 0; i < count; i++) {
8344 IDWriteFontFamily1 *family;
8345 UINT32 j, fontcount;
8346 IDWriteFont3 *font;
8348 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
8349 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
8351 fontcount = IDWriteFontFamily1_GetFontCount(family);
8352 for (j = 0; j < fontcount; j++) {
8353 IDWriteFontFaceReference *ref, *ref2;
8354 IDWriteFontSet *fontset;
8355 UINT32 setcount, id;
8357 hr = IDWriteFontFamily1_GetFont(family, j, &font);
8358 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
8360 /* Create a set with a single font reference, test set properties. */
8361 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
8362 ok(hr == S_OK, "Failed to create font set builder, hr %#x.\n", hr);
8364 hr = IDWriteFont3_GetFontFaceReference(font, &ref);
8365 ok(hr == S_OK, "Failed to get fontface reference, hr %#x.\n", hr);
8367 EXPECT_REF(ref, 1);
8368 hr = IDWriteFontSetBuilder_AddFontFaceReference(builder, ref);
8369 ok(hr == S_OK, "Failed to add fontface reference, hr %#x.\n", hr);
8370 EXPECT_REF(ref, 1);
8372 hr = IDWriteFontSetBuilder_CreateFontSet(builder, &fontset);
8373 ok(hr == S_OK, "Failed to create a font set, hr %#x.\n", hr);
8375 setcount = IDWriteFontSet_GetFontCount(fontset);
8376 ok(setcount == 1, "Unexpected font count %u.\n", setcount);
8378 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref2);
8379 ok(hr == S_OK, "Failed to get font face reference, hr %#x.\n", hr);
8380 ok(ref2 != ref, "Unexpected reference.\n");
8381 IDWriteFontFaceReference_Release(ref2);
8383 for (id = DWRITE_FONT_PROPERTY_ID_FAMILY_NAME; id < DWRITE_FONT_PROPERTY_ID_TOTAL; id++) {
8384 static const WCHAR fmtW[] = {'%','u',0};
8385 IDWriteLocalizedStrings *values;
8386 WCHAR buffW[255], buff2W[255];
8387 UINT32 c, ivalue;
8388 BOOL exists;
8390 hr = IDWriteFontSet_GetPropertyValues(fontset, 0, id, &exists, &values);
8391 ok(hr == S_OK, "Failed to get property value, hr %#x.\n", hr);
8393 if (!exists)
8394 continue;
8396 switch (id)
8398 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
8399 ivalue = IDWriteFont3_GetWeight(font);
8400 break;
8401 case DWRITE_FONT_PROPERTY_ID_STRETCH:
8402 ivalue = IDWriteFont3_GetStretch(font);
8403 break;
8404 case DWRITE_FONT_PROPERTY_ID_STYLE:
8405 ivalue = IDWriteFont3_GetStyle(font);
8406 break;
8407 default:
8411 switch (id)
8413 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
8414 case DWRITE_FONT_PROPERTY_ID_STRETCH:
8415 case DWRITE_FONT_PROPERTY_ID_STYLE:
8416 c = IDWriteLocalizedStrings_GetCount(values);
8417 ok(c == 1, "Unexpected string count %u.\n", c);
8419 buffW[0] = 'a';
8420 hr = IDWriteLocalizedStrings_GetLocaleName(values, 0, buffW, ARRAY_SIZE(buffW));
8421 ok(hr == S_OK, "Failed to get locale name, hr %#x.\n", hr);
8422 ok(!*buffW, "Unexpected locale %s.\n", wine_dbgstr_w(buffW));
8424 buff2W[0] = 0;
8425 hr = IDWriteLocalizedStrings_GetString(values, 0, buff2W, ARRAY_SIZE(buff2W));
8426 ok(hr == S_OK, "Failed to get property string, hr %#x.\n", hr);
8428 wsprintfW(buffW, fmtW, ivalue);
8429 ok(!lstrcmpW(buffW, buff2W), "Unexpected property value %s, expected %s.\n", wine_dbgstr_w(buff2W),
8430 wine_dbgstr_w(buffW));
8431 break;
8432 default:
8436 IDWriteLocalizedStrings_Release(values);
8439 IDWriteFontSet_Release(fontset);
8440 IDWriteFontFaceReference_Release(ref);
8441 IDWriteFontSetBuilder_Release(builder);
8443 IDWriteFont3_Release(font);
8446 IDWriteFontFamily1_Release(family);
8449 IDWriteFontCollection1_Release(collection);
8451 ref = IDWriteFactory3_Release(factory);
8452 ok(ref == 0, "factory not released, %u\n", ref);
8455 START_TEST(font)
8457 IDWriteFactory *factory;
8459 if (!(factory = create_factory())) {
8460 win_skip("failed to create factory\n");
8461 return;
8464 test_object_lifetime();
8465 test_CreateFontFromLOGFONT();
8466 test_CreateBitmapRenderTarget();
8467 test_GetFontFamily();
8468 test_GetFamilyNames();
8469 test_CreateFontFace();
8470 test_GetMetrics();
8471 test_system_fontcollection();
8472 test_ConvertFontFaceToLOGFONT();
8473 test_CustomFontCollection();
8474 test_CreateCustomFontFileReference();
8475 test_CreateFontFileReference();
8476 test_shared_isolated();
8477 test_GetUnicodeRanges();
8478 test_GetFontFromFontFace();
8479 test_GetFirstMatchingFont();
8480 test_GetMatchingFonts();
8481 test_GetInformationalStrings();
8482 test_GetGdiInterop();
8483 test_CreateFontFaceFromHdc();
8484 test_GetSimulations();
8485 test_GetFaceNames();
8486 test_TryGetFontTable();
8487 test_ConvertFontToLOGFONT();
8488 test_CreateStreamFromKey();
8489 test_ReadFileFragment();
8490 test_GetDesignGlyphMetrics();
8491 test_GetDesignGlyphAdvances();
8492 test_IsMonospacedFont();
8493 test_GetGlyphRunOutline();
8494 test_GetEudcFontCollection();
8495 test_GetCaretMetrics();
8496 test_GetGlyphCount();
8497 test_GetKerningPairAdjustments();
8498 test_CreateRenderingParams();
8499 test_CreateGlyphRunAnalysis();
8500 test_GetGdiCompatibleMetrics();
8501 test_GetPanose();
8502 test_GetGdiCompatibleGlyphAdvances();
8503 test_GetRecommendedRenderingMode();
8504 test_GetAlphaBlendParams();
8505 test_CreateAlphaTexture();
8506 test_IsSymbolFont();
8507 test_GetPaletteEntries();
8508 test_TranslateColorGlyphRun();
8509 test_HasCharacter();
8510 test_CreateFontFaceReference();
8511 test_GetFontSignature();
8512 test_font_properties();
8513 test_HasVerticalGlyphVariants();
8514 test_HasKerningPairs();
8515 test_ComputeGlyphOrigins();
8516 test_inmemory_file_loader();
8517 test_GetGlyphImageFormats();
8518 test_CreateCustomRenderingParams();
8519 test_localfontfileloader();
8520 test_AnalyzeContainerType();
8521 test_fontsetbuilder();
8523 IDWriteFactory_Release(factory);