dwrite/tests: Add missing return value test (Coverity).
[wine.git] / dlls / dwrite / tests / font.c
blob24e8e73b2c8eb647642033d149aa819e42cd0080
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/test.h"
35 #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p')
36 #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X')
37 #define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p')
38 #define MS_CPAL_TAG DWRITE_MAKE_OPENTYPE_TAG('C','P','A','L')
39 #define MS_0S2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2')
40 #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d')
41 #define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a')
42 #define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t')
43 #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B')
44 #define MS_KERN_TAG DWRITE_MAKE_OPENTYPE_TAG('k','e','r','n')
45 #define MS_GLYF_TAG DWRITE_MAKE_OPENTYPE_TAG('g','l','y','f')
46 #define MS_CFF__TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F',' ')
47 #define MS_CFF2_TAG DWRITE_MAKE_OPENTYPE_TAG('C','F','F','2')
48 #define MS_COLR_TAG DWRITE_MAKE_OPENTYPE_TAG('C','O','L','R')
49 #define MS_SVG__TAG DWRITE_MAKE_OPENTYPE_TAG('S','V','G',' ')
50 #define MS_SBIX_TAG DWRITE_MAKE_OPENTYPE_TAG('s','b','i','x')
51 #define MS_MAXP_TAG DWRITE_MAKE_OPENTYPE_TAG('m','a','x','p')
52 #define MS_CBLC_TAG DWRITE_MAKE_OPENTYPE_TAG('C','B','L','C')
54 /* 'sbix' formats */
55 #define MS_PNG__TAG DWRITE_MAKE_OPENTYPE_TAG('p','n','g',' ')
56 #define MS_JPG__TAG DWRITE_MAKE_OPENTYPE_TAG('j','p','g',' ')
57 #define MS_TIFF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','i','f','f')
59 #define MS_WOFF_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','F')
60 #define MS_WOF2_TAG DWRITE_MAKE_OPENTYPE_TAG('w','O','F','2')
62 #ifdef WORDS_BIGENDIAN
63 #define GET_BE_WORD(x) (x)
64 #define GET_BE_DWORD(x) (x)
65 #define GET_LE_WORD(x) RtlUshortByteSwap(x)
66 #define GET_LE_DWORD(x) RtlUlongByteSwap(x)
67 #else
68 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
69 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
70 #define GET_LE_WORD(x) (x)
71 #define GET_LE_DWORD(x) (x)
72 #endif
74 #define EXPECT_HR(hr,hr_exp) \
75 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
77 #define DEFINE_EXPECT(func) \
78 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
80 #define SET_EXPECT(func) \
81 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
83 #define CHECK_EXPECT2(func) \
84 do { \
85 ok(expect_ ##func, "unexpected call " #func "\n"); \
86 called_ ## func = TRUE; \
87 }while(0)
89 #define CHECK_EXPECT(func) \
90 do { \
91 CHECK_EXPECT2(func); \
92 expect_ ## func = FALSE; \
93 }while(0)
95 #define CHECK_CALLED(func) \
96 do { \
97 ok(called_ ## func, "expected " #func "\n"); \
98 expect_ ## func = called_ ## func = FALSE; \
99 }while(0)
101 #define CLEAR_CALLED(func) \
102 expect_ ## func = called_ ## func = FALSE
104 DEFINE_EXPECT(setfillmode);
106 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
107 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
109 ULONG rc;
110 IUnknown_AddRef(obj);
111 rc = IUnknown_Release(obj);
112 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
115 #define EXPECT_REF_BROKEN(obj,ref,brokenref) _expect_ref_broken((IUnknown*)obj, ref, brokenref, __LINE__)
116 static void _expect_ref_broken(IUnknown* obj, ULONG ref, ULONG brokenref, int line)
118 ULONG rc;
119 IUnknown_AddRef(obj);
120 rc = IUnknown_Release(obj);
121 ok_(__FILE__,line)(rc == ref || broken(rc == brokenref), "expected refcount %d, got %d\n", ref, rc);
124 static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size)
126 return HeapAlloc(GetProcessHeap(), 0, size);
129 static inline BOOL heap_free(void *mem)
131 return HeapFree(GetProcessHeap(), 0, mem);
134 static const WCHAR test_fontfile[] = {'w','i','n','e','_','t','e','s','t','_','f','o','n','t','.','t','t','f',0};
135 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
136 static const WCHAR arialW[] = {'A','r','i','a','l',0};
137 static const WCHAR tahomaUppercaseW[] = {'T','A','H','O','M','A',0};
138 static const WCHAR tahomaStrangecaseW[] = {'t','A','h','O','m','A',0};
139 static const WCHAR blahW[] = {'B','l','a','h','!',0};
140 static const WCHAR emojiW[] = {'S','e','g','o','e',' ','U','I',' ','E','m','o','j','i',0};
142 /* PANOSE is 10 bytes in size, need to pack the structure properly */
143 #include "pshpack2.h"
144 typedef struct
146 USHORT majorVersion;
147 USHORT minorVersion;
148 ULONG revision;
149 ULONG checksumadj;
150 ULONG magic;
151 USHORT flags;
152 USHORT unitsPerEm;
153 ULONGLONG created;
154 ULONGLONG modified;
155 SHORT xMin;
156 SHORT yMin;
157 SHORT xMax;
158 SHORT yMax;
159 USHORT macStyle;
160 USHORT lowestRecPPEM;
161 SHORT direction_hint;
162 SHORT index_format;
163 SHORT glyphdata_format;
164 } TT_HEAD;
166 enum TT_HEAD_MACSTYLE
168 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
169 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
170 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
171 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
172 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
173 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
174 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
177 typedef struct
179 USHORT version;
180 SHORT xAvgCharWidth;
181 USHORT usWeightClass;
182 USHORT usWidthClass;
183 SHORT fsType;
184 SHORT ySubscriptXSize;
185 SHORT ySubscriptYSize;
186 SHORT ySubscriptXOffset;
187 SHORT ySubscriptYOffset;
188 SHORT ySuperscriptXSize;
189 SHORT ySuperscriptYSize;
190 SHORT ySuperscriptXOffset;
191 SHORT ySuperscriptYOffset;
192 SHORT yStrikeoutSize;
193 SHORT yStrikeoutPosition;
194 SHORT sFamilyClass;
195 PANOSE panose;
196 ULONG ulUnicodeRange1;
197 ULONG ulUnicodeRange2;
198 ULONG ulUnicodeRange3;
199 ULONG ulUnicodeRange4;
200 CHAR achVendID[4];
201 USHORT fsSelection;
202 USHORT usFirstCharIndex;
203 USHORT usLastCharIndex;
204 /* According to the Apple spec, original version didn't have the below fields,
205 * version numbers were taken from the OpenType spec.
207 /* version 0 (TrueType 1.5) */
208 USHORT sTypoAscender;
209 USHORT sTypoDescender;
210 USHORT sTypoLineGap;
211 USHORT usWinAscent;
212 USHORT usWinDescent;
213 /* version 1 (TrueType 1.66) */
214 ULONG ulCodePageRange1;
215 ULONG ulCodePageRange2;
216 /* version 2 (OpenType 1.2) */
217 SHORT sxHeight;
218 SHORT sCapHeight;
219 USHORT usDefaultChar;
220 USHORT usBreakChar;
221 USHORT usMaxContext;
222 } TT_OS2_V2;
224 enum OS2_FSSELECTION {
225 OS2_FSSELECTION_ITALIC = 1 << 0,
226 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
227 OS2_FSSELECTION_NEGATIVE = 1 << 2,
228 OS2_FSSELECTION_OUTLINED = 1 << 3,
229 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
230 OS2_FSSELECTION_BOLD = 1 << 5,
231 OS2_FSSELECTION_REGULAR = 1 << 6,
232 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
233 OS2_FSSELECTION_WWS = 1 << 8,
234 OS2_FSSELECTION_OBLIQUE = 1 << 9
237 typedef struct {
238 ULONG Version;
239 ULONG italicAngle;
240 SHORT underlinePosition;
241 SHORT underlineThickness;
242 ULONG fixed_pitch;
243 ULONG minmemType42;
244 ULONG maxmemType42;
245 ULONG minmemType1;
246 ULONG maxmemType1;
247 } TT_POST;
249 typedef struct {
250 USHORT majorVersion;
251 USHORT minorVersion;
252 SHORT ascender;
253 SHORT descender;
254 SHORT linegap;
255 USHORT advanceWidthMax;
256 SHORT minLeftSideBearing;
257 SHORT minRightSideBearing;
258 SHORT xMaxExtent;
259 SHORT caretSlopeRise;
260 SHORT caretSlopeRun;
261 SHORT caretOffset;
262 SHORT reserved[4];
263 SHORT metricDataFormat;
264 USHORT numberOfHMetrics;
265 } TT_HHEA;
267 typedef struct {
268 DWORD version;
269 WORD ScriptList;
270 WORD FeatureList;
271 WORD LookupList;
272 } GSUB_Header;
274 typedef struct {
275 CHAR FeatureTag[4];
276 WORD Feature;
277 } OT_FeatureRecord;
279 typedef struct {
280 WORD FeatureCount;
281 OT_FeatureRecord FeatureRecord[1];
282 } OT_FeatureList;
284 typedef struct {
285 WORD FeatureParams;
286 WORD LookupCount;
287 WORD LookupListIndex[1];
288 } OT_Feature;
290 typedef struct {
291 WORD LookupCount;
292 WORD Lookup[1];
293 } OT_LookupList;
295 typedef struct {
296 WORD LookupType;
297 WORD LookupFlag;
298 WORD SubTableCount;
299 WORD SubTable[1];
300 } OT_LookupTable;
302 typedef struct {
303 WORD SubstFormat;
304 WORD Coverage;
305 WORD DeltaGlyphID;
306 } GSUB_SingleSubstFormat1;
308 typedef struct {
309 WORD SubstFormat;
310 WORD Coverage;
311 WORD GlyphCount;
312 WORD Substitute[1];
313 } GSUB_SingleSubstFormat2;
315 typedef struct {
316 WORD SubstFormat;
317 WORD ExtensionLookupType;
318 DWORD ExtensionOffset;
319 } GSUB_ExtensionPosFormat1;
321 typedef struct {
322 WORD version;
323 WORD flags;
324 DWORD numStrikes;
325 DWORD strikeOffset[1];
326 } sbix_header;
328 typedef struct {
329 WORD ppem;
330 WORD ppi;
331 DWORD glyphDataOffsets[1];
332 } sbix_strike;
334 typedef struct {
335 WORD originOffsetX;
336 WORD originOffsetY;
337 DWORD graphicType;
338 BYTE data[1];
339 } sbix_glyph_data;
341 typedef struct {
342 WORD majorVersion;
343 WORD minorVersion;
344 DWORD numSizes;
345 } CBLCHeader;
347 typedef struct {
348 BYTE res[12];
349 } sbitLineMetrics;
351 typedef struct {
352 DWORD indexSubTableArrayOffset;
353 DWORD indexTablesSize;
354 DWORD numberofIndexSubTables;
355 DWORD colorRef;
356 sbitLineMetrics hori;
357 sbitLineMetrics vert;
358 WORD startGlyphIndex;
359 WORD endGlyphIndex;
360 BYTE ppemX;
361 BYTE ppemY;
362 BYTE bitDepth;
363 BYTE flags;
364 } CBLCBitmapSizeTable;
366 typedef struct {
367 DWORD version;
368 WORD numGlyphs;
369 } maxp;
371 struct WOFFHeader
373 ULONG signature;
374 ULONG flavor;
375 ULONG length;
376 USHORT numTables;
377 USHORT reserved;
378 ULONG totalSfntSize;
379 USHORT majorVersion;
380 USHORT minorVersion;
381 ULONG metaOffset;
382 ULONG metaLength;
383 ULONG metaOrigLength;
384 ULONG privOffset;
385 ULONG privLength;
388 struct WOFFHeader2
390 ULONG signature;
391 ULONG flavor;
392 ULONG length;
393 USHORT numTables;
394 USHORT reserved;
395 ULONG totalSfntSize;
396 ULONG totalCompressedSize;
397 USHORT majorVersion;
398 USHORT minorVersion;
399 ULONG metaOffset;
400 ULONG metaLength;
401 ULONG metaOrigLength;
402 ULONG privOffset;
403 ULONG privLength;
406 #include "poppack.h"
408 static void *create_factory_iid(REFIID riid)
410 IUnknown *factory = NULL;
411 DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, riid, &factory);
412 return factory;
415 static IDWriteFactory *create_factory(void)
417 IDWriteFactory *factory = create_factory_iid(&IID_IDWriteFactory);
418 ok(factory != NULL, "Failed to create factory.\n");
419 return factory;
422 static IDWriteFontFace *create_fontface(IDWriteFactory *factory)
424 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
425 IDWriteGdiInterop *interop;
426 IDWriteFontFace *fontface;
427 IDWriteFont *font;
428 LOGFONTW logfont;
429 HRESULT hr;
431 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
432 ok(hr == S_OK, "got 0x%08x\n", hr);
434 memset(&logfont, 0, sizeof(logfont));
435 logfont.lfHeight = 12;
436 logfont.lfWidth = 12;
437 logfont.lfWeight = FW_NORMAL;
438 logfont.lfItalic = 1;
439 lstrcpyW(logfont.lfFaceName, tahomaW);
441 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
442 ok(hr == S_OK, "got 0x%08x\n", hr);
444 hr = IDWriteFont_CreateFontFace(font, &fontface);
445 ok(hr == S_OK, "got 0x%08x\n", hr);
447 IDWriteFont_Release(font);
448 IDWriteGdiInterop_Release(interop);
450 return fontface;
453 static IDWriteFont *get_font(IDWriteFactory *factory, const WCHAR *name, DWRITE_FONT_STYLE style)
455 IDWriteFontCollection *collection;
456 IDWriteFontFamily *family;
457 IDWriteFont *font = NULL;
458 UINT32 index;
459 BOOL exists;
460 HRESULT hr;
462 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
463 ok(hr == S_OK, "got 0x%08x\n", hr);
465 index = ~0;
466 exists = FALSE;
467 hr = IDWriteFontCollection_FindFamilyName(collection, name, &index, &exists);
468 ok(hr == S_OK, "got 0x%08x\n", hr);
469 if (!exists) goto not_found;
471 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
472 ok(hr == S_OK, "got 0x%08x\n", hr);
474 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
475 DWRITE_FONT_STRETCH_NORMAL, style, &font);
476 ok(hr == S_OK, "got 0x%08x\n", hr);
478 IDWriteFontFamily_Release(family);
479 not_found:
480 IDWriteFontCollection_Release(collection);
481 return font;
484 static IDWriteFont *get_tahoma_instance(IDWriteFactory *factory, DWRITE_FONT_STYLE style)
486 IDWriteFont *font = get_font(factory, tahomaW, style);
487 ok(font != NULL, "failed to get Tahoma\n");
488 return font;
491 static WCHAR *create_testfontfile(const WCHAR *filename)
493 static WCHAR pathW[MAX_PATH];
494 DWORD written;
495 HANDLE file;
496 HRSRC res;
497 void *ptr;
499 GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
500 lstrcatW(pathW, filename);
502 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
503 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW),
504 GetLastError());
506 res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
507 ok( res != 0, "couldn't find resource\n" );
508 ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
509 WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
510 ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
511 CloseHandle( file );
513 return pathW;
516 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
517 static void _delete_testfontfile(const WCHAR *filename, int line)
519 BOOL ret = DeleteFileW(filename);
520 ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError());
523 struct test_fontenumerator
525 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
526 LONG ref;
528 DWORD index;
529 IDWriteFontFile *font_file;
532 static inline struct test_fontenumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
534 return CONTAINING_RECORD(iface, struct test_fontenumerator, IDWriteFontFileEnumerator_iface);
537 static HRESULT WINAPI singlefontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
539 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
541 *obj = iface;
542 IDWriteFontFileEnumerator_AddRef(iface);
543 return S_OK;
545 return E_NOINTERFACE;
548 static ULONG WINAPI singlefontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
550 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
551 return InterlockedIncrement(&This->ref);
554 static ULONG WINAPI singlefontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
556 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
557 ULONG ref = InterlockedDecrement(&This->ref);
558 if (!ref) {
559 IDWriteFontFile_Release(This->font_file);
560 heap_free(This);
562 return ref;
565 static HRESULT WINAPI singlefontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **font_file)
567 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
568 IDWriteFontFile_AddRef(This->font_file);
569 *font_file = This->font_file;
570 return S_OK;
573 static HRESULT WINAPI singlefontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
575 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
577 if (This->index > 1) {
578 *current = FALSE;
579 return S_OK;
582 This->index++;
583 *current = TRUE;
584 return S_OK;
587 static const struct IDWriteFontFileEnumeratorVtbl singlefontfileenumeratorvtbl =
589 singlefontfileenumerator_QueryInterface,
590 singlefontfileenumerator_AddRef,
591 singlefontfileenumerator_Release,
592 singlefontfileenumerator_MoveNext,
593 singlefontfileenumerator_GetCurrentFontFile
596 static HRESULT create_enumerator(IDWriteFontFile *font_file, IDWriteFontFileEnumerator **ret)
598 struct test_fontenumerator *enumerator;
600 enumerator = heap_alloc(sizeof(struct test_fontenumerator));
601 if (!enumerator)
602 return E_OUTOFMEMORY;
604 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &singlefontfileenumeratorvtbl;
605 enumerator->ref = 1;
606 enumerator->index = 0;
607 enumerator->font_file = font_file;
608 IDWriteFontFile_AddRef(font_file);
610 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
611 return S_OK;
614 struct test_fontcollectionloader
616 IDWriteFontCollectionLoader IDWriteFontFileCollectionLoader_iface;
617 IDWriteFontFileLoader *loader;
620 static inline struct test_fontcollectionloader *impl_from_IDWriteFontFileCollectionLoader(IDWriteFontCollectionLoader* iface)
622 return CONTAINING_RECORD(iface, struct test_fontcollectionloader, IDWriteFontFileCollectionLoader_iface);
625 static HRESULT WINAPI resourcecollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
627 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontCollectionLoader))
629 *obj = iface;
630 IDWriteFontCollectionLoader_AddRef(iface);
631 return S_OK;
633 return E_NOINTERFACE;
636 static ULONG WINAPI resourcecollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
638 return 2;
641 static ULONG WINAPI resourcecollectionloader_Release(IDWriteFontCollectionLoader *iface)
643 return 1;
646 static HRESULT WINAPI resourcecollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory,
647 const void * collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator ** fontFileEnumerator)
649 struct test_fontcollectionloader *This = impl_from_IDWriteFontFileCollectionLoader(iface);
650 IDWriteFontFile *font_file;
651 HRESULT hr;
653 hr = IDWriteFactory_CreateCustomFontFileReference(factory, collectionKey, collectionKeySize, This->loader, &font_file);
654 ok(hr == S_OK, "Failed to create custom file reference, hr %#x.\n", hr);
656 hr = create_enumerator(font_file, fontFileEnumerator);
657 ok(hr == S_OK, "got 0x%08x\n", hr);
659 IDWriteFontFile_Release(font_file);
660 return hr;
663 static const struct IDWriteFontCollectionLoaderVtbl resourcecollectionloadervtbl = {
664 resourcecollectionloader_QueryInterface,
665 resourcecollectionloader_AddRef,
666 resourcecollectionloader_Release,
667 resourcecollectionloader_CreateEnumeratorFromKey
670 /* Here is a functional custom font set of interfaces */
671 struct test_fontdatastream
673 IDWriteFontFileStream IDWriteFontFileStream_iface;
674 LONG ref;
676 LPVOID data;
677 DWORD size;
680 static inline struct test_fontdatastream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream* iface)
682 return CONTAINING_RECORD(iface, struct test_fontdatastream, IDWriteFontFileStream_iface);
685 static HRESULT WINAPI fontdatastream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
687 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
689 *obj = iface;
690 IDWriteFontFileStream_AddRef(iface);
691 return S_OK;
693 *obj = NULL;
694 return E_NOINTERFACE;
697 static ULONG WINAPI fontdatastream_AddRef(IDWriteFontFileStream *iface)
699 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
700 ULONG ref = InterlockedIncrement(&This->ref);
701 return ref;
704 static ULONG WINAPI fontdatastream_Release(IDWriteFontFileStream *iface)
706 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
707 ULONG ref = InterlockedDecrement(&This->ref);
708 if (ref == 0)
709 HeapFree(GetProcessHeap(), 0, This);
710 return ref;
713 static HRESULT WINAPI fontdatastream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
715 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
716 *fragment_context = NULL;
717 if (offset+fragment_size > This->size)
719 *fragment_start = NULL;
720 return E_FAIL;
722 else
724 *fragment_start = (BYTE*)This->data + offset;
725 return S_OK;
729 static void WINAPI fontdatastream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
731 /* Do Nothing */
734 static HRESULT WINAPI fontdatastream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
736 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
737 *size = This->size;
738 return S_OK;
741 static HRESULT WINAPI fontdatastream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
743 return E_NOTIMPL;
746 static const IDWriteFontFileStreamVtbl fontdatastreamvtbl =
748 fontdatastream_QueryInterface,
749 fontdatastream_AddRef,
750 fontdatastream_Release,
751 fontdatastream_ReadFileFragment,
752 fontdatastream_ReleaseFileFragment,
753 fontdatastream_GetFileSize,
754 fontdatastream_GetLastWriteTime
757 static HRESULT create_fontdatastream(LPVOID data, UINT size, IDWriteFontFileStream** iface)
759 struct test_fontdatastream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct test_fontdatastream));
760 if (!This)
761 return E_OUTOFMEMORY;
763 This->data = data;
764 This->size = size;
765 This->ref = 1;
766 This->IDWriteFontFileStream_iface.lpVtbl = &fontdatastreamvtbl;
768 *iface = &This->IDWriteFontFileStream_iface;
769 return S_OK;
772 static HRESULT WINAPI resourcefontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
774 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
776 *obj = iface;
777 return S_OK;
779 *obj = NULL;
780 return E_NOINTERFACE;
783 static ULONG WINAPI resourcefontfileloader_AddRef(IDWriteFontFileLoader *iface)
785 return 2;
788 static ULONG WINAPI resourcefontfileloader_Release(IDWriteFontFileLoader *iface)
790 return 1;
793 static HRESULT WINAPI resourcefontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
794 IDWriteFontFileStream **stream)
796 LPVOID data;
797 DWORD size;
798 HGLOBAL mem;
800 mem = LoadResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
801 ok(mem != NULL, "Failed to lock font resource\n");
802 if (mem)
804 size = SizeofResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
805 data = LockResource(mem);
806 return create_fontdatastream(data, size, stream);
808 return E_FAIL;
811 static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = {
812 resourcefontfileloader_QueryInterface,
813 resourcefontfileloader_AddRef,
814 resourcefontfileloader_Release,
815 resourcefontfileloader_CreateStreamFromKey
818 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
820 static D2D1_POINT_2F g_startpoints[2];
821 static int g_startpoint_count;
823 static HRESULT WINAPI test_geometrysink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **ret)
825 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
826 IsEqualIID(riid, &IID_IUnknown))
828 *ret = iface;
829 ID2D1SimplifiedGeometrySink_AddRef(iface);
830 return S_OK;
833 *ret = NULL;
834 return E_NOINTERFACE;
837 static ULONG WINAPI test_geometrysink_AddRef(ID2D1SimplifiedGeometrySink *iface)
839 return 2;
842 static ULONG WINAPI test_geometrysink_Release(ID2D1SimplifiedGeometrySink *iface)
844 return 1;
847 static void WINAPI test_geometrysink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
849 CHECK_EXPECT(setfillmode);
850 ok(mode == D2D1_FILL_MODE_WINDING, "fill mode %d\n", mode);
853 static void WINAPI test_geometrysink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT flags)
855 ok(0, "unexpected SetSegmentFlags() - flags %d\n", flags);
858 static void WINAPI test_geometrysink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
859 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
861 ok(figureBegin == D2D1_FIGURE_BEGIN_FILLED, "begin figure %d\n", figureBegin);
862 if (g_startpoint_count < sizeof(g_startpoints)/sizeof(g_startpoints[0]))
863 g_startpoints[g_startpoint_count] = startPoint;
864 g_startpoint_count++;
867 static void WINAPI test_geometrysink_AddLines(ID2D1SimplifiedGeometrySink *iface,
868 const D2D1_POINT_2F *points, UINT32 count)
872 static void WINAPI test_geometrysink_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
873 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
877 static void WINAPI test_geometrysink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
879 ok(figureEnd == D2D1_FIGURE_END_CLOSED, "end figure %d\n", figureEnd);
882 static HRESULT WINAPI test_geometrysink_Close(ID2D1SimplifiedGeometrySink *iface)
884 ok(0, "unexpected Close()\n");
885 return E_NOTIMPL;
888 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink_vtbl = {
889 test_geometrysink_QueryInterface,
890 test_geometrysink_AddRef,
891 test_geometrysink_Release,
892 test_geometrysink_SetFillMode,
893 test_geometrysink_SetSegmentFlags,
894 test_geometrysink_BeginFigure,
895 test_geometrysink_AddLines,
896 test_geometrysink_AddBeziers,
897 test_geometrysink_EndFigure,
898 test_geometrysink_Close
901 static void WINAPI test_geometrysink2_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
902 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
904 ok(0, "unexpected call\n");
907 static void WINAPI test_geometrysink2_AddLines(ID2D1SimplifiedGeometrySink *iface,
908 const D2D1_POINT_2F *points, UINT32 count)
910 ok(0, "unexpected call\n");
913 static void WINAPI test_geometrysink2_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
914 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
916 ok(0, "unexpected call\n");
919 static void WINAPI test_geometrysink2_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
921 ok(0, "unexpected call\n");
924 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink2_vtbl = {
925 test_geometrysink_QueryInterface,
926 test_geometrysink_AddRef,
927 test_geometrysink_Release,
928 test_geometrysink_SetFillMode,
929 test_geometrysink_SetSegmentFlags,
930 test_geometrysink2_BeginFigure,
931 test_geometrysink2_AddLines,
932 test_geometrysink2_AddBeziers,
933 test_geometrysink2_EndFigure,
934 test_geometrysink_Close
937 static ID2D1SimplifiedGeometrySink test_geomsink = { &test_geometrysink_vtbl };
938 static ID2D1SimplifiedGeometrySink test_geomsink2 = { &test_geometrysink2_vtbl };
940 static void test_CreateFontFromLOGFONT(void)
942 static const WCHAR tahomaspW[] = {'T','a','h','o','m','a',' ',0};
943 IDWriteGdiInterop1 *interop1;
944 IDWriteGdiInterop *interop;
945 DWRITE_FONT_WEIGHT weight;
946 DWRITE_FONT_STYLE style;
947 IDWriteFont *font;
948 LOGFONTW logfont;
949 LONG weights[][2] = {
950 {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
951 {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
952 { 0, DWRITE_FONT_WEIGHT_NORMAL},
953 { 50, DWRITE_FONT_WEIGHT_NORMAL},
954 {150, DWRITE_FONT_WEIGHT_NORMAL},
955 {250, DWRITE_FONT_WEIGHT_NORMAL},
956 {350, DWRITE_FONT_WEIGHT_NORMAL},
957 {450, DWRITE_FONT_WEIGHT_NORMAL},
958 {650, DWRITE_FONT_WEIGHT_BOLD},
959 {750, DWRITE_FONT_WEIGHT_BOLD},
960 {850, DWRITE_FONT_WEIGHT_BOLD},
961 {950, DWRITE_FONT_WEIGHT_BOLD},
962 {960, DWRITE_FONT_WEIGHT_BOLD},
964 OUTLINETEXTMETRICW otm;
965 IDWriteFactory *factory;
966 HRESULT hr;
967 BOOL ret;
968 HDC hdc;
969 HFONT hfont;
970 BOOL exists;
971 ULONG ref;
972 int i;
973 UINT r;
975 factory = create_factory();
977 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
978 ok(hr == S_OK, "got %#x\n", hr);
980 if (0)
981 /* null out parameter crashes this call */
982 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
984 font = (void*)0xdeadbeef;
985 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
986 EXPECT_HR(hr, E_INVALIDARG);
987 ok(font == NULL, "got %p\n", font);
989 memset(&logfont, 0, sizeof(logfont));
990 logfont.lfHeight = 12;
991 logfont.lfWidth = 12;
992 logfont.lfWeight = FW_NORMAL;
993 logfont.lfItalic = 1;
994 lstrcpyW(logfont.lfFaceName, tahomaW);
996 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
997 EXPECT_HR(hr, S_OK);
999 hfont = CreateFontIndirectW(&logfont);
1000 hdc = CreateCompatibleDC(0);
1001 SelectObject(hdc, hfont);
1003 otm.otmSize = sizeof(otm);
1004 r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
1005 ok(r, "got %d\n", r);
1006 DeleteDC(hdc);
1007 DeleteObject(hfont);
1009 exists = TRUE;
1010 hr = IDWriteFont_HasCharacter(font, 0xd800, &exists);
1011 ok(hr == S_OK, "got 0x%08x\n", hr);
1012 ok(exists == FALSE, "got %d\n", exists);
1014 exists = FALSE;
1015 hr = IDWriteFont_HasCharacter(font, 0x20, &exists);
1016 ok(hr == S_OK, "got 0x%08x\n", hr);
1017 ok(exists == TRUE, "got %d\n", exists);
1019 /* now check properties */
1020 weight = IDWriteFont_GetWeight(font);
1021 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1023 style = IDWriteFont_GetStyle(font);
1024 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1025 ok(otm.otmfsSelection & 1, "got 0x%08x\n", otm.otmfsSelection);
1027 ret = IDWriteFont_IsSymbolFont(font);
1028 ok(!ret, "got %d\n", ret);
1030 IDWriteFont_Release(font);
1032 /* weight values */
1033 for (i = 0; i < sizeof(weights)/(2*sizeof(LONG)); i++)
1035 memset(&logfont, 0, sizeof(logfont));
1036 logfont.lfHeight = 12;
1037 logfont.lfWidth = 12;
1038 logfont.lfWeight = weights[i][0];
1039 lstrcpyW(logfont.lfFaceName, tahomaW);
1041 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1042 EXPECT_HR(hr, S_OK);
1044 weight = IDWriteFont_GetWeight(font);
1045 ok(weight == weights[i][1],
1046 "%d: got %d, expected %d\n", i, weight, weights[i][1]);
1048 IDWriteFont_Release(font);
1051 /* weight not from enum */
1052 memset(&logfont, 0, sizeof(logfont));
1053 logfont.lfHeight = 12;
1054 logfont.lfWidth = 12;
1055 logfont.lfWeight = 550;
1056 lstrcpyW(logfont.lfFaceName, tahomaW);
1058 font = NULL;
1059 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1060 ok(hr == S_OK, "got 0x%08x\n", hr);
1062 weight = IDWriteFont_GetWeight(font);
1063 ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
1064 "got %d\n", weight);
1066 IDWriteFont_Release(font);
1068 /* empty or nonexistent face name */
1069 memset(&logfont, 0, sizeof(logfont));
1070 logfont.lfHeight = 12;
1071 logfont.lfWidth = 12;
1072 logfont.lfWeight = FW_NORMAL;
1073 lstrcpyW(logfont.lfFaceName, blahW);
1075 font = (void*)0xdeadbeef;
1076 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1077 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1078 ok(font == NULL, "got %p\n", font);
1080 /* Try with name 'Tahoma ' */
1081 memset(&logfont, 0, sizeof(logfont));
1082 logfont.lfHeight = 12;
1083 logfont.lfWidth = 12;
1084 logfont.lfWeight = FW_NORMAL;
1085 lstrcpyW(logfont.lfFaceName, tahomaspW);
1087 font = (void*)0xdeadbeef;
1088 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1089 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1090 ok(font == NULL, "got %p\n", font);
1092 /* empty string as a facename */
1093 memset(&logfont, 0, sizeof(logfont));
1094 logfont.lfHeight = 12;
1095 logfont.lfWidth = 12;
1096 logfont.lfWeight = FW_NORMAL;
1098 font = (void*)0xdeadbeef;
1099 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1100 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
1101 ok(font == NULL, "got %p\n", font);
1103 /* IDWriteGdiInterop1::CreateFontFromLOGFONT() */
1104 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
1105 if (hr == S_OK) {
1106 memset(&logfont, 0, sizeof(logfont));
1107 logfont.lfHeight = 12;
1108 logfont.lfWidth = 12;
1109 logfont.lfWeight = FW_NORMAL;
1110 logfont.lfItalic = 1;
1111 lstrcpyW(logfont.lfFaceName, tahomaW);
1113 hr = IDWriteGdiInterop1_CreateFontFromLOGFONT(interop1, &logfont, NULL, &font);
1114 ok(hr == S_OK, "got 0x%08x\n", hr);
1116 IDWriteFont_Release(font);
1117 IDWriteGdiInterop1_Release(interop1);
1119 else
1120 win_skip("IDWriteGdiInterop1 is not supported, skipping CreateFontFromLOGFONT() tests.\n");
1122 ref = IDWriteGdiInterop_Release(interop);
1123 ok(ref == 0, "interop is not released, %u\n", ref);
1124 ref = IDWriteFactory_Release(factory);
1125 ok(ref == 0, "factory is not released, %u\n", ref);
1128 static void test_CreateBitmapRenderTarget(void)
1130 IDWriteBitmapRenderTarget *target, *target2;
1131 IDWriteBitmapRenderTarget1 *target1;
1132 IDWriteRenderingParams *params;
1133 IDWriteGdiInterop *interop;
1134 IDWriteFontFace *fontface;
1135 IDWriteFactory *factory;
1136 DWRITE_GLYPH_RUN run;
1137 HBITMAP hbm, hbm2;
1138 UINT16 glyphs[2];
1139 DWRITE_MATRIX m;
1140 DIBSECTION ds;
1141 XFORM xform;
1142 COLORREF c;
1143 HRESULT hr;
1144 FLOAT pdip;
1145 SIZE size;
1146 ULONG ref;
1147 UINT32 ch;
1148 HDC hdc;
1149 int ret;
1151 factory = create_factory();
1153 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1154 EXPECT_HR(hr, S_OK);
1156 target = NULL;
1157 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
1158 EXPECT_HR(hr, S_OK);
1160 if (0) /* crashes on native */
1161 hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
1163 size.cx = size.cy = -1;
1164 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1165 EXPECT_HR(hr, S_OK);
1166 ok(size.cx == 0, "got %d\n", size.cx);
1167 ok(size.cy == 0, "got %d\n", size.cy);
1169 target2 = NULL;
1170 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
1171 EXPECT_HR(hr, S_OK);
1172 ok(target != target2, "got %p, %p\n", target2, target);
1173 IDWriteBitmapRenderTarget_Release(target2);
1175 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1176 ok(hdc != NULL, "got %p\n", hdc);
1178 /* test mode */
1179 ret = GetGraphicsMode(hdc);
1180 ok(ret == GM_ADVANCED, "got %d\n", ret);
1182 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1183 ok(hbm != NULL, "got %p\n", hbm);
1185 /* check DIB properties */
1186 ret = GetObjectW(hbm, sizeof(ds), &ds);
1187 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1188 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1189 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1190 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1191 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1192 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1194 IDWriteBitmapRenderTarget_Release(target);
1196 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1197 ok(!hbm, "got %p\n", hbm);
1199 target = NULL;
1200 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
1201 EXPECT_HR(hr, S_OK);
1203 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1204 ok(hdc != NULL, "got %p\n", hdc);
1206 /* test context settings */
1207 c = GetTextColor(hdc);
1208 ok(c == RGB(0, 0, 0), "got 0x%08x\n", c);
1209 ret = GetBkMode(hdc);
1210 ok(ret == OPAQUE, "got %d\n", ret);
1211 c = GetBkColor(hdc);
1212 ok(c == RGB(255, 255, 255), "got 0x%08x\n", c);
1214 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1215 ok(hbm != NULL, "got %p\n", hbm);
1217 /* check DIB properties */
1218 ret = GetObjectW(hbm, sizeof(ds), &ds);
1219 ok(ret == sizeof(ds), "got %d\n", ret);
1220 ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
1221 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1222 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1223 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1224 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1226 size.cx = size.cy = -1;
1227 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1228 EXPECT_HR(hr, S_OK);
1229 ok(size.cx == 10, "got %d\n", size.cx);
1230 ok(size.cy == 5, "got %d\n", size.cy);
1232 /* resize to same size */
1233 hr = IDWriteBitmapRenderTarget_Resize(target, 10, 5);
1234 ok(hr == S_OK, "got 0x%08x\n", hr);
1236 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1237 ok(hbm2 == hbm, "got %p, %p\n", hbm2, hbm);
1239 /* shrink */
1240 hr = IDWriteBitmapRenderTarget_Resize(target, 5, 5);
1241 ok(hr == S_OK, "got 0x%08x\n", hr);
1243 size.cx = size.cy = -1;
1244 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1245 ok(hr == S_OK, "got 0x%08x\n", hr);
1246 ok(size.cx == 5, "got %d\n", size.cx);
1247 ok(size.cy == 5, "got %d\n", size.cy);
1249 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1250 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1252 hr = IDWriteBitmapRenderTarget_Resize(target, 20, 5);
1253 ok(hr == S_OK, "got 0x%08x\n", hr);
1255 size.cx = size.cy = -1;
1256 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1257 ok(hr == S_OK, "got 0x%08x\n", hr);
1258 ok(size.cx == 20, "got %d\n", size.cx);
1259 ok(size.cy == 5, "got %d\n", size.cy);
1261 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1262 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1264 hr = IDWriteBitmapRenderTarget_Resize(target, 1, 5);
1265 ok(hr == S_OK, "got 0x%08x\n", hr);
1267 size.cx = size.cy = -1;
1268 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1269 ok(hr == S_OK, "got 0x%08x\n", hr);
1270 ok(size.cx == 1, "got %d\n", size.cx);
1271 ok(size.cy == 5, "got %d\n", size.cy);
1273 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1274 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1276 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1277 ok(ret == sizeof(ds), "got %d\n", ret);
1278 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1279 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1280 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1281 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1282 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1284 /* empty rectangle */
1285 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 5);
1286 ok(hr == S_OK, "got 0x%08x\n", hr);
1288 size.cx = size.cy = -1;
1289 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1290 ok(hr == S_OK, "got 0x%08x\n", hr);
1291 ok(size.cx == 0, "got %d\n", size.cx);
1292 ok(size.cy == 5, "got %d\n", size.cy);
1294 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1295 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1297 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1298 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1299 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1300 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1301 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1302 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1303 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1305 /* transform tests, current hdc transform is not immediately affected */
1306 if (0) /* crashes on native */
1307 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, NULL);
1309 memset(&m, 0xcc, sizeof(m));
1310 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1311 ok(hr == S_OK, "got 0x%08x\n", hr);
1312 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);
1313 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1314 ret = GetWorldTransform(hdc, &xform);
1315 ok(ret, "got %d\n", ret);
1316 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1317 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1319 memset(&m, 0, sizeof(m));
1320 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1321 ok(hr == S_OK, "got 0x%08x\n", hr);
1323 memset(&m, 0xcc, sizeof(m));
1324 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1325 ok(hr == S_OK, "got 0x%08x\n", hr);
1326 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);
1327 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1328 ret = GetWorldTransform(hdc, &xform);
1329 ok(ret, "got %d\n", ret);
1330 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1331 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1333 memset(&m, 0, sizeof(m));
1334 m.m11 = 2.0; m.m22 = 1.0;
1335 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1336 ok(hr == S_OK, "got 0x%08x\n", hr);
1337 ret = GetWorldTransform(hdc, &xform);
1338 ok(ret, "got %d\n", ret);
1339 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1340 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1342 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, NULL);
1343 ok(hr == S_OK, "got 0x%08x\n", hr);
1345 memset(&m, 0xcc, sizeof(m));
1346 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1347 ok(hr == S_OK, "got 0x%08x\n", hr);
1348 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);
1349 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1351 /* pixels per dip */
1352 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1353 ok(pdip == 1.0, "got %.2f\n", pdip);
1355 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
1356 ok(hr == S_OK, "got 0x%08x\n", hr);
1358 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, -1.0);
1359 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1361 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 0.0);
1362 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1364 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1365 ok(pdip == 2.0, "got %.2f\n", pdip);
1367 hr = IDWriteBitmapRenderTarget_QueryInterface(target, &IID_IDWriteBitmapRenderTarget1, (void**)&target1);
1368 if (hr == S_OK) {
1369 DWRITE_TEXT_ANTIALIAS_MODE mode;
1371 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1372 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1374 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE+1);
1375 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1377 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1378 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1380 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
1381 ok(hr == S_OK, "got 0x%08x\n", hr);
1383 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1384 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, "got %d\n", mode);
1386 IDWriteBitmapRenderTarget1_Release(target1);
1388 else
1389 win_skip("IDWriteBitmapRenderTarget1 is not supported.\n");
1391 /* DrawGlyphRun() argument validation. */
1392 hr = IDWriteBitmapRenderTarget_Resize(target, 16, 16);
1393 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
1395 fontface = create_fontface(factory);
1397 ch = 'A';
1398 glyphs[0] = 0;
1399 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, glyphs);
1400 ok(hr == S_OK, "got 0x%08x\n", hr);
1401 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
1402 glyphs[1] = glyphs[0];
1404 memset(&run, 0, sizeof(run));
1405 run.fontFace = fontface;
1406 run.fontEmSize = 12.0f;
1407 run.glyphCount = 2;
1408 run.glyphIndices = glyphs;
1410 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
1411 DWRITE_RENDERING_MODE_DEFAULT, &params);
1412 ok(hr == S_OK, "Failed to create rendering params, hr %#x.\n", hr);
1414 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1415 &run, NULL, RGB(255, 0, 0), NULL);
1416 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1418 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1419 &run, NULL, RGB(255, 0, 0), NULL);
1420 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1422 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1423 &run, params, RGB(255, 0, 0), NULL);
1424 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* Vista */, "Unexpected hr %#x.\n", hr);
1426 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL,
1427 &run, params, RGB(255, 0, 0), NULL);
1428 ok(hr == S_OK, "Failed to draw a run, hr %#x.\n", hr);
1430 IDWriteRenderingParams_Release(params);
1432 /* Zero sized target returns earlier. */
1433 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 16);
1434 ok(hr == S_OK, "Failed to resize target, hr %#x.\n", hr);
1436 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_NATURAL,
1437 &run, NULL, RGB(255, 0, 0), NULL);
1438 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1440 hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL + 1,
1441 &run, params, RGB(255, 0, 0), NULL);
1442 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
1444 IDWriteFontFace_Release(fontface);
1446 ref = IDWriteBitmapRenderTarget_Release(target);
1447 ok(ref == 0, "render target not released, %u\n", ref);
1448 ref = IDWriteGdiInterop_Release(interop);
1449 ok(ref == 0, "interop not released, %u\n", ref);
1450 ref = IDWriteFactory_Release(factory);
1451 ok(ref == 0, "factory not released, %u\n", ref);
1454 static void test_GetFontFamily(void)
1456 IDWriteFontCollection *collection, *collection2;
1457 IDWriteFontCollection *syscoll;
1458 IDWriteFontFamily *family, *family2;
1459 IDWriteFontFamily1 *family1;
1460 IDWriteGdiInterop *interop;
1461 IDWriteFont *font, *font2;
1462 IDWriteFactory *factory;
1463 LOGFONTW logfont;
1464 HRESULT hr;
1465 ULONG ref;
1467 factory = create_factory();
1469 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1470 EXPECT_HR(hr, S_OK);
1472 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1473 ok(hr == S_OK, "got 0x%08x\n", hr);
1475 memset(&logfont, 0, sizeof(logfont));
1476 logfont.lfHeight = 12;
1477 logfont.lfWidth = 12;
1478 logfont.lfWeight = FW_NORMAL;
1479 logfont.lfItalic = 1;
1480 lstrcpyW(logfont.lfFaceName, tahomaW);
1482 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1483 ok(hr == S_OK, "got 0x%08x\n", hr);
1485 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1486 ok(hr == S_OK, "got 0x%08x\n", hr);
1487 ok(font2 != font, "got %p, %p\n", font2, font);
1489 if (0) /* crashes on native */
1490 hr = IDWriteFont_GetFontFamily(font, NULL);
1492 EXPECT_REF(font, 1);
1493 hr = IDWriteFont_GetFontFamily(font, &family);
1494 EXPECT_HR(hr, S_OK);
1495 EXPECT_REF(font, 1);
1496 EXPECT_REF(family, 2);
1498 hr = IDWriteFont_GetFontFamily(font, &family2);
1499 EXPECT_HR(hr, S_OK);
1500 ok(family2 == family, "got %p, previous %p\n", family2, family);
1501 EXPECT_REF(font, 1);
1502 EXPECT_REF(family, 3);
1503 IDWriteFontFamily_Release(family2);
1505 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
1506 EXPECT_HR(hr, E_NOINTERFACE);
1507 ok(family2 == NULL, "got %p\n", family2);
1509 hr = IDWriteFont_GetFontFamily(font2, &family2);
1510 ok(hr == S_OK, "got 0x%08x\n", hr);
1511 ok(family2 != family, "got %p, %p\n", family2, family);
1513 collection = NULL;
1514 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
1515 ok(hr == S_OK, "got 0x%08x\n", hr);
1517 collection2 = NULL;
1518 hr = IDWriteFontFamily_GetFontCollection(family2, &collection2);
1519 ok(hr == S_OK, "got 0x%08x\n", hr);
1520 ok(collection == collection2, "got %p, %p\n", collection, collection2);
1521 ok(collection == syscoll, "got %p, %p\n", collection, syscoll);
1523 IDWriteFont_Release(font);
1524 IDWriteFont_Release(font2);
1526 hr = IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily1, (void**)&family1);
1527 if (hr == S_OK) {
1528 IDWriteFontFaceReference *ref, *ref1;
1529 IDWriteFontList *fontlist;
1530 IDWriteFont3 *font3;
1531 IDWriteFont1 *font1;
1533 font3 = (void*)0xdeadbeef;
1534 hr = IDWriteFontFamily1_GetFont(family1, ~0u, &font3);
1535 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1536 ok(font3 == NULL, "got %p\n", font3);
1538 hr = IDWriteFontFamily1_GetFont(family1, 0, &font3);
1539 ok(hr == S_OK, "got 0x%08x\n", hr);
1541 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont, (void**)&font);
1542 ok(hr == S_OK, "got 0x%08x\n", hr);
1543 IDWriteFont_Release(font);
1545 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont1, (void**)&font1);
1546 ok(hr == S_OK, "got 0x%08x\n", hr);
1547 IDWriteFont1_Release(font1);
1549 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList1, (void**)&fontlist);
1550 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1552 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void**)&fontlist);
1553 ok(hr == S_OK, "got 0x%08x\n", hr);
1554 IDWriteFontList_Release(fontlist);
1556 IDWriteFont3_Release(font3);
1558 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref);
1559 ok(hr == S_OK, "got 0x%08x\n", hr);
1561 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref1);
1562 ok(hr == S_OK, "got 0x%08x\n", hr);
1563 ok(ref != ref1, "got %p, %p\n", ref, ref1);
1565 IDWriteFontFaceReference_Release(ref);
1566 IDWriteFontFaceReference_Release(ref1);
1568 IDWriteFontFamily1_Release(family1);
1570 else
1571 win_skip("IDWriteFontFamily1 is not supported.\n");
1573 IDWriteFontCollection_Release(syscoll);
1574 IDWriteFontCollection_Release(collection2);
1575 IDWriteFontCollection_Release(collection);
1576 IDWriteFontFamily_Release(family2);
1577 IDWriteFontFamily_Release(family);
1578 IDWriteGdiInterop_Release(interop);
1579 ref = IDWriteFactory_Release(factory);
1580 ok(ref == 0, "factory not released, %u\n", ref);
1583 static void test_GetFamilyNames(void)
1585 IDWriteFontFamily *family;
1586 IDWriteLocalizedStrings *names, *names2;
1587 IDWriteGdiInterop *interop;
1588 IDWriteFactory *factory;
1589 IDWriteFont *font;
1590 LOGFONTW logfont;
1591 WCHAR buffer[100];
1592 HRESULT hr;
1593 UINT32 len;
1594 ULONG ref;
1596 factory = create_factory();
1598 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1599 EXPECT_HR(hr, S_OK);
1601 memset(&logfont, 0, sizeof(logfont));
1602 logfont.lfHeight = 12;
1603 logfont.lfWidth = 12;
1604 logfont.lfWeight = FW_NORMAL;
1605 logfont.lfItalic = 1;
1606 lstrcpyW(logfont.lfFaceName, tahomaW);
1608 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1609 EXPECT_HR(hr, S_OK);
1611 hr = IDWriteFont_GetFontFamily(font, &family);
1612 EXPECT_HR(hr, S_OK);
1614 if (0) /* crashes on native */
1615 hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
1617 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1618 ok(hr == S_OK, "got 0x%08x\n", hr);
1619 EXPECT_REF(names, 1);
1621 hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
1622 ok(hr == S_OK, "got 0x%08x\n", hr);
1623 EXPECT_REF(names2, 1);
1624 ok(names != names2, "got %p, was %p\n", names2, names);
1626 IDWriteLocalizedStrings_Release(names2);
1628 /* GetStringLength */
1629 if (0) /* crashes on native */
1630 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
1632 len = 100;
1633 hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
1634 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1635 ok(len == (UINT32)-1, "got %u\n", len);
1637 len = 0;
1638 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
1639 ok(hr == S_OK, "got 0x%08x\n", hr);
1640 ok(len > 0, "got %u\n", len);
1642 /* GetString */
1643 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
1644 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1646 hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
1647 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1649 if (0)
1650 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
1652 buffer[0] = 1;
1653 hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
1654 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1655 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1657 buffer[0] = 1;
1658 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
1659 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1660 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1662 buffer[0] = 1;
1663 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
1664 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1665 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1667 buffer[0] = 0;
1668 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1669 ok(hr == S_OK, "got 0x%08x\n", hr);
1670 ok(buffer[0] != 0, "got %x\n", buffer[0]);
1672 IDWriteLocalizedStrings_Release(names);
1674 IDWriteFontFamily_Release(family);
1675 IDWriteFont_Release(font);
1676 IDWriteGdiInterop_Release(interop);
1677 ref = IDWriteFactory_Release(factory);
1678 ok(ref == 0, "factory not released, %u\n", ref);
1681 static void test_CreateFontFace(void)
1683 IDWriteFontFace *fontface, *fontface2;
1684 IDWriteFontCollection *collection;
1685 DWRITE_FONT_FILE_TYPE file_type;
1686 DWRITE_FONT_FACE_TYPE face_type;
1687 IDWriteGdiInterop *interop;
1688 IDWriteFont *font, *font2;
1689 IDWriteFontFamily *family;
1690 IDWriteFactory *factory;
1691 IDWriteFontFile *file;
1692 LOGFONTW logfont;
1693 BOOL supported;
1694 UINT32 count;
1695 WCHAR *path;
1696 HRESULT hr;
1698 factory = create_factory();
1700 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1701 EXPECT_HR(hr, S_OK);
1703 memset(&logfont, 0, sizeof(logfont));
1704 logfont.lfHeight = 12;
1705 logfont.lfWidth = 12;
1706 logfont.lfWeight = FW_NORMAL;
1707 logfont.lfItalic = 1;
1708 lstrcpyW(logfont.lfFaceName, tahomaW);
1710 font = NULL;
1711 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1712 ok(hr == S_OK, "got 0x%08x\n", hr);
1714 font2 = NULL;
1715 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1716 ok(hr == S_OK, "got 0x%08x\n", hr);
1717 ok(font != font2, "got %p, %p\n", font, font2);
1719 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
1720 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1722 if (0) /* crashes on native */
1723 hr = IDWriteFont_CreateFontFace(font, NULL);
1725 fontface = NULL;
1726 hr = IDWriteFont_CreateFontFace(font, &fontface);
1727 ok(hr == S_OK, "got 0x%08x\n", hr);
1729 fontface2 = NULL;
1730 hr = IDWriteFont_CreateFontFace(font, &fontface2);
1731 ok(hr == S_OK, "got 0x%08x\n", hr);
1732 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1733 IDWriteFontFace_Release(fontface2);
1735 fontface2 = NULL;
1736 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1737 ok(hr == S_OK, "got 0x%08x\n", hr);
1738 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1739 IDWriteFontFace_Release(fontface2);
1741 IDWriteFont_Release(font2);
1742 IDWriteFont_Release(font);
1744 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFont, (void**)&font);
1745 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL), "got 0x%08x\n", hr);
1747 IDWriteFontFace_Release(fontface);
1748 IDWriteGdiInterop_Release(interop);
1750 /* Create from system collection */
1751 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1752 ok(hr == S_OK, "got 0x%08x\n", hr);
1754 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
1755 ok(hr == S_OK, "got 0x%08x\n", hr);
1757 font = NULL;
1758 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1759 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1760 ok(hr == S_OK, "got 0x%08x\n", hr);
1762 font2 = NULL;
1763 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1764 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
1765 ok(hr == S_OK, "got 0x%08x\n", hr);
1766 ok(font != font2, "got %p, %p\n", font, font2);
1768 fontface = NULL;
1769 hr = IDWriteFont_CreateFontFace(font, &fontface);
1770 ok(hr == S_OK, "got 0x%08x\n", hr);
1772 fontface2 = NULL;
1773 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1774 ok(hr == S_OK, "got 0x%08x\n", hr);
1775 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1777 IDWriteFontFace_Release(fontface);
1778 IDWriteFontFace_Release(fontface2);
1779 IDWriteFont_Release(font2);
1780 IDWriteFont_Release(font);
1781 IDWriteFontFamily_Release(family);
1782 IDWriteFontCollection_Release(collection);
1784 /* IDWriteFactory::CreateFontFace() */
1785 path = create_testfontfile(test_fontfile);
1786 factory = create_factory();
1788 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
1789 ok(hr == S_OK, "got 0x%08x\n",hr);
1791 supported = FALSE;
1792 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1793 face_type = DWRITE_FONT_FACE_TYPE_CFF;
1794 count = 0;
1795 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &count);
1796 ok(hr == S_OK, "got 0x%08x\n", hr);
1797 ok(supported == TRUE, "got %i\n", supported);
1798 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
1799 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
1800 ok(count == 1, "got %i\n", count);
1802 /* invalid simulation flags */
1803 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, ~0u, &fontface);
1804 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1806 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0xf, &fontface);
1807 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1809 /* try mismatching face type, the one that's not supported */
1810 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1811 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
1813 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, 1, &file, 0,
1814 DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1815 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* < win10 */, "got 0x%08x\n", hr);
1817 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_RAW_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1818 todo_wine
1819 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == E_INVALIDARG) /* older versions */, "got 0x%08x\n", hr);
1821 fontface = (void*)0xdeadbeef;
1822 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TYPE1, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1823 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1824 ok(fontface == NULL, "got %p\n", fontface);
1826 fontface = (void*)0xdeadbeef;
1827 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_VECTOR, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1828 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1829 ok(fontface == NULL, "got %p\n", fontface);
1831 fontface = (void*)0xdeadbeef;
1832 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_BITMAP, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1833 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1834 ok(fontface == NULL, "got %p\n", fontface);
1836 fontface = NULL;
1837 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_UNKNOWN, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1838 todo_wine
1839 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* < win10 */, "got 0x%08x\n", hr);
1840 if (hr == S_OK) {
1841 ok(fontface != NULL, "got %p\n", fontface);
1842 face_type = IDWriteFontFace_GetType(fontface);
1843 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %d\n", face_type);
1844 IDWriteFontFace_Release(fontface);
1847 IDWriteFontFile_Release(file);
1848 IDWriteFactory_Release(factory);
1849 DELETE_FONTFILE(path);
1852 static void get_expected_font_metrics(IDWriteFontFace *fontface, DWRITE_FONT_METRICS1 *metrics)
1854 void *os2_context, *head_context, *post_context, *hhea_context;
1855 const TT_OS2_V2 *tt_os2;
1856 const TT_HEAD *tt_head;
1857 const TT_POST *tt_post;
1858 const TT_HHEA *tt_hhea;
1859 UINT32 size;
1860 BOOL exists;
1861 HRESULT hr;
1863 memset(metrics, 0, sizeof(*metrics));
1865 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void**)&tt_os2, &size, &os2_context, &exists);
1866 ok(hr == S_OK, "got 0x%08x\n", hr);
1867 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void**)&tt_head, &size, &head_context, &exists);
1868 ok(hr == S_OK, "got 0x%08x\n", hr);
1869 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HHEA_TAG, (const void**)&tt_hhea, &size, &hhea_context, &exists);
1870 ok(hr == S_OK, "got 0x%08x\n", hr);
1871 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_POST_TAG, (const void**)&tt_post, &size, &post_context, &exists);
1872 ok(hr == S_OK, "got 0x%08x\n", hr);
1874 if (tt_head) {
1875 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
1876 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
1877 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
1878 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
1879 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
1882 if (tt_os2) {
1883 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
1884 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
1885 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1886 metrics->descent = descent < 0 ? -descent : 0;
1887 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1888 metrics->hasTypographicMetrics = TRUE;
1890 else {
1891 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
1892 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1893 interpreted as large unsigned value. */
1894 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
1896 if (tt_hhea) {
1897 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
1898 INT32 linegap;
1900 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
1901 metrics->ascent - metrics->descent;
1902 metrics->lineGap = linegap > 0 ? linegap : 0;
1906 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
1907 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
1909 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
1910 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
1911 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
1912 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
1913 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
1914 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
1915 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
1916 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
1919 if (tt_post) {
1920 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1921 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1924 if (metrics->underlineThickness == 0)
1925 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1926 if (metrics->strikethroughThickness == 0)
1927 metrics->strikethroughThickness = metrics->underlineThickness;
1929 if (tt_os2)
1930 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
1931 if (tt_head)
1932 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
1933 if (tt_hhea)
1934 IDWriteFontFace_ReleaseFontTable(fontface, hhea_context);
1935 if (tt_post)
1936 IDWriteFontFace_ReleaseFontTable(fontface, post_context);
1939 static void check_font_metrics(const WCHAR *nameW, BOOL has_metrics1, const DWRITE_FONT_METRICS *got,
1940 const DWRITE_FONT_METRICS1 *expected)
1942 ok(got->designUnitsPerEm == expected->designUnitsPerEm, "font %s: designUnitsPerEm %u, expected %u\n",
1943 wine_dbgstr_w(nameW), got->designUnitsPerEm, expected->designUnitsPerEm);
1944 ok(got->ascent == expected->ascent, "font %s: ascent %u, expected %u\n", wine_dbgstr_w(nameW), got->ascent,
1945 expected->ascent);
1946 ok(got->descent == expected->descent, "font %s: descent %u, expected %u\n", wine_dbgstr_w(nameW), got->descent,
1947 expected->descent);
1948 ok(got->lineGap == expected->lineGap, "font %s: lineGap %d, expected %d\n", wine_dbgstr_w(nameW), got->lineGap,
1949 expected->lineGap);
1950 ok(got->underlinePosition == expected->underlinePosition, "font %s: underlinePosition %d, expected %d\n",
1951 wine_dbgstr_w(nameW), got->underlinePosition, expected->underlinePosition);
1952 ok(got->underlineThickness == expected->underlineThickness, "font %s: underlineThickness %u, "
1953 "expected %u\n", wine_dbgstr_w(nameW), got->underlineThickness, expected->underlineThickness);
1954 ok(got->strikethroughPosition == expected->strikethroughPosition, "font %s: strikethroughPosition %d, expected %d\n",
1955 wine_dbgstr_w(nameW), got->strikethroughPosition, expected->strikethroughPosition);
1956 ok(got->strikethroughThickness == expected->strikethroughThickness, "font %s: strikethroughThickness %u, "
1957 "expected %u\n", wine_dbgstr_w(nameW), got->strikethroughThickness, expected->strikethroughThickness);
1959 if (has_metrics1) {
1960 const DWRITE_FONT_METRICS1 *m1 = (const DWRITE_FONT_METRICS1*)got;
1961 ok(m1->hasTypographicMetrics == expected->hasTypographicMetrics, "font %s: hasTypographicMetrics %d, "
1962 "expected %d\n", wine_dbgstr_w(nameW), m1->hasTypographicMetrics, expected->hasTypographicMetrics);
1963 ok(m1->glyphBoxLeft == expected->glyphBoxLeft, "font %s: glyphBoxLeft %d, expected %d\n", wine_dbgstr_w(nameW),
1964 m1->glyphBoxLeft, expected->glyphBoxLeft);
1965 ok(m1->glyphBoxTop == expected->glyphBoxTop, "font %s: glyphBoxTop %d, expected %d\n", wine_dbgstr_w(nameW),
1966 m1->glyphBoxTop, expected->glyphBoxTop);
1967 ok(m1->glyphBoxRight == expected->glyphBoxRight, "font %s: glyphBoxRight %d, expected %d\n", wine_dbgstr_w(nameW),
1968 m1->glyphBoxRight, expected->glyphBoxRight);
1969 ok(m1->glyphBoxBottom == expected->glyphBoxBottom, "font %s: glyphBoxBottom %d, expected %d\n", wine_dbgstr_w(nameW),
1970 m1->glyphBoxBottom, expected->glyphBoxBottom);
1972 ok(m1->subscriptPositionX == expected->subscriptPositionX, "font %s: subscriptPositionX %d, expected %d\n",
1973 wine_dbgstr_w(nameW), m1->subscriptPositionX, expected->subscriptPositionX);
1974 ok(m1->subscriptPositionY == expected->subscriptPositionY, "font %s: subscriptPositionY %d, expected %d\n",
1975 wine_dbgstr_w(nameW), m1->subscriptPositionY, expected->subscriptPositionY);
1976 ok(m1->subscriptSizeX == expected->subscriptSizeX, "font %s: subscriptSizeX %d, expected %d\n",
1977 wine_dbgstr_w(nameW), m1->subscriptSizeX, expected->subscriptSizeX);
1978 ok(m1->subscriptSizeY == expected->subscriptSizeY, "font %s: subscriptSizeY %d, expected %d\n",
1979 wine_dbgstr_w(nameW), m1->subscriptSizeY, expected->subscriptSizeY);
1980 ok(m1->superscriptPositionX == expected->superscriptPositionX, "font %s: superscriptPositionX %d, expected %d\n",
1981 wine_dbgstr_w(nameW), m1->superscriptPositionX, expected->superscriptPositionX);
1982 ok(m1->superscriptPositionY == expected->superscriptPositionY, "font %s: superscriptPositionY %d, expected %d\n",
1983 wine_dbgstr_w(nameW), m1->superscriptPositionY, expected->superscriptPositionY);
1984 ok(m1->superscriptSizeX == expected->superscriptSizeX, "font %s: superscriptSizeX %d, expected %d\n",
1985 wine_dbgstr_w(nameW), m1->superscriptSizeX, expected->superscriptSizeX);
1986 ok(m1->superscriptSizeY == expected->superscriptSizeY, "font %s: superscriptSizeY %d, expected %d\n",
1987 wine_dbgstr_w(nameW), m1->superscriptSizeY, expected->superscriptSizeY);
1991 static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
1993 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1994 BOOL exists = FALSE;
1995 UINT32 index;
1996 HRESULT hr;
1998 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
1999 ok(hr == S_OK, "got 0x%08x\n", hr);
2000 ok(exists, "got %d\n", exists);
2002 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
2003 ok(hr == S_OK, "got 0x%08x\n", hr);
2006 static void test_GetMetrics(void)
2008 DWRITE_FONT_METRICS metrics, metrics2;
2009 IDWriteFontCollection *syscollection;
2010 IDWriteGdiInterop *interop;
2011 IDWriteFontFace *fontface;
2012 IDWriteFactory *factory;
2013 OUTLINETEXTMETRICW otm;
2014 IDWriteFontFile *file;
2015 IDWriteFont1 *font1;
2016 IDWriteFont *font;
2017 LOGFONTW logfont;
2018 UINT32 count, i;
2019 HRESULT hr;
2020 HDC hdc;
2021 HFONT hfont;
2022 ULONG ref;
2023 int ret;
2025 factory = create_factory();
2027 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2028 EXPECT_HR(hr, S_OK);
2030 memset(&logfont, 0, sizeof(logfont));
2031 logfont.lfHeight = 12;
2032 logfont.lfWidth = 12;
2033 logfont.lfWeight = FW_NORMAL;
2034 logfont.lfItalic = 1;
2035 lstrcpyW(logfont.lfFaceName, tahomaW);
2037 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2038 ok(hr == S_OK, "got 0x%08x\n", hr);
2040 hfont = CreateFontIndirectW(&logfont);
2041 hdc = CreateCompatibleDC(0);
2042 SelectObject(hdc, hfont);
2044 otm.otmSize = sizeof(otm);
2045 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
2046 ok(ret, "got %d\n", ret);
2047 DeleteDC(hdc);
2048 DeleteObject(hfont);
2050 if (0) /* crashes on native */
2051 IDWriteFont_GetMetrics(font, NULL);
2053 memset(&metrics, 0, sizeof(metrics));
2054 IDWriteFont_GetMetrics(font, &metrics);
2056 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2057 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2058 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2059 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2060 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2061 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2062 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2063 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2064 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2065 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2067 hr = IDWriteFont_CreateFontFace(font, &fontface);
2068 ok(hr == S_OK, "got 0x%08x\n", hr);
2070 memset(&metrics, 0, sizeof(metrics));
2071 IDWriteFontFace_GetMetrics(fontface, &metrics);
2073 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
2074 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
2075 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
2076 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
2077 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
2078 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
2079 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
2080 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
2081 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
2082 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
2084 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
2085 if (hr == S_OK) {
2086 DWRITE_FONT_METRICS1 metrics1;
2087 IDWriteFontFace1 *fontface1;
2089 memset(&metrics1, 0, sizeof(metrics1));
2090 IDWriteFont1_GetMetrics(font1, &metrics1);
2092 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2093 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2094 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2095 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2096 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2097 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2098 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2099 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2100 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2101 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2102 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2103 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2104 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2105 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2106 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2107 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2108 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2109 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2110 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2111 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2112 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2114 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2115 ok(hr == S_OK, "got 0x%08x\n", hr);
2117 memset(&metrics1, 0, sizeof(metrics1));
2118 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2120 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
2121 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
2122 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
2123 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
2124 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
2125 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
2126 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
2127 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
2128 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
2129 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
2130 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
2131 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
2132 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
2133 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
2134 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
2135 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
2136 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
2137 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
2138 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
2139 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
2140 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
2142 IDWriteFontFace1_Release(fontface1);
2143 IDWriteFont1_Release(font1);
2145 else
2146 win_skip("DWRITE_FONT_METRICS1 is not supported.\n");
2148 IDWriteFontFace_Release(fontface);
2149 IDWriteFont_Release(font);
2150 IDWriteGdiInterop_Release(interop);
2152 /* bold simulation affects returned font metrics */
2153 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
2155 /* create regulat Tahoma with bold simulation */
2156 hr = IDWriteFont_CreateFontFace(font, &fontface);
2157 ok(hr == S_OK, "got 0x%08x\n", hr);
2159 count = 1;
2160 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
2161 ok(hr == S_OK, "got 0x%08x\n", hr);
2163 IDWriteFontFace_GetMetrics(fontface, &metrics);
2164 ok(IDWriteFontFace_GetSimulations(fontface) == 0, "wrong simulations flags\n");
2165 IDWriteFontFace_Release(fontface);
2167 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
2168 0, DWRITE_FONT_SIMULATIONS_BOLD, &fontface);
2169 ok(hr == S_OK, "got 0x%08x\n", hr);
2170 IDWriteFontFace_GetMetrics(fontface, &metrics2);
2171 ok(IDWriteFontFace_GetSimulations(fontface) == DWRITE_FONT_SIMULATIONS_BOLD, "wrong simulations flags\n");
2173 ok(metrics.ascent == metrics2.ascent, "got %u, %u\n", metrics2.ascent, metrics.ascent);
2174 ok(metrics.descent == metrics2.descent, "got %u, %u\n", metrics2.descent, metrics.descent);
2175 ok(metrics.lineGap == metrics2.lineGap, "got %d, %d\n", metrics2.lineGap, metrics.lineGap);
2176 ok(metrics.capHeight == metrics2.capHeight, "got %u, %u\n", metrics2.capHeight, metrics.capHeight);
2177 ok(metrics.xHeight == metrics2.xHeight, "got %u, %u\n", metrics2.xHeight, metrics.xHeight);
2178 ok(metrics.underlinePosition == metrics2.underlinePosition, "got %d, %d\n", metrics2.underlinePosition,
2179 metrics.underlinePosition);
2180 ok(metrics.underlineThickness == metrics2.underlineThickness, "got %u, %u\n", metrics2.underlineThickness,
2181 metrics.underlineThickness);
2182 ok(metrics.strikethroughPosition == metrics2.strikethroughPosition, "got %d, %d\n", metrics2.strikethroughPosition,
2183 metrics.strikethroughPosition);
2184 ok(metrics.strikethroughThickness == metrics2.strikethroughThickness, "got %u, %u\n", metrics2.strikethroughThickness,
2185 metrics.strikethroughThickness);
2187 IDWriteFontFile_Release(file);
2188 IDWriteFontFace_Release(fontface);
2189 IDWriteFont_Release(font);
2191 /* test metrics for whole system collection */
2192 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
2193 ok(hr == S_OK, "got 0x%08x\n", hr);
2194 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
2196 for (i = 0; i < count; i++) {
2197 DWRITE_FONT_METRICS1 expected_metrics, metrics1;
2198 IDWriteLocalizedStrings *names;
2199 IDWriteFontFace1 *fontface1;
2200 IDWriteFontFamily *family;
2201 IDWriteFont *font;
2202 WCHAR nameW[256];
2204 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
2205 ok(hr == S_OK, "got 0x%08x\n", hr);
2207 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
2208 DWRITE_FONT_STYLE_NORMAL, &font);
2209 ok(hr == S_OK, "got 0x%08x\n", hr);
2211 hr = IDWriteFont_CreateFontFace(font, &fontface);
2212 ok(hr == S_OK, "got 0x%08x\n", hr);
2214 fontface1 = NULL;
2215 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2217 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2218 ok(hr == S_OK, "got 0x%08x\n", hr);
2220 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
2222 IDWriteLocalizedStrings_Release(names);
2223 IDWriteFont_Release(font);
2225 get_expected_font_metrics(fontface, &expected_metrics);
2226 if (fontface1) {
2227 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2228 check_font_metrics(nameW, TRUE, (const DWRITE_FONT_METRICS*)&metrics1, &expected_metrics);
2230 else {
2231 IDWriteFontFace_GetMetrics(fontface, &metrics);
2232 check_font_metrics(nameW, FALSE, &metrics, &expected_metrics);
2235 if (fontface1)
2236 IDWriteFontFace1_Release(fontface1);
2237 IDWriteFontFace_Release(fontface);
2238 IDWriteFontFamily_Release(family);
2240 IDWriteFontCollection_Release(syscollection);
2241 ref = IDWriteFactory_Release(factory);
2242 ok(ref == 0, "factory not released, %u\n", ref);
2245 static void test_system_fontcollection(void)
2247 IDWriteFontCollection *collection, *coll2;
2248 IDWriteLocalFontFileLoader *localloader;
2249 IDWriteFontCollection1 *collection1;
2250 IDWriteFactory *factory, *factory2;
2251 IDWriteFontFileLoader *loader;
2252 IDWriteFontFamily *family;
2253 IDWriteFontFace *fontface;
2254 IDWriteFontFile *file;
2255 IDWriteFont *font;
2256 HRESULT hr;
2257 ULONG ref;
2258 UINT32 i;
2259 BOOL ret;
2261 factory = create_factory();
2263 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2264 ok(hr == S_OK, "got 0x%08x\n", hr);
2266 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, FALSE);
2267 ok(hr == S_OK, "got 0x%08x\n", hr);
2268 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2269 IDWriteFontCollection_Release(coll2);
2271 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, TRUE);
2272 ok(hr == S_OK, "got 0x%08x\n", hr);
2273 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2274 IDWriteFontCollection_Release(coll2);
2276 factory2 = create_factory();
2277 hr = IDWriteFactory_GetSystemFontCollection(factory2, &coll2, FALSE);
2278 ok(hr == S_OK, "got 0x%08x\n", hr);
2279 ok(coll2 != collection, "got %p, was %p\n", coll2, collection);
2280 IDWriteFontCollection_Release(coll2);
2281 IDWriteFactory_Release(factory2);
2283 i = IDWriteFontCollection_GetFontFamilyCount(collection);
2284 ok(i, "got %u\n", i);
2286 /* invalid index */
2287 family = (void*)0xdeadbeef;
2288 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2289 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2290 ok(family == NULL, "got %p\n", family);
2292 ret = FALSE;
2293 i = (UINT32)-1;
2294 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaW, &i, &ret);
2295 ok(hr == S_OK, "got 0x%08x\n", hr);
2296 ok(ret, "got %d\n", ret);
2297 ok(i != (UINT32)-1, "got %u\n", i);
2299 ret = FALSE;
2300 i = (UINT32)-1;
2301 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaUppercaseW, &i, &ret);
2302 ok(hr == S_OK, "got 0x%08x\n", hr);
2303 ok(ret, "got %d\n", ret);
2304 ok(i != (UINT32)-1, "got %u\n", i);
2306 ret = FALSE;
2307 i = (UINT32)-1;
2308 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaStrangecaseW, &i, &ret);
2309 ok(hr == S_OK, "got 0x%08x\n", hr);
2310 ok(ret, "got %d\n", ret);
2311 ok(i != (UINT32)-1, "got %u\n", i);
2313 /* get back local file loader */
2314 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2315 ok(hr == S_OK, "got 0x%08x\n", hr);
2317 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2318 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2319 ok(hr == S_OK, "got 0x%08x\n", hr);
2320 IDWriteFontFamily_Release(family);
2322 hr = IDWriteFont_CreateFontFace(font, &fontface);
2323 ok(hr == S_OK, "got 0x%08x\n", hr);
2324 IDWriteFont_Release(font);
2326 i = 1;
2327 file = NULL;
2328 hr = IDWriteFontFace_GetFiles(fontface, &i, &file);
2329 ok(hr == S_OK, "got 0x%08x\n", hr);
2330 ok(file != NULL, "got %p\n", file);
2331 IDWriteFontFace_Release(fontface);
2333 hr = IDWriteFontFile_GetLoader(file, &loader);
2334 ok(hr == S_OK, "got 0x%08x\n", hr);
2335 IDWriteFontFile_Release(file);
2337 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2338 ok(hr == S_OK, "got 0x%08x\n", hr);
2339 IDWriteLocalFontFileLoader_Release(localloader);
2341 /* local loader is not registered by default */
2342 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
2343 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2344 hr = IDWriteFactory_UnregisterFontFileLoader(factory, loader);
2345 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2347 /* try with a different factory */
2348 factory2 = create_factory();
2349 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2350 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2351 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2352 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2353 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2354 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2355 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2356 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2357 IDWriteFactory_Release(factory2);
2359 IDWriteFontFileLoader_Release(loader);
2361 ret = TRUE;
2362 i = 0;
2363 hr = IDWriteFontCollection_FindFamilyName(collection, blahW, &i, &ret);
2364 ok(hr == S_OK, "got 0x%08x\n", hr);
2365 ok(!ret, "got %d\n", ret);
2366 ok(i == (UINT32)-1, "got %u\n", i);
2368 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection1, (void**)&collection1);
2369 if (hr == S_OK) {
2370 IDWriteFontSet *fontset, *fontset2;
2371 IDWriteFontFamily1 *family1;
2372 IDWriteFactory3 *factory3;
2374 hr = IDWriteFontCollection1_QueryInterface(collection1, &IID_IDWriteFontCollection, (void**)&coll2);
2375 ok(hr == S_OK, "got 0x%08x\n", hr);
2376 ok(coll2 == collection, "got %p, %p\n", collection, coll2);
2377 IDWriteFontCollection_Release(coll2);
2379 family1 = (void*)0xdeadbeef;
2380 hr = IDWriteFontCollection1_GetFontFamily(collection1, ~0u, &family1);
2381 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2382 ok(family1 == NULL, "got %p\n", family1);
2384 hr = IDWriteFontCollection1_GetFontFamily(collection1, 0, &family1);
2385 ok(hr == S_OK, "got 0x%08x\n", hr);
2386 IDWriteFontFamily1_Release(family1);
2388 /* system fontset */
2389 EXPECT_REF(collection1, 2);
2390 EXPECT_REF(factory, 2);
2391 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset);
2392 todo_wine
2393 ok(hr == S_OK, "Failed to get fontset, hr %#x.\n", hr);
2394 if (hr == S_OK) {
2395 EXPECT_REF(collection1, 2);
2396 EXPECT_REF(factory, 2);
2397 EXPECT_REF(fontset, 1);
2399 hr = IDWriteFontCollection1_GetFontSet(collection1, &fontset2);
2400 ok(hr == S_OK, "Failed to get fontset, hr %#x.\n", hr);
2401 ok(fontset != fontset2, "Expected new fontset instance.\n");
2402 EXPECT_REF(fontset2, 1);
2403 IDWriteFontSet_Release(fontset2);
2405 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3);
2406 ok(hr == S_OK, "Failed to get IDWriteFactory3 interface, hr %#x.\n", hr);
2408 EXPECT_REF(factory, 3);
2409 hr = IDWriteFactory3_GetSystemFontSet(factory3, &fontset2);
2410 ok(hr == S_OK, "Failed to get system font set, hr %#x.\n", hr);
2411 ok(fontset != fontset2, "Expected new fontset instance.\n");
2412 EXPECT_REF(fontset2, 1);
2413 EXPECT_REF(factory, 4);
2415 IDWriteFontSet_Release(fontset2);
2416 IDWriteFontSet_Release(fontset);
2418 IDWriteFactory3_Release(factory3);
2420 IDWriteFontCollection1_Release(collection1);
2422 else
2423 win_skip("IDWriteFontCollection1 is not supported.\n");
2425 ref = IDWriteFontCollection_Release(collection);
2426 ok(ref == 0, "collection not released, %u\n", ref);
2427 ref = IDWriteFactory_Release(factory);
2428 ok(ref == 0, "factory not released, %u\n", ref);
2431 static void get_logfont_from_font(IDWriteFont *font, LOGFONTW *logfont)
2433 void *os2_context, *head_context;
2434 IDWriteLocalizedStrings *names;
2435 DWRITE_FONT_SIMULATIONS sim;
2436 IDWriteFontFace *fontface;
2437 const TT_OS2_V2 *tt_os2;
2438 DWRITE_FONT_STYLE style;
2439 const TT_HEAD *tt_head;
2440 LONG weight;
2441 UINT32 size;
2442 BOOL exists;
2443 HRESULT hr;
2445 /* These are rendering time properties. */
2446 logfont->lfHeight = 0;
2447 logfont->lfWidth = 0;
2448 logfont->lfEscapement = 0;
2449 logfont->lfOrientation = 0;
2450 logfont->lfUnderline = 0;
2451 logfont->lfStrikeOut = 0;
2453 logfont->lfWeight = 0;
2454 logfont->lfItalic = 0;
2456 hr = IDWriteFont_CreateFontFace(font, &fontface);
2457 ok(hr == S_OK, "Failed to create font face, %#x\n", hr);
2459 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void **)&tt_os2, &size,
2460 &os2_context, &exists);
2461 ok(hr == S_OK, "Failed to get OS/2 table, %#x\n", hr);
2463 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void **)&tt_head, &size,
2464 &head_context, &exists);
2465 ok(hr == S_OK, "Failed to get head table, %#x\n", hr);
2467 sim = IDWriteFont_GetSimulations(font);
2469 /* lfWeight */
2470 weight = FW_REGULAR;
2471 if (tt_os2) {
2472 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
2474 if (usWeightClass >= 1 && usWeightClass <= 9)
2475 usWeightClass *= 100;
2477 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
2478 weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
2479 else if (usWeightClass > 0)
2480 weight = usWeightClass;
2482 else if (tt_head) {
2483 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2484 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
2485 weight = DWRITE_FONT_WEIGHT_BOLD;
2487 if (sim & DWRITE_FONT_SIMULATIONS_BOLD)
2488 weight += (FW_BOLD - FW_REGULAR) / 2 + 1;
2489 logfont->lfWeight = weight;
2491 /* lfItalic */
2492 if (IDWriteFont_GetSimulations(font) & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2493 logfont->lfItalic = 1;
2495 style = IDWriteFont_GetStyle(font);
2496 if (!logfont->lfItalic && ((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE))) {
2497 if (tt_os2) {
2498 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
2499 logfont->lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
2501 else if (tt_head) {
2502 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2503 logfont->lfItalic = !!(macStyle & TT_HEAD_MACSTYLE_ITALIC);
2507 /* lfFaceName */
2508 exists = FALSE;
2509 logfont->lfFaceName[0] = 0;
2510 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &exists);
2511 if (SUCCEEDED(hr)) {
2512 if (exists) {
2513 static const WCHAR enusW[] = {'e','n','-','u','s',0};
2514 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
2515 UINT32 index;
2517 /* Fallback to en-us if there's no string for user locale. */
2518 exists = FALSE;
2519 if (GetSystemDefaultLocaleName(localeW, sizeof(localeW)/sizeof(WCHAR)))
2520 IDWriteLocalizedStrings_FindLocaleName(names, localeW, &index, &exists);
2522 if (!exists)
2523 IDWriteLocalizedStrings_FindLocaleName(names, enusW, &index, &exists);
2525 if (exists)
2526 IDWriteLocalizedStrings_GetString(names, index, logfont->lfFaceName, sizeof(logfont->lfFaceName)/sizeof(WCHAR));
2529 IDWriteLocalizedStrings_Release(names);
2532 if (tt_os2)
2533 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2534 if (tt_head)
2535 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2536 IDWriteFontFace_Release(fontface);
2539 static void test_ConvertFontFaceToLOGFONT(void)
2541 IDWriteFontCollection *collection;
2542 IDWriteGdiInterop *interop;
2543 IDWriteFontFace *fontface;
2544 IDWriteFactory *factory;
2545 LOGFONTW logfont;
2546 UINT32 count, i;
2547 HRESULT hr;
2548 ULONG ref;
2550 factory = create_factory();
2552 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2553 ok(hr == S_OK, "got 0x%08x\n", hr);
2555 if (0) /* crashes on native */
2557 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, NULL);
2558 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, NULL);
2560 memset(&logfont, 0xcc, sizeof(logfont));
2561 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, &logfont);
2562 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2563 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2565 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2566 ok(hr == S_OK, "got 0x%08x\n", hr);
2568 count = IDWriteFontCollection_GetFontFamilyCount(collection);
2569 for (i = 0; i < count; i++) {
2570 WCHAR nameW[128], familynameW[64], facenameW[64];
2571 IDWriteLocalizedStrings *names;
2572 DWRITE_FONT_SIMULATIONS sim;
2573 IDWriteFontFamily *family;
2574 UINT32 font_count, j;
2575 IDWriteFont *font;
2576 LOGFONTW lf;
2578 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2579 ok(hr == S_OK, "got 0x%08x\n", hr);
2581 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2582 ok(hr == S_OK, "got 0x%08x\n", hr);
2584 get_enus_string(names, familynameW, sizeof(familynameW)/sizeof(familynameW[0]));
2585 IDWriteLocalizedStrings_Release(names);
2587 font_count = IDWriteFontFamily_GetFontCount(family);
2589 for (j = 0; j < font_count; j++) {
2590 static const WCHAR spaceW[] = {' ', 0};
2591 IDWriteFontFace *fontface;
2593 hr = IDWriteFontFamily_GetFont(family, j, &font);
2594 ok(hr == S_OK, "got 0x%08x\n", hr);
2596 hr = IDWriteFont_GetFaceNames(font, &names);
2597 ok(hr == S_OK, "got 0x%08x\n", hr);
2599 get_enus_string(names, facenameW, sizeof(facenameW)/sizeof(facenameW[0]));
2600 IDWriteLocalizedStrings_Release(names);
2602 lstrcpyW(nameW, familynameW);
2603 lstrcatW(nameW, spaceW);
2604 lstrcatW(nameW, facenameW);
2606 hr = IDWriteFont_CreateFontFace(font, &fontface);
2607 ok(hr == S_OK, "got 0x%08x\n", hr);
2609 memset(&logfont, 0xcc, sizeof(logfont));
2610 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, &logfont);
2611 ok(hr == S_OK, "got 0x%08x\n", hr);
2613 sim = IDWriteFontFace_GetSimulations(fontface);
2614 get_logfont_from_font(font, &lf);
2616 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
2617 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
2618 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
2619 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
2620 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
2621 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
2622 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
2624 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
2625 logfont.lfOutPrecision);
2626 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
2627 logfont.lfClipPrecision);
2628 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
2629 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
2630 logfont.lfPitchAndFamily);
2632 IDWriteFontFace_Release(fontface);
2633 IDWriteFont_Release(font);
2636 IDWriteFontFamily_Release(family);
2639 IDWriteFontCollection_Release(collection);
2640 IDWriteGdiInterop_Release(interop);
2641 ref = IDWriteFactory_Release(factory);
2642 ok(ref == 0, "factory not released, %u\n", ref);
2645 static HRESULT WINAPI fontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2647 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
2649 *obj = iface;
2650 IDWriteFontFileEnumerator_AddRef(iface);
2651 return S_OK;
2653 return E_NOINTERFACE;
2656 static ULONG WINAPI fontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2658 return 2;
2661 static ULONG WINAPI fontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2663 return 1;
2666 static HRESULT WINAPI fontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2668 *file = NULL;
2669 return E_FAIL;
2672 static HRESULT WINAPI fontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2674 *current = FALSE;
2675 return S_OK;
2678 static const struct IDWriteFontFileEnumeratorVtbl dwritefontfileenumeratorvtbl =
2680 fontfileenumerator_QueryInterface,
2681 fontfileenumerator_AddRef,
2682 fontfileenumerator_Release,
2683 fontfileenumerator_MoveNext,
2684 fontfileenumerator_GetCurrentFontFile,
2687 struct collection_loader
2689 IDWriteFontCollectionLoader IDWriteFontCollectionLoader_iface;
2690 LONG ref;
2693 static inline struct collection_loader *impl_from_IDWriteFontCollectionLoader(IDWriteFontCollectionLoader *iface)
2695 return CONTAINING_RECORD(iface, struct collection_loader, IDWriteFontCollectionLoader_iface);
2698 static HRESULT WINAPI fontcollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
2700 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2702 if (IsEqualIID(&IID_IDWriteFontCollectionLoader, riid) ||
2703 IsEqualIID(&IID_IUnknown, riid))
2705 *obj = &loader->IDWriteFontCollectionLoader_iface;
2706 IDWriteFontCollectionLoader_AddRef(iface);
2707 return S_OK;
2710 *obj = NULL;
2711 return E_NOINTERFACE;
2714 static ULONG WINAPI fontcollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
2716 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2717 return InterlockedIncrement(&loader->ref);
2720 static ULONG WINAPI fontcollectionloader_Release(IDWriteFontCollectionLoader *iface)
2722 struct collection_loader *loader = impl_from_IDWriteFontCollectionLoader(iface);
2723 ULONG ref = InterlockedDecrement(&loader->ref);
2725 if (!ref)
2726 heap_free(loader);
2728 return ref;
2731 static HRESULT WINAPI fontcollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory, const void *key,
2732 UINT32 key_size, IDWriteFontFileEnumerator **ret)
2734 static IDWriteFontFileEnumerator enumerator = { &dwritefontfileenumeratorvtbl };
2735 *ret = &enumerator;
2736 return S_OK;
2739 static const struct IDWriteFontCollectionLoaderVtbl dwritefontcollectionloadervtbl = {
2740 fontcollectionloader_QueryInterface,
2741 fontcollectionloader_AddRef,
2742 fontcollectionloader_Release,
2743 fontcollectionloader_CreateEnumeratorFromKey
2746 static IDWriteFontCollectionLoader *create_collection_loader(void)
2748 struct collection_loader *loader = heap_alloc(sizeof(*loader));
2750 loader->IDWriteFontCollectionLoader_iface.lpVtbl = &dwritefontcollectionloadervtbl;
2751 loader->ref = 1;
2753 return &loader->IDWriteFontCollectionLoader_iface;
2756 static void test_CustomFontCollection(void)
2758 static const WCHAR fontnameW[] = {'w','i','n','e','_','t','e','s','t',0};
2759 IDWriteFontCollectionLoader *loader, *loader2, *loader3;
2760 IDWriteFontCollection *font_collection = NULL;
2761 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
2762 struct test_fontcollectionloader resource_collection = { { &resourcecollectionloadervtbl }, &rloader };
2763 IDWriteFontFamily *family, *family2, *family3;
2764 IDWriteFontFace *idfontface, *idfontface2;
2765 IDWriteFontFile *fontfile, *fontfile2;
2766 IDWriteLocalizedStrings *string;
2767 IDWriteFont *idfont, *idfont2;
2768 IDWriteFactory *factory;
2769 UINT32 index, count;
2770 BOOL exists;
2771 HRESULT hr;
2772 HRSRC font;
2773 ULONG ref;
2775 factory = create_factory();
2777 loader = create_collection_loader();
2778 loader2 = create_collection_loader();
2779 loader3 = create_collection_loader();
2781 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, NULL);
2782 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2784 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, NULL);
2785 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2787 EXPECT_REF(loader, 1);
2788 EXPECT_REF(loader2, 1);
2790 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
2791 ok(hr == S_OK, "got 0x%08x\n", hr);
2792 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader2);
2793 ok(hr == S_OK, "got 0x%08x\n", hr);
2794 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, loader);
2795 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2797 EXPECT_REF(loader, 2);
2798 EXPECT_REF(loader2, 2);
2800 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
2801 ok(hr == S_OK, "got 0x%08x\n", hr);
2802 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
2803 ok(hr == S_OK, "got 0x%08x\n", hr);
2805 /* Loader wasn't registered. */
2806 font_collection = (void*)0xdeadbeef;
2807 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader3, "Billy", 6, &font_collection);
2808 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2809 ok(font_collection == NULL, "got %p\n", font_collection);
2811 EXPECT_REF(factory, 1);
2812 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader, "Billy", 6, &font_collection);
2813 ok(hr == S_OK, "got 0x%08x\n", hr);
2814 todo_wine
2815 EXPECT_REF(factory, 1);
2816 EXPECT_REF(loader, 2);
2817 IDWriteFontCollection_Release(font_collection);
2819 hr = IDWriteFactory_CreateCustomFontCollection(factory, loader2, "Billy", 6, &font_collection);
2820 ok(hr == S_OK, "got 0x%08x\n", hr);
2821 IDWriteFontCollection_Release(font_collection);
2823 font_collection = (void*)0xdeadbeef;
2824 hr = IDWriteFactory_CreateCustomFontCollection(factory, (IDWriteFontCollectionLoader*)0xdeadbeef, "Billy", 6, &font_collection);
2825 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2826 ok(font_collection == NULL, "got %p\n", font_collection);
2828 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
2829 ok(font != NULL, "Failed to find font resource\n");
2831 hr = IDWriteFactory_CreateCustomFontCollection(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface,
2832 &font, sizeof(HRSRC), &font_collection);
2833 ok(hr == S_OK, "got 0x%08x\n",hr);
2834 EXPECT_REF(font_collection, 1);
2836 index = 1;
2837 exists = FALSE;
2838 hr = IDWriteFontCollection_FindFamilyName(font_collection, fontnameW, &index, &exists);
2839 ok(hr == S_OK, "got 0x%08x\n", hr);
2840 ok(index == 0, "got index %i\n", index);
2841 ok(exists, "got exists %i\n", exists);
2843 count = IDWriteFontCollection_GetFontFamilyCount(font_collection);
2844 ok(count == 1, "got %u\n", count);
2846 family = NULL;
2847 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family);
2848 ok(hr == S_OK, "got 0x%08x\n", hr);
2849 EXPECT_REF(family, 1);
2851 family2 = NULL;
2852 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family2);
2853 ok(hr == S_OK, "got 0x%08x\n", hr);
2854 EXPECT_REF(family2, 1);
2855 ok(family != family2, "got %p, %p\n", family, family2);
2857 hr = IDWriteFontFamily_GetFont(family, 0, &idfont);
2858 ok(hr == S_OK, "got 0x%08x\n", hr);
2859 EXPECT_REF(idfont, 1);
2860 EXPECT_REF(family, 2);
2861 hr = IDWriteFontFamily_GetFont(family, 0, &idfont2);
2862 ok(hr == S_OK, "got 0x%08x\n", hr);
2863 EXPECT_REF(idfont2, 1);
2864 EXPECT_REF(family, 3);
2865 ok(idfont != idfont2, "got %p, %p\n", idfont, idfont2);
2866 IDWriteFont_Release(idfont2);
2868 hr = IDWriteFont_GetInformationalStrings(idfont, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &string, &exists);
2869 ok(hr == S_OK, "got 0x%08x\n", hr);
2870 ok(exists, "got %d\n", exists);
2871 EXPECT_REF(string, 1);
2872 IDWriteLocalizedStrings_Release(string);
2874 family3 = NULL;
2875 hr = IDWriteFont_GetFontFamily(idfont, &family3);
2876 ok(hr == S_OK, "got 0x%08x\n", hr);
2877 EXPECT_REF(family, 3);
2878 ok(family == family3, "got %p, %p\n", family, family3);
2879 IDWriteFontFamily_Release(family3);
2881 idfontface = NULL;
2882 hr = IDWriteFont_CreateFontFace(idfont, &idfontface);
2883 ok(hr == S_OK, "got 0x%08x\n", hr);
2884 EXPECT_REF(idfont, 1);
2886 idfont2 = NULL;
2887 hr = IDWriteFontFamily_GetFont(family2, 0, &idfont2);
2888 ok(hr == S_OK, "got 0x%08x\n", hr);
2889 EXPECT_REF(idfont2, 1);
2890 EXPECT_REF(idfont, 1);
2891 ok(idfont2 != idfont, "Font instances should not match\n");
2893 idfontface2 = NULL;
2894 hr = IDWriteFont_CreateFontFace(idfont2, &idfontface2);
2895 ok(hr == S_OK, "got 0x%08x\n", hr);
2896 ok(idfontface2 == idfontface, "fontfaces should match\n");
2898 index = 1;
2899 fontfile = NULL;
2900 hr = IDWriteFontFace_GetFiles(idfontface, &index, &fontfile);
2901 ok(hr == S_OK, "got 0x%08x\n", hr);
2903 index = 1;
2904 fontfile2 = NULL;
2905 hr = IDWriteFontFace_GetFiles(idfontface2, &index, &fontfile2);
2906 ok(hr == S_OK, "got 0x%08x\n", hr);
2907 ok(fontfile == fontfile2, "fontfiles should match\n");
2909 IDWriteFont_Release(idfont);
2910 IDWriteFont_Release(idfont2);
2911 IDWriteFontFile_Release(fontfile);
2912 IDWriteFontFile_Release(fontfile2);
2913 IDWriteFontFace_Release(idfontface);
2914 IDWriteFontFace_Release(idfontface2);
2915 IDWriteFontFamily_Release(family2);
2916 IDWriteFontFamily_Release(family);
2917 IDWriteFontCollection_Release(font_collection);
2919 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
2920 ok(hr == S_OK, "got 0x%08x\n", hr);
2921 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader);
2922 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2923 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, loader2);
2924 ok(hr == S_OK, "got 0x%08x\n", hr);
2925 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
2926 ok(hr == S_OK, "got 0x%08x\n", hr);
2927 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
2928 ok(hr == S_OK, "got 0x%08x\n", hr);
2930 IDWriteFontCollectionLoader_Release(loader);
2931 IDWriteFontCollectionLoader_Release(loader2);
2932 IDWriteFontCollectionLoader_Release(loader3);
2934 ref = IDWriteFactory_Release(factory);
2935 ok(ref == 0, "factory not released, %u\n", ref);
2938 static HRESULT WINAPI fontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
2940 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
2942 *obj = iface;
2943 IDWriteFontFileLoader_AddRef(iface);
2944 return S_OK;
2947 *obj = NULL;
2948 return E_NOINTERFACE;
2951 static ULONG WINAPI fontfileloader_AddRef(IDWriteFontFileLoader *iface)
2953 return 2;
2956 static ULONG WINAPI fontfileloader_Release(IDWriteFontFileLoader *iface)
2958 return 1;
2961 static HRESULT WINAPI fontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
2962 IDWriteFontFileStream **stream)
2964 return 0x8faecafe;
2967 static const struct IDWriteFontFileLoaderVtbl dwritefontfileloadervtbl = {
2968 fontfileloader_QueryInterface,
2969 fontfileloader_AddRef,
2970 fontfileloader_Release,
2971 fontfileloader_CreateStreamFromKey
2974 static void test_CreateCustomFontFileReference(void)
2976 IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl };
2977 IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl };
2978 IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl };
2979 IDWriteFactory *factory, *factory2;
2980 IDWriteFontFileLoader *loader;
2981 IDWriteFontFile *file, *file2;
2982 BOOL support;
2983 DWRITE_FONT_FILE_TYPE file_type;
2984 DWRITE_FONT_FACE_TYPE face_type;
2985 UINT32 count;
2986 IDWriteFontFace *face, *face2;
2987 HRESULT hr;
2988 HRSRC fontrsrc;
2989 UINT32 codePoints[1] = {0xa8};
2990 UINT16 indices[2];
2991 const void *key;
2992 UINT32 key_size;
2993 WCHAR *path;
2994 ULONG ref;
2996 path = create_testfontfile(test_fontfile);
2998 factory = create_factory();
2999 factory2 = create_factory();
3001 if (0) { /* crashes on win10 */
3002 hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
3003 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3005 /* local loader is accepted too */
3006 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3007 ok(hr == S_OK, "got 0x%08x\n", hr);
3009 hr = IDWriteFontFile_GetLoader(file, &loader);
3010 ok(hr == S_OK, "got 0x%08x\n", hr);
3012 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
3013 ok(hr == S_OK, "got 0x%08x\n", hr);
3015 hr = IDWriteFactory_CreateCustomFontFileReference(factory, key, key_size, loader, &file2);
3016 ok(hr == S_OK, "got 0x%08x\n", hr);
3018 IDWriteFontFile_Release(file2);
3019 IDWriteFontFile_Release(file);
3020 IDWriteFontFileLoader_Release(loader);
3022 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3023 ok(hr == S_OK, "got 0x%08x\n", hr);
3024 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader2);
3025 ok(hr == S_OK, "got 0x%08x\n", hr);
3026 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
3027 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
3028 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3029 ok(hr == S_OK, "got 0x%08x\n", hr);
3031 file = NULL;
3032 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3033 ok(hr == S_OK, "got 0x%08x\n", hr);
3034 IDWriteFontFile_Release(file);
3036 file = (void*)0xdeadbeef;
3037 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader3, &file);
3038 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3039 ok(file == NULL, "got %p\n", file);
3041 file = (void*)0xdeadbeef;
3042 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, NULL, &file);
3043 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3044 ok(file == NULL, "got %p\n", file);
3046 file = NULL;
3047 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
3048 ok(hr == S_OK, "got 0x%08x\n", hr);
3050 file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
3051 face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
3052 support = TRUE;
3053 count = 1;
3054 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3055 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
3056 ok(support == FALSE, "got %i\n", support);
3057 ok(file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN, "got %i\n", file_type);
3058 ok(face_type == DWRITE_FONT_FACE_TYPE_UNKNOWN, "got %i\n", face_type);
3059 ok(count == 0, "got %i\n", count);
3061 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0, &face);
3062 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
3063 IDWriteFontFile_Release(file);
3065 fontrsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3066 ok(fontrsrc != NULL, "Failed to find font resource\n");
3068 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file);
3069 ok(hr == S_OK, "got 0x%08x\n", hr);
3071 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3072 face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
3073 support = FALSE;
3074 count = 0;
3075 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
3076 ok(hr == S_OK, "got 0x%08x\n", hr);
3077 ok(support == TRUE, "got %i\n", support);
3078 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
3079 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
3080 ok(count == 1, "got %i\n", count);
3082 /* invalid index */
3083 face = (void*)0xdeadbeef;
3084 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 1, DWRITE_FONT_SIMULATIONS_NONE, &face);
3085 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3086 ok(face == NULL, "got %p\n", face);
3088 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
3089 ok(hr == S_OK, "got 0x%08x\n", hr);
3091 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3092 ok(hr == S_OK, "got 0x%08x\n", hr);
3093 /* fontface instances are reused starting with win7 */
3094 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3095 IDWriteFontFace_Release(face2);
3097 /* file was created with different factory */
3098 face2 = NULL;
3099 hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3100 todo_wine
3101 ok(hr == S_OK, "got 0x%08x\n", hr);
3102 if (face2) {
3103 IDWriteFontFace_Release(face2);
3105 file2 = NULL;
3106 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2);
3107 ok(hr == S_OK, "got 0x%08x\n", hr);
3108 ok(file != file2, "got %p, %p\n", file, file2);
3110 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
3111 ok(hr == S_OK, "got 0x%08x\n", hr);
3112 /* fontface instances are reused starting with win7 */
3113 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
3114 IDWriteFontFace_Release(face2);
3115 IDWriteFontFile_Release(file2);
3117 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, NULL);
3118 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3120 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, NULL);
3121 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3123 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, indices);
3124 ok(hr == S_OK, "got 0x%08x\n", hr);
3126 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, indices);
3127 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3129 indices[0] = indices[1] = 11;
3130 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, indices);
3131 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3132 ok(indices[0] == 0, "got index %i\n", indices[0]);
3133 ok(indices[1] == 11, "got index %i\n", indices[1]);
3135 if (0) /* crashes on native */
3136 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, NULL);
3138 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 1, indices);
3139 ok(hr == S_OK, "got 0x%08x\n", hr);
3140 ok(indices[0] == 7, "Unexpected glyph index, %u.\n", indices[0]);
3141 IDWriteFontFace_Release(face);
3142 IDWriteFontFile_Release(file);
3144 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3145 ok(hr == S_OK, "got 0x%08x\n", hr);
3146 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
3147 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3148 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader2);
3149 ok(hr == S_OK, "got 0x%08x\n", hr);
3150 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3151 ok(hr == S_OK, "got 0x%08x\n", hr);
3153 ref = IDWriteFactory_Release(factory2);
3154 ok(ref == 0, "factory not released, %u\n", ref);
3155 ref = IDWriteFactory_Release(factory);
3156 ok(ref == 0, "factory not released, %u\n", ref);
3157 DELETE_FONTFILE(path);
3160 static void test_CreateFontFileReference(void)
3162 HRESULT hr;
3163 IDWriteFontFile *ffile = NULL;
3164 BOOL support;
3165 DWRITE_FONT_FILE_TYPE type;
3166 DWRITE_FONT_FACE_TYPE face;
3167 UINT32 count;
3168 IDWriteFontFace *fface = NULL;
3169 IDWriteFactory *factory;
3170 WCHAR *path;
3171 ULONG ref;
3173 path = create_testfontfile(test_fontfile);
3174 factory = create_factory();
3176 ffile = (void*)0xdeadbeef;
3177 hr = IDWriteFactory_CreateFontFileReference(factory, NULL, NULL, &ffile);
3178 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
3179 ok(ffile == NULL, "got %p\n", ffile);
3181 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &ffile);
3182 ok(hr == S_OK, "got 0x%08x\n",hr);
3184 support = FALSE;
3185 type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
3186 face = DWRITE_FONT_FACE_TYPE_CFF;
3187 count = 0;
3188 hr = IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count);
3189 ok(hr == S_OK, "got 0x%08x\n", hr);
3190 ok(support == TRUE, "got %i\n", support);
3191 ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type);
3192 ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face);
3193 ok(count == 1, "got %i\n", count);
3195 hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface);
3196 ok(hr == S_OK, "got 0x%08x\n", hr);
3198 IDWriteFontFace_Release(fface);
3199 IDWriteFontFile_Release(ffile);
3200 ref = IDWriteFactory_Release(factory);
3201 ok(ref == 0, "factory not released, %u\n", ref);
3203 DELETE_FONTFILE(path);
3206 static void test_shared_isolated(void)
3208 IDWriteFactory *isolated, *isolated2;
3209 IDWriteFactory *shared, *shared2;
3210 HRESULT hr;
3211 ULONG ref;
3213 /* invalid type */
3214 shared = NULL;
3215 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&shared);
3216 ok(hr == S_OK, "got 0x%08x\n", hr);
3217 ok(shared != NULL, "got %p\n", shared);
3218 IDWriteFactory_Release(shared);
3220 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared);
3221 ok(hr == S_OK, "got 0x%08x\n", hr);
3223 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3224 ok(hr == S_OK, "got 0x%08x\n", hr);
3225 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3226 IDWriteFactory_Release(shared2);
3228 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IUnknown, (IUnknown**)&shared2);
3229 ok(hr == S_OK, "got 0x%08x\n", hr);
3230 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3232 IDWriteFactory_Release(shared);
3233 IDWriteFactory_Release(shared2);
3235 /* we got 2 references, released 2 - still same pointer is returned */
3236 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
3237 ok(hr == S_OK, "got 0x%08x\n", hr);
3238 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
3239 IDWriteFactory_Release(shared2);
3241 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated);
3242 ok(hr == S_OK, "got 0x%08x\n", hr);
3244 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3245 ok(hr == S_OK, "got 0x%08x\n", hr);
3246 ok(isolated != isolated2, "got %p, and %p\n", isolated, isolated2);
3247 IDWriteFactory_Release(isolated2);
3249 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IUnknown, (IUnknown**)&isolated2);
3250 ok(hr == S_OK, "got 0x%08x\n", hr);
3251 IDWriteFactory_Release(isolated2);
3253 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&isolated2);
3254 ok(hr == S_OK, "got 0x%08x\n", hr);
3255 ok(shared != isolated2, "got %p, and %p\n", shared, isolated2);
3257 ref = IDWriteFactory_Release(isolated);
3258 ok(ref == 0, "factory not released, %u\n", ref);
3259 ref = IDWriteFactory_Release(isolated2);
3260 ok(ref == 0, "factory not released, %u\n", ref);
3263 static void test_GetUnicodeRanges(void)
3265 DWRITE_UNICODE_RANGE *ranges, r;
3266 IDWriteFontFile *ffile = NULL;
3267 IDWriteFontFace1 *fontface1;
3268 IDWriteFontFace *fontface;
3269 IDWriteFactory *factory;
3270 UINT32 count;
3271 HRESULT hr;
3272 HRSRC font;
3273 ULONG ref;
3275 factory = create_factory();
3277 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
3278 ok(hr == S_OK, "got 0x%08x\n", hr);
3280 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
3281 ok(font != NULL, "Failed to find font resource\n");
3283 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile);
3284 ok(hr == S_OK, "got 0x%08x\n", hr);
3286 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3287 ok(hr == S_OK, "got 0x%08x\n", hr);
3288 IDWriteFontFile_Release(ffile);
3290 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3291 IDWriteFontFace_Release(fontface);
3292 if (hr != S_OK) {
3293 win_skip("GetUnicodeRanges() is not supported.\n");
3294 IDWriteFactory_Release(factory);
3295 return;
3298 count = 0;
3299 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
3300 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3301 ok(count > 0, "got %u\n", count);
3303 count = 1;
3304 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count);
3305 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3306 ok(count == 0, "got %u\n", count);
3308 count = 0;
3309 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count);
3310 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3311 ok(count > 1, "got %u\n", count);
3313 ranges = heap_alloc(count*sizeof(DWRITE_UNICODE_RANGE));
3314 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
3315 ok(hr == S_OK, "got 0x%08x\n", hr);
3317 ranges[0].first = ranges[0].last = 0;
3318 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count);
3319 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3320 ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last);
3322 heap_free(ranges);
3324 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3325 ok(hr == S_OK, "got 0x%08x\n", hr);
3327 IDWriteFontFace1_Release(fontface1);
3328 ref = IDWriteFactory_Release(factory);
3329 ok(ref == 0, "factory not released, %u\n", ref);
3332 static void test_GetFontFromFontFace(void)
3334 IDWriteFontFace *fontface, *fontface2;
3335 IDWriteFontCollection *collection;
3336 IDWriteFont *font, *font2, *font3;
3337 IDWriteFontFamily *family;
3338 IDWriteFactory *factory;
3339 IDWriteFontFile *file;
3340 WCHAR *path;
3341 HRESULT hr;
3342 ULONG ref;
3344 factory = create_factory();
3346 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3347 ok(hr == S_OK, "got 0x%08x\n", hr);
3349 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3350 ok(hr == S_OK, "got 0x%08x\n", hr);
3352 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3353 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3354 ok(hr == S_OK, "got 0x%08x\n", hr);
3356 hr = IDWriteFont_CreateFontFace(font, &fontface);
3357 ok(hr == S_OK, "got 0x%08x\n", hr);
3359 font2 = NULL;
3360 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
3361 ok(hr == S_OK, "got 0x%08x\n", hr);
3362 ok(font2 != font, "got %p, %p\n", font2, font);
3364 font3 = NULL;
3365 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3366 ok(hr == S_OK, "got 0x%08x\n", hr);
3367 ok(font3 != font && font3 != font2, "got %p, %p, %p\n", font3, font2, font);
3369 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
3370 ok(hr == S_OK, "got 0x%08x\n", hr);
3371 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3372 IDWriteFontFace_Release(fontface2);
3374 hr = IDWriteFont_CreateFontFace(font3, &fontface2);
3375 ok(hr == S_OK, "got 0x%08x\n", hr);
3376 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3377 IDWriteFontFace_Release(fontface2);
3378 IDWriteFontFace_Release(fontface);
3379 IDWriteFont_Release(font3);
3380 IDWriteFactory_Release(factory);
3382 /* fontface that wasn't created from this collection */
3383 factory = create_factory();
3384 path = create_testfontfile(test_fontfile);
3386 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3387 ok(hr == S_OK, "got 0x%08x\n",hr);
3389 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3390 ok(hr == S_OK, "got 0x%08x\n", hr);
3391 IDWriteFontFile_Release(file);
3393 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3394 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
3395 ok(font3 == NULL, "got %p\n", font3);
3396 IDWriteFontFace_Release(fontface);
3398 IDWriteFont_Release(font);
3399 IDWriteFont_Release(font2);
3400 IDWriteFontFamily_Release(family);
3401 IDWriteFontCollection_Release(collection);
3402 ref = IDWriteFactory_Release(factory);
3403 ok(ref == 0, "factory not released, %u\n", ref);
3404 DELETE_FONTFILE(path);
3407 static void test_GetFirstMatchingFont(void)
3409 DWRITE_FONT_SIMULATIONS simulations;
3410 IDWriteFontCollection *collection;
3411 IDWriteFontFamily *family;
3412 IDWriteFont *font, *font2;
3413 IDWriteFactory *factory;
3414 HRESULT hr;
3415 ULONG ref;
3417 factory = create_factory();
3419 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3420 ok(hr == S_OK, "got 0x%08x\n", hr);
3422 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3423 ok(hr == S_OK, "got 0x%08x\n", hr);
3425 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3426 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3427 ok(hr == S_OK, "got 0x%08x\n", hr);
3429 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3430 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
3431 ok(hr == S_OK, "got 0x%08x\n", hr);
3432 ok(font != font2, "got %p, %p\n", font, font2);
3433 IDWriteFont_Release(font);
3434 IDWriteFont_Release(font2);
3436 /* out-of-range font props are allowed */
3437 hr = IDWriteFontFamily_GetFirstMatchingFont(family, 1000, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3438 ok(hr == S_OK, "got 0x%08x\n", hr);
3439 IDWriteFont_Release(font);
3441 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, 10, DWRITE_FONT_STYLE_NORMAL, &font);
3442 ok(hr == S_OK, "got 0x%08x\n", hr);
3443 IDWriteFont_Release(font);
3445 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3446 10, &font);
3447 ok(hr == S_OK, "got 0x%08x\n", hr);
3448 IDWriteFont_Release(font);
3450 IDWriteFontFamily_Release(family);
3452 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
3453 simulations = IDWriteFont_GetSimulations(font);
3454 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "%d\n", simulations);
3455 IDWriteFont_Release(font);
3457 IDWriteFontCollection_Release(collection);
3458 ref = IDWriteFactory_Release(factory);
3459 ok(ref == 0, "factory not released, %u\n", ref);
3462 static void test_GetMatchingFonts(void)
3464 IDWriteFontCollection *collection;
3465 IDWriteFontFamily *family;
3466 IDWriteFactory *factory;
3467 IDWriteFontList *fontlist, *fontlist2;
3468 IDWriteFontList1 *fontlist1;
3469 HRESULT hr;
3470 ULONG ref;
3472 factory = create_factory();
3474 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3475 ok(hr == S_OK, "got 0x%08x\n", hr);
3477 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3478 ok(hr == S_OK, "got 0x%08x\n", hr);
3480 /* out-of-range font props are allowed */
3481 hr = IDWriteFontFamily_GetMatchingFonts(family, 1000, DWRITE_FONT_STRETCH_NORMAL,
3482 DWRITE_FONT_STYLE_NORMAL, &fontlist);
3483 ok(hr == S_OK, "got 0x%08x\n", hr);
3484 IDWriteFontList_Release(fontlist);
3486 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, 10,
3487 DWRITE_FONT_STYLE_NORMAL, &fontlist);
3488 ok(hr == S_OK, "got 0x%08x\n", hr);
3489 IDWriteFontList_Release(fontlist);
3491 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3492 10, &fontlist);
3493 ok(hr == S_OK, "got 0x%08x\n", hr);
3494 IDWriteFontList_Release(fontlist);
3496 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
3497 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
3498 ok(hr == S_OK, "got 0x%08x\n", hr);
3500 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
3501 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
3502 ok(hr == S_OK, "got 0x%08x\n", hr);
3503 ok(fontlist != fontlist2, "got %p, %p\n", fontlist, fontlist2);
3504 IDWriteFontList_Release(fontlist2);
3506 hr = IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList1, (void**)&fontlist1);
3507 if (hr == S_OK) {
3508 IDWriteFontFaceReference *ref, *ref1;
3509 IDWriteFont3 *font;
3510 UINT32 count;
3512 count = IDWriteFontList1_GetFontCount(fontlist1);
3513 ok(count > 0, "got %u\n", count);
3515 font = (void*)0xdeadbeef;
3516 hr = IDWriteFontList1_GetFont(fontlist1, ~0u, &font);
3517 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3518 ok(font == NULL, "got %p\n", font);
3520 font = (void*)0xdeadbeef;
3521 hr = IDWriteFontList1_GetFont(fontlist1, count, &font);
3522 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3523 ok(font == NULL, "got %p\n", font);
3525 hr = IDWriteFontList1_GetFont(fontlist1, 0, &font);
3526 ok(hr == S_OK, "got 0x%08x\n", hr);
3527 IDWriteFont3_Release(font);
3529 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref);
3530 ok(hr == S_OK, "got 0x%08x\n", hr);
3532 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref1);
3533 ok(hr == S_OK, "got 0x%08x\n", hr);
3534 ok(ref != ref1, "got %p, %p\n", ref, ref1);
3536 IDWriteFontFaceReference_Release(ref1);
3537 IDWriteFontFaceReference_Release(ref);
3538 IDWriteFontList1_Release(fontlist1);
3540 else
3541 win_skip("IDWriteFontList1 is not supported.\n");
3543 IDWriteFontList_Release(fontlist);
3544 IDWriteFontFamily_Release(family);
3546 IDWriteFontCollection_Release(collection);
3547 ref = IDWriteFactory_Release(factory);
3548 ok(ref == 0, "factory not released, %u\n", ref);
3551 static void test_GetInformationalStrings(void)
3553 IDWriteLocalizedStrings *strings, *strings2;
3554 IDWriteFontCollection *collection;
3555 IDWriteFontFamily *family;
3556 IDWriteFactory *factory;
3557 IDWriteFont *font;
3558 BOOL exists;
3559 HRESULT hr;
3560 ULONG ref;
3562 factory = create_factory();
3564 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3565 ok(hr == S_OK, "got 0x%08x\n", hr);
3567 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3568 ok(hr == S_OK, "got 0x%08x\n", hr);
3570 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3571 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3572 ok(hr == S_OK, "got 0x%08x\n", hr);
3574 exists = TRUE;
3575 strings = (void*)0xdeadbeef;
3576 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1, &strings, &exists);
3577 ok(hr == S_OK, "got 0x%08x\n", hr);
3578 ok(exists == FALSE, "got %d\n", exists);
3579 ok(strings == NULL, "got %p\n", strings);
3581 exists = TRUE;
3582 strings = NULL;
3583 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists);
3584 ok(hr == S_OK, "got 0x%08x\n", hr);
3585 ok(exists == FALSE, "got %d\n", exists);
3587 exists = FALSE;
3588 strings = NULL;
3589 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
3590 ok(hr == S_OK, "got 0x%08x\n", hr);
3591 ok(exists == TRUE, "got %d\n", exists);
3593 /* strings instance is not reused */
3594 strings2 = NULL;
3595 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings2, &exists);
3596 ok(hr == S_OK, "got 0x%08x\n", hr);
3597 ok(strings2 != strings, "got %p, %p\n", strings2, strings);
3599 IDWriteLocalizedStrings_Release(strings);
3600 IDWriteLocalizedStrings_Release(strings2);
3601 IDWriteFont_Release(font);
3602 IDWriteFontFamily_Release(family);
3603 IDWriteFontCollection_Release(collection);
3604 ref = IDWriteFactory_Release(factory);
3605 ok(ref == 0, "factory not released, %u\n", ref);
3608 static void test_GetGdiInterop(void)
3610 IDWriteGdiInterop *interop, *interop2;
3611 IDWriteFactory *factory, *factory2;
3612 IDWriteFont *font;
3613 LOGFONTW logfont;
3614 HRESULT hr;
3615 ULONG ref;
3617 factory = create_factory();
3619 interop = NULL;
3620 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3621 ok(hr == S_OK, "got 0x%08x\n", hr);
3623 interop2 = NULL;
3624 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
3625 ok(hr == S_OK, "got 0x%08x\n", hr);
3626 ok(interop == interop2, "got %p, %p\n", interop, interop2);
3627 IDWriteGdiInterop_Release(interop2);
3629 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory2);
3630 ok(hr == S_OK, "got 0x%08x\n", hr);
3632 /* each factory gets its own interop */
3633 interop2 = NULL;
3634 hr = IDWriteFactory_GetGdiInterop(factory2, &interop2);
3635 ok(hr == S_OK, "got 0x%08x\n", hr);
3636 ok(interop != interop2, "got %p, %p\n", interop, interop2);
3638 /* release factory - interop still works */
3639 IDWriteFactory_Release(factory2);
3641 memset(&logfont, 0, sizeof(logfont));
3642 logfont.lfHeight = 12;
3643 logfont.lfWidth = 12;
3644 logfont.lfWeight = FW_NORMAL;
3645 logfont.lfItalic = 1;
3646 lstrcpyW(logfont.lfFaceName, tahomaW);
3648 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop2, &logfont, &font);
3649 ok(hr == S_OK, "got 0x%08x\n", hr);
3650 IDWriteFont_Release(font);
3652 IDWriteGdiInterop_Release(interop2);
3653 IDWriteGdiInterop_Release(interop);
3654 ref = IDWriteFactory_Release(factory);
3655 ok(ref == 0, "factory not released, %u\n", ref);
3658 static void test_CreateFontFaceFromHdc(void)
3660 IDWriteGdiInterop *interop;
3661 IDWriteFontFace *fontface;
3662 IDWriteFactory *factory;
3663 HFONT hfont, oldhfont;
3664 LOGFONTW logfont;
3665 LOGFONTA lf;
3666 HRESULT hr;
3667 ULONG ref;
3668 HDC hdc;
3670 factory = create_factory();
3672 interop = NULL;
3673 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3674 ok(hr == S_OK, "got 0x%08x\n", hr);
3676 /* Invalid HDC. */
3677 fontface = (void*)0xdeadbeef;
3678 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, NULL, &fontface);
3679 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3680 ok(fontface == NULL, "got %p\n", fontface);
3682 fontface = (void *)0xdeadbeef;
3683 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, (HDC)0xdeadbeef, &fontface);
3684 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3685 ok(fontface == NULL, "got %p\n", fontface);
3687 memset(&logfont, 0, sizeof(logfont));
3688 logfont.lfHeight = 12;
3689 logfont.lfWidth = 12;
3690 logfont.lfWeight = FW_NORMAL;
3691 logfont.lfItalic = 1;
3692 lstrcpyW(logfont.lfFaceName, tahomaW);
3694 hfont = CreateFontIndirectW(&logfont);
3695 hdc = CreateCompatibleDC(0);
3696 oldhfont = SelectObject(hdc, hfont);
3698 fontface = NULL;
3699 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
3700 ok(hr == S_OK, "got 0x%08x\n", hr);
3701 IDWriteFontFace_Release(fontface);
3702 DeleteObject(SelectObject(hdc, oldhfont));
3704 /* Select bitmap font MS Sans Serif, format that's not supported by DirectWrite. */
3705 memset(&lf, 0, sizeof(lf));
3706 lf.lfHeight = -12;
3707 strcpy(lf.lfFaceName, "MS Sans Serif");
3709 hfont = CreateFontIndirectA(&lf);
3710 oldhfont = SelectObject(hdc, hfont);
3712 fontface = (void *)0xdeadbeef;
3713 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
3714 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* Vista */, "got 0x%08x\n", hr);
3715 ok(fontface == NULL, "got %p\n", fontface);
3717 DeleteObject(SelectObject(hdc, oldhfont));
3718 DeleteDC(hdc);
3720 IDWriteGdiInterop_Release(interop);
3721 ref = IDWriteFactory_Release(factory);
3722 ok(ref == 0, "factory not released, %u\n", ref);
3725 static void test_GetSimulations(void)
3727 DWRITE_FONT_SIMULATIONS simulations;
3728 IDWriteGdiInterop *interop;
3729 IDWriteFontFace *fontface;
3730 IDWriteFactory *factory;
3731 IDWriteFont *font;
3732 LOGFONTW logfont;
3733 HRESULT hr;
3734 ULONG ref;
3736 factory = create_factory();
3738 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3739 ok(hr == S_OK, "got 0x%08x\n", hr);
3741 memset(&logfont, 0, sizeof(logfont));
3742 logfont.lfHeight = 12;
3743 logfont.lfWidth = 12;
3744 logfont.lfWeight = FW_NORMAL;
3745 logfont.lfItalic = 1;
3746 lstrcpyW(logfont.lfFaceName, tahomaW);
3748 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3749 ok(hr == S_OK, "got 0x%08x\n", hr);
3751 simulations = IDWriteFont_GetSimulations(font);
3752 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
3753 hr = IDWriteFont_CreateFontFace(font, &fontface);
3754 ok(hr == S_OK, "got 0x%08x\n", hr);
3755 simulations = IDWriteFontFace_GetSimulations(fontface);
3756 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
3757 IDWriteFontFace_Release(fontface);
3758 IDWriteFont_Release(font);
3760 memset(&logfont, 0, sizeof(logfont));
3761 logfont.lfHeight = 12;
3762 logfont.lfWidth = 12;
3763 logfont.lfWeight = FW_NORMAL;
3764 logfont.lfItalic = 0;
3765 lstrcpyW(logfont.lfFaceName, tahomaW);
3767 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3768 ok(hr == S_OK, "got 0x%08x\n", hr);
3770 simulations = IDWriteFont_GetSimulations(font);
3771 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
3772 hr = IDWriteFont_CreateFontFace(font, &fontface);
3773 ok(hr == S_OK, "got 0x%08x\n", hr);
3774 simulations = IDWriteFontFace_GetSimulations(fontface);
3775 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
3776 IDWriteFontFace_Release(fontface);
3777 IDWriteFont_Release(font);
3779 IDWriteGdiInterop_Release(interop);
3780 ref = IDWriteFactory_Release(factory);
3781 ok(ref == 0, "factory not released, %u\n", ref);
3784 static void test_GetFaceNames(void)
3786 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
3787 static const WCHAR enus2W[] = {'e','n','-','U','s',0};
3788 static const WCHAR enusW[] = {'e','n','-','u','s',0};
3789 IDWriteLocalizedStrings *strings, *strings2;
3790 IDWriteGdiInterop *interop;
3791 IDWriteFactory *factory;
3792 UINT32 count, index;
3793 IDWriteFont *font;
3794 LOGFONTW logfont;
3795 WCHAR buffW[255];
3796 BOOL exists;
3797 HRESULT hr;
3798 ULONG ref;
3800 factory = create_factory();
3802 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3803 ok(hr == S_OK, "got 0x%08x\n", hr);
3805 memset(&logfont, 0, sizeof(logfont));
3806 logfont.lfHeight = 12;
3807 logfont.lfWidth = 12;
3808 logfont.lfWeight = FW_NORMAL;
3809 logfont.lfItalic = 1;
3810 lstrcpyW(logfont.lfFaceName, tahomaW);
3812 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3813 ok(hr == S_OK, "got 0x%08x\n", hr);
3815 hr = IDWriteFont_GetFaceNames(font, &strings);
3816 ok(hr == S_OK, "got 0x%08x\n", hr);
3818 hr = IDWriteFont_GetFaceNames(font, &strings2);
3819 ok(hr == S_OK, "got 0x%08x\n", hr);
3820 ok(strings != strings2, "got %p, %p\n", strings2, strings);
3821 IDWriteLocalizedStrings_Release(strings2);
3823 count = IDWriteLocalizedStrings_GetCount(strings);
3824 ok(count == 1, "got %d\n", count);
3826 index = 1;
3827 exists = FALSE;
3828 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enus2W, &index, &exists);
3829 ok(hr == S_OK, "got 0x%08x\n", hr);
3830 ok(index == 0 && exists, "got %d, %d\n", index, exists);
3832 count = 0;
3833 hr = IDWriteLocalizedStrings_GetLocaleNameLength(strings, 1, &count);
3834 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3835 ok(count == ~0, "got %d\n", count);
3837 /* for simulated faces names are also simulated */
3838 buffW[0] = 0;
3839 hr = IDWriteLocalizedStrings_GetLocaleName(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
3840 ok(hr == S_OK, "got 0x%08x\n", hr);
3841 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
3843 buffW[0] = 0;
3844 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
3845 ok(hr == S_OK, "got 0x%08x\n", hr);
3846 ok(!lstrcmpW(buffW, obliqueW), "got %s\n", wine_dbgstr_w(buffW));
3847 IDWriteLocalizedStrings_Release(strings);
3849 IDWriteFont_Release(font);
3850 IDWriteGdiInterop_Release(interop);
3851 ref = IDWriteFactory_Release(factory);
3852 ok(ref == 0, "factory not released, %u\n", ref);
3855 struct local_refkey
3857 FILETIME writetime;
3858 WCHAR name[1];
3861 static void test_TryGetFontTable(void)
3863 IDWriteLocalFontFileLoader *localloader;
3864 WIN32_FILE_ATTRIBUTE_DATA info;
3865 const struct local_refkey *key;
3866 IDWriteFontFileLoader *loader;
3867 const void *table, *table2;
3868 IDWriteFontFace *fontface;
3869 void *context, *context2;
3870 IDWriteFactory *factory;
3871 IDWriteFontFile *file;
3872 WCHAR buffW[MAX_PATH];
3873 BOOL exists, ret;
3874 UINT32 size, len;
3875 WCHAR *path;
3876 HRESULT hr;
3877 ULONG ref;
3879 path = create_testfontfile(test_fontfile);
3881 factory = create_factory();
3883 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3884 ok(hr == S_OK, "got 0x%08x\n",hr);
3886 key = NULL;
3887 size = 0;
3888 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
3889 ok(hr == S_OK, "got 0x%08x\n", hr);
3890 ok(size != 0, "got %u\n", size);
3892 ret = GetFileAttributesExW(path, GetFileExInfoStandard, &info);
3893 ok(ret, "got %d\n", ret);
3894 ok(!memcmp(&info.ftLastWriteTime, &key->writetime, sizeof(key->writetime)), "got wrong write time\n");
3896 hr = IDWriteFontFile_GetLoader(file, &loader);
3897 ok(hr == S_OK, "got 0x%08x\n", hr);
3898 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
3899 IDWriteFontFileLoader_Release(loader);
3901 hr = IDWriteLocalFontFileLoader_GetFilePathLengthFromKey(localloader, key, size, &len);
3902 ok(hr == S_OK, "got 0x%08x\n", hr);
3903 ok(lstrlenW(key->name) == len, "path length %d\n", len);
3905 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, size, buffW, sizeof(buffW)/sizeof(WCHAR));
3906 ok(hr == S_OK, "got 0x%08x\n", hr);
3907 ok(!lstrcmpW(buffW, key->name), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(key->name));
3908 IDWriteLocalFontFileLoader_Release(localloader);
3910 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, 0, &fontface);
3911 ok(hr == S_OK, "got 0x%08x\n",hr);
3913 exists = FALSE;
3914 context = (void*)0xdeadbeef;
3915 table = NULL;
3916 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table, &size, &context, &exists);
3917 ok(hr == S_OK, "got 0x%08x\n",hr);
3918 ok(exists == TRUE, "got %d\n", exists);
3919 ok(context == NULL && table != NULL, "cmap: context %p, table %p\n", context, table);
3921 exists = FALSE;
3922 context2 = (void*)0xdeadbeef;
3923 table2 = NULL;
3924 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table2, &size, &context2, &exists);
3925 ok(hr == S_OK, "got 0x%08x\n",hr);
3926 ok(exists == TRUE, "got %d\n", exists);
3927 ok(context2 == context && table2 == table, "cmap: context2 %p, table2 %p\n", context2, table2);
3929 IDWriteFontFace_ReleaseFontTable(fontface, context2);
3930 IDWriteFontFace_ReleaseFontTable(fontface, context);
3932 /* table does not exist */
3933 exists = TRUE;
3934 context = (void*)0xdeadbeef;
3935 table = (void*)0xdeadbeef;
3936 hr = IDWriteFontFace_TryGetFontTable(fontface, 0xabababab, &table, &size, &context, &exists);
3937 ok(hr == S_OK, "got 0x%08x\n", hr);
3938 ok(exists == FALSE, "got %d\n", exists);
3939 ok(context == NULL && table == NULL, "got context %p, table pointer %p\n", context, table);
3941 IDWriteFontFace_Release(fontface);
3942 IDWriteFontFile_Release(file);
3943 ref = IDWriteFactory_Release(factory);
3944 ok(ref == 0, "factory not released, %u\n", ref);
3945 DELETE_FONTFILE(path);
3948 static void test_ConvertFontToLOGFONT(void)
3950 IDWriteFactory *factory, *factory2;
3951 IDWriteFontCollection *collection;
3952 IDWriteGdiInterop *interop;
3953 IDWriteFontFamily *family;
3954 IDWriteFont *font;
3955 LOGFONTW logfont;
3956 UINT32 i, count;
3957 BOOL system;
3958 HRESULT hr;
3959 ULONG ref;
3961 factory = create_factory();
3962 factory2 = create_factory();
3964 interop = NULL;
3965 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3966 ok(hr == S_OK, "got 0x%08x\n", hr);
3968 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection, FALSE);
3969 ok(hr == S_OK, "got 0x%08x\n", hr);
3971 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3972 ok(hr == S_OK, "got 0x%08x\n", hr);
3974 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3975 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3976 ok(hr == S_OK, "got 0x%08x\n", hr);
3978 if (0) { /* crashes on native */
3979 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, NULL, NULL);
3980 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, NULL);
3981 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, NULL, &system);
3984 memset(&logfont, 0xcc, sizeof(logfont));
3985 system = TRUE;
3986 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, &system);
3987 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3988 ok(!system, "got %d\n", system);
3989 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
3991 count = IDWriteFontCollection_GetFontFamilyCount(collection);
3992 for (i = 0; i < count; i++) {
3993 WCHAR nameW[128], familynameW[64], facenameW[64];
3994 IDWriteLocalizedStrings *names;
3995 DWRITE_FONT_SIMULATIONS sim;
3996 IDWriteFontFamily *family;
3997 UINT32 font_count, j;
3998 IDWriteFont *font;
3999 LOGFONTW lf;
4001 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
4002 ok(hr == S_OK, "got 0x%08x\n", hr);
4004 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
4005 ok(hr == S_OK, "got 0x%08x\n", hr);
4007 get_enus_string(names, familynameW, sizeof(familynameW)/sizeof(familynameW[0]));
4008 IDWriteLocalizedStrings_Release(names);
4010 font_count = IDWriteFontFamily_GetFontCount(family);
4012 for (j = 0; j < font_count; j++) {
4013 static const WCHAR spaceW[] = {' ', 0};
4015 hr = IDWriteFontFamily_GetFont(family, j, &font);
4016 ok(hr == S_OK, "got 0x%08x\n", hr);
4018 hr = IDWriteFont_GetFaceNames(font, &names);
4019 ok(hr == S_OK, "got 0x%08x\n", hr);
4021 get_enus_string(names, facenameW, sizeof(facenameW)/sizeof(facenameW[0]));
4022 IDWriteLocalizedStrings_Release(names);
4024 lstrcpyW(nameW, familynameW);
4025 lstrcatW(nameW, spaceW);
4026 lstrcatW(nameW, facenameW);
4028 system = FALSE;
4029 memset(&logfont, 0xcc, sizeof(logfont));
4030 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, &logfont, &system);
4031 ok(hr == S_OK, "got 0x%08x\n", hr);
4032 ok(system, "got %d\n", system);
4034 sim = IDWriteFont_GetSimulations(font);
4036 get_logfont_from_font(font, &lf);
4037 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
4038 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
4039 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
4040 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
4041 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
4042 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
4043 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
4045 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
4046 logfont.lfOutPrecision);
4047 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
4048 logfont.lfClipPrecision);
4049 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
4050 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
4051 logfont.lfPitchAndFamily);
4053 IDWriteFont_Release(font);
4056 IDWriteFontFamily_Release(family);
4059 IDWriteFactory_Release(factory2);
4061 IDWriteFontCollection_Release(collection);
4062 IDWriteFontFamily_Release(family);
4063 IDWriteFont_Release(font);
4064 IDWriteGdiInterop_Release(interop);
4065 ref = IDWriteFactory_Release(factory);
4066 ok(ref == 0, "factory not released, %u\n", ref);
4069 static void test_CreateStreamFromKey(void)
4071 IDWriteLocalFontFileLoader *localloader;
4072 IDWriteFontFileStream *stream, *stream2;
4073 IDWriteFontFileLoader *loader;
4074 IDWriteFactory *factory;
4075 IDWriteFontFile *file;
4076 UINT64 writetime;
4077 WCHAR *path;
4078 void *key;
4079 UINT32 size;
4080 HRESULT hr;
4081 ULONG ref;
4083 factory = create_factory();
4085 path = create_testfontfile(test_fontfile);
4087 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4088 ok(hr == S_OK, "got 0x%08x\n",hr);
4090 key = NULL;
4091 size = 0;
4092 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4093 ok(hr == S_OK, "got 0x%08x\n", hr);
4094 ok(size != 0, "got %u\n", size);
4096 hr = IDWriteFontFile_GetLoader(file, &loader);
4097 ok(hr == S_OK, "got 0x%08x\n", hr);
4098 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4099 IDWriteFontFileLoader_Release(loader);
4101 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4102 ok(hr == S_OK, "got 0x%08x\n", hr);
4103 EXPECT_REF(stream, 1);
4105 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2);
4106 ok(hr == S_OK, "got 0x%08x\n", hr);
4107 ok(stream == stream2 || broken(stream != stream2) /* Win7 SP0 */, "got %p, %p\n", stream, stream2);
4108 if (stream == stream2)
4109 EXPECT_REF(stream, 2);
4110 IDWriteFontFileStream_Release(stream);
4111 IDWriteFontFileStream_Release(stream2);
4113 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4114 ok(hr == S_OK, "got 0x%08x\n", hr);
4115 EXPECT_REF(stream, 1);
4117 writetime = 0;
4118 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
4119 ok(hr == S_OK, "got 0x%08x\n", hr);
4120 ok(writetime != 0, "got %s\n", wine_dbgstr_longlong(writetime));
4122 IDWriteFontFileStream_Release(stream);
4123 IDWriteFontFile_Release(file);
4125 IDWriteLocalFontFileLoader_Release(localloader);
4126 ref = IDWriteFactory_Release(factory);
4127 ok(ref == 0, "factory not released, %u\n", ref);
4128 DELETE_FONTFILE(path);
4131 static void test_ReadFileFragment(void)
4133 IDWriteLocalFontFileLoader *localloader;
4134 IDWriteFontFileStream *stream;
4135 IDWriteFontFileLoader *loader;
4136 IDWriteFactory *factory;
4137 IDWriteFontFile *file;
4138 const void *fragment, *fragment2;
4139 void *key, *context, *context2;
4140 UINT64 filesize;
4141 UINT32 size;
4142 WCHAR *path;
4143 HRESULT hr;
4144 ULONG ref;
4146 factory = create_factory();
4148 path = create_testfontfile(test_fontfile);
4150 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4151 ok(hr == S_OK, "got 0x%08x\n",hr);
4153 key = NULL;
4154 size = 0;
4155 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
4156 ok(hr == S_OK, "got 0x%08x\n", hr);
4157 ok(size != 0, "got %u\n", size);
4159 hr = IDWriteFontFile_GetLoader(file, &loader);
4160 ok(hr == S_OK, "got 0x%08x\n", hr);
4161 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
4162 IDWriteFontFileLoader_Release(loader);
4164 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
4165 ok(hr == S_OK, "got 0x%08x\n", hr);
4167 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
4168 ok(hr == S_OK, "got 0x%08x\n", hr);
4170 /* reading past the end of the stream */
4171 fragment = (void*)0xdeadbeef;
4172 context = (void*)0xdeadbeef;
4173 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize+1, &context);
4174 ok(hr == E_FAIL, "got 0x%08x\n", hr);
4175 ok(context == NULL, "got %p\n", context);
4176 ok(fragment == NULL, "got %p\n", fragment);
4178 fragment = (void*)0xdeadbeef;
4179 context = (void*)0xdeadbeef;
4180 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
4181 ok(hr == S_OK, "got 0x%08x\n", hr);
4182 ok(context == NULL, "got %p\n", context);
4183 ok(fragment != NULL, "got %p\n", fragment);
4185 fragment2 = (void*)0xdeadbeef;
4186 context2 = (void*)0xdeadbeef;
4187 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment2, 0, filesize, &context2);
4188 ok(hr == S_OK, "got 0x%08x\n", hr);
4189 ok(context2 == NULL, "got %p\n", context2);
4190 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
4192 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
4193 IDWriteFontFileStream_ReleaseFileFragment(stream, context2);
4195 /* fragment is released, try again */
4196 fragment = (void*)0xdeadbeef;
4197 context = (void*)0xdeadbeef;
4198 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
4199 ok(hr == S_OK, "got 0x%08x\n", hr);
4200 ok(context == NULL, "got %p\n", context);
4201 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
4202 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
4204 IDWriteFontFile_Release(file);
4205 IDWriteFontFileStream_Release(stream);
4206 IDWriteLocalFontFileLoader_Release(localloader);
4207 ref = IDWriteFactory_Release(factory);
4208 ok(ref == 0, "factory not released, %u\n", ref);
4209 DELETE_FONTFILE(path);
4212 static void test_GetDesignGlyphMetrics(void)
4214 DWRITE_GLYPH_METRICS metrics[2];
4215 IDWriteFontFace *fontface;
4216 IDWriteFactory *factory;
4217 IDWriteFontFile *file;
4218 UINT16 indices[2];
4219 UINT32 codepoint;
4220 WCHAR *path;
4221 HRESULT hr;
4222 ULONG ref;
4224 factory = create_factory();
4226 path = create_testfontfile(test_fontfile);
4228 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4229 ok(hr == S_OK, "got 0x%08x\n",hr);
4231 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
4232 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4233 ok(hr == S_OK, "got 0x%08x\n",hr);
4234 IDWriteFontFile_Release(file);
4236 codepoint = 'A';
4237 indices[0] = 0;
4238 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &indices[0]);
4239 ok(hr == S_OK, "got 0x%08x\n", hr);
4240 ok(indices[0] > 0, "got %u\n", indices[0]);
4242 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 0, metrics, FALSE);
4243 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
4245 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 1, metrics, FALSE);
4246 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
4248 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 0, metrics, FALSE);
4249 ok(hr == S_OK, "got 0x%08x\n",hr);
4251 /* missing glyphs are ignored */
4252 indices[1] = 1;
4253 memset(metrics, 0xcc, sizeof(metrics));
4254 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 2, metrics, FALSE);
4255 ok(hr == S_OK, "got 0x%08x\n",hr);
4256 ok(metrics[0].advanceWidth == 1000, "got %d\n", metrics[0].advanceWidth);
4257 ok(metrics[1].advanceWidth == 0, "got %d\n", metrics[1].advanceWidth);
4259 IDWriteFontFace_Release(fontface);
4260 ref = IDWriteFactory_Release(factory);
4261 ok(ref == 0, "factory not released, %u\n", ref);
4262 DELETE_FONTFILE(path);
4265 static void test_IsMonospacedFont(void)
4267 static const WCHAR courierW[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
4268 IDWriteFontCollection *collection;
4269 IDWriteFactory *factory;
4270 UINT32 index;
4271 BOOL exists;
4272 HRESULT hr;
4273 ULONG ref;
4275 factory = create_factory();
4276 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4277 ok(hr == S_OK, "got 0x%08x\n", hr);
4279 exists = FALSE;
4280 hr = IDWriteFontCollection_FindFamilyName(collection, courierW, &index, &exists);
4281 ok(hr == S_OK, "got 0x%08x\n", hr);
4282 if (exists) {
4283 IDWriteFontFamily *family;
4284 IDWriteFont1 *font1;
4285 IDWriteFont *font;
4287 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
4288 ok(hr == S_OK, "got 0x%08x\n", hr);
4290 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
4291 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
4292 ok(hr == S_OK, "got 0x%08x\n", hr);
4293 IDWriteFontFamily_Release(family);
4295 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
4296 if (hr == S_OK) {
4297 IDWriteFontFace1 *fontface1;
4298 IDWriteFontFace *fontface;
4299 BOOL is_monospaced;
4301 is_monospaced = IDWriteFont1_IsMonospacedFont(font1);
4302 ok(is_monospaced, "got %d\n", is_monospaced);
4304 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
4305 ok(hr == S_OK, "got 0x%08x\n", hr);
4306 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4307 ok(hr == S_OK, "got 0x%08x\n", hr);
4308 is_monospaced = IDWriteFontFace1_IsMonospacedFont(fontface1);
4309 ok(is_monospaced, "got %d\n", is_monospaced);
4310 IDWriteFontFace1_Release(fontface1);
4312 IDWriteFontFace_Release(fontface);
4313 IDWriteFont1_Release(font1);
4315 else
4316 win_skip("IsMonospacedFont() is not supported.\n");
4318 IDWriteFont_Release(font);
4320 else
4321 skip("Courier New font not found.\n");
4323 ref = IDWriteFontCollection_Release(collection);
4324 ok(ref == 0, "factory not released, %u\n", ref);
4327 static void test_GetDesignGlyphAdvances(void)
4329 IDWriteFontFace1 *fontface1;
4330 IDWriteFontFace *fontface;
4331 IDWriteFactory *factory;
4332 IDWriteFontFile *file;
4333 WCHAR *path;
4334 HRESULT hr;
4335 ULONG ref;
4337 factory = create_factory();
4339 path = create_testfontfile(test_fontfile);
4341 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4342 ok(hr == S_OK, "got 0x%08x\n", hr);
4344 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
4345 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4346 ok(hr == S_OK, "got 0x%08x\n", hr);
4347 IDWriteFontFile_Release(file);
4349 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4350 if (hr == S_OK) {
4351 UINT32 codepoint;
4352 UINT16 index;
4353 INT32 advance;
4355 codepoint = 'A';
4356 index = 0;
4357 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &index);
4358 ok(hr == S_OK, "got 0x%08x\n", hr);
4359 ok(index > 0, "got %u\n", index);
4361 advance = 0;
4362 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, FALSE);
4363 ok(hr == S_OK, "got 0x%08x\n", hr);
4364 ok(advance == 1000, "got %i\n", advance);
4366 advance = 0;
4367 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, TRUE);
4368 ok(hr == S_OK, "got 0x%08x\n", hr);
4369 todo_wine
4370 ok(advance == 2048, "got %i\n", advance);
4372 IDWriteFontFace1_Release(fontface1);
4374 else
4375 win_skip("GetDesignGlyphAdvances() is not supported.\n");
4377 IDWriteFontFace_Release(fontface);
4378 ref = IDWriteFactory_Release(factory);
4379 ok(ref == 0, "factory not released, %u\n", ref);
4380 DELETE_FONTFILE(path);
4383 static void test_GetGlyphRunOutline(void)
4385 DWRITE_GLYPH_OFFSET offsets[2];
4386 IDWriteFactory *factory;
4387 IDWriteFontFile *file;
4388 IDWriteFontFace *face;
4389 UINT32 codepoint;
4390 FLOAT advances[2];
4391 UINT16 glyphs[2];
4392 WCHAR *path;
4393 HRESULT hr;
4394 ULONG ref;
4396 path = create_testfontfile(test_fontfile);
4397 factory = create_factory();
4399 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4400 ok(hr == S_OK, "got 0x%08x\n",hr);
4402 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
4403 ok(hr == S_OK, "got 0x%08x\n", hr);
4404 IDWriteFontFile_Release(file);
4406 codepoint = 'A';
4407 glyphs[0] = 0;
4408 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4409 ok(hr == S_OK, "got 0x%08x\n", hr);
4410 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4411 glyphs[1] = glyphs[0];
4413 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, glyphs, advances, offsets, 1, FALSE, FALSE, NULL);
4414 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4416 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, NULL, NULL, offsets, 1, FALSE, FALSE, &test_geomsink);
4417 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4419 advances[0] = 1.0;
4420 advances[1] = 0.0;
4422 offsets[0].advanceOffset = 1.0;
4423 offsets[0].ascenderOffset = 1.0;
4424 offsets[1].advanceOffset = 0.0;
4425 offsets[1].ascenderOffset = 0.0;
4427 /* default advances, no offsets */
4428 memset(g_startpoints, 0, sizeof(g_startpoints));
4429 g_startpoint_count = 0;
4430 SET_EXPECT(setfillmode);
4431 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, FALSE, &test_geomsink);
4432 ok(hr == S_OK, "got 0x%08x\n", hr);
4433 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4434 if (g_startpoint_count == 2) {
4435 /* glyph advance of 500 is applied */
4436 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);
4437 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);
4439 CHECK_CALLED(setfillmode);
4441 /* default advances, no offsets, RTL */
4442 memset(g_startpoints, 0, sizeof(g_startpoints));
4443 g_startpoint_count = 0;
4444 SET_EXPECT(setfillmode);
4445 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, TRUE, &test_geomsink);
4446 ok(hr == S_OK, "got 0x%08x\n", hr);
4447 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4448 if (g_startpoint_count == 2) {
4449 /* advance is -500 now */
4450 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);
4451 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);
4453 CHECK_CALLED(setfillmode);
4455 /* default advances, additional offsets */
4456 memset(g_startpoints, 0, sizeof(g_startpoints));
4457 g_startpoint_count = 0;
4458 SET_EXPECT(setfillmode);
4459 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, FALSE, &test_geomsink);
4460 ok(hr == S_OK, "got 0x%08x\n", hr);
4461 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4462 if (g_startpoint_count == 2) {
4463 /* offsets applied to first contour */
4464 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);
4465 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);
4467 CHECK_CALLED(setfillmode);
4469 /* default advances, additional offsets, RTL */
4470 memset(g_startpoints, 0, sizeof(g_startpoints));
4471 g_startpoint_count = 0;
4472 SET_EXPECT(setfillmode);
4473 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, TRUE, &test_geomsink);
4474 ok(hr == S_OK, "got 0x%08x\n", hr);
4475 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4476 if (g_startpoint_count == 2) {
4477 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);
4478 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);
4480 CHECK_CALLED(setfillmode);
4482 /* custom advances and offsets, offset turns total advance value to zero */
4483 memset(g_startpoints, 0, sizeof(g_startpoints));
4484 g_startpoint_count = 0;
4485 SET_EXPECT(setfillmode);
4486 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, advances, offsets, 2, FALSE, FALSE, &test_geomsink);
4487 ok(hr == S_OK, "got 0x%08x\n", hr);
4488 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4489 if (g_startpoint_count == 2) {
4490 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);
4491 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);
4493 CHECK_CALLED(setfillmode);
4495 /* 0 glyph count */
4496 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 0, FALSE, FALSE, &test_geomsink2);
4497 ok(hr == S_OK, "got 0x%08x\n", hr);
4499 /* Glyph with open figure, single contour point. */
4500 codepoint = 'B';
4501 glyphs[0] = 0;
4502 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4503 ok(hr == S_OK, "got 0x%08x\n", hr);
4504 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4506 SET_EXPECT(setfillmode);
4507 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
4508 ok(hr == S_OK, "got 0x%08x\n", hr);
4509 CHECK_CALLED(setfillmode);
4511 IDWriteFactory_Release(factory);
4512 IDWriteFontFace_Release(face);
4513 DELETE_FONTFILE(path);
4515 /* space glyph */
4516 factory = create_factory();
4517 face = create_fontface(factory);
4519 codepoint = ' ';
4520 glyphs[0] = 0;
4521 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4522 ok(hr == S_OK, "got 0x%08x\n", hr);
4523 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4525 SET_EXPECT(setfillmode);
4526 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
4527 ok(hr == S_OK, "got 0x%08x\n", hr);
4528 CHECK_CALLED(setfillmode);
4530 IDWriteFontFace_Release(face);
4531 ref = IDWriteFactory_Release(factory);
4532 ok(ref == 0, "factory not released, %u\n", ref);
4535 static void test_GetEudcFontCollection(void)
4537 IDWriteFontCollection *coll, *coll2;
4538 IDWriteFactory1 *factory;
4539 HRESULT hr;
4540 ULONG ref;
4542 factory = create_factory_iid(&IID_IDWriteFactory1);
4543 if (!factory) {
4544 win_skip("GetEudcFontCollection() is not supported.\n");
4545 return;
4548 EXPECT_REF(factory, 1);
4549 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll, FALSE);
4550 ok(hr == S_OK, "got 0x%08x\n", hr);
4551 EXPECT_REF(factory, 2);
4552 hr = IDWriteFactory1_GetEudcFontCollection(factory, &coll2, FALSE);
4553 ok(hr == S_OK, "got 0x%08x\n", hr);
4554 EXPECT_REF(factory, 2);
4555 ok(coll == coll2, "got %p, %p\n", coll, coll2);
4556 IDWriteFontCollection_Release(coll);
4557 IDWriteFontCollection_Release(coll2);
4559 ref = IDWriteFactory1_Release(factory);
4560 ok(ref == 0, "factory not released, %u\n", ref);
4563 static void test_GetCaretMetrics(void)
4565 DWRITE_FONT_METRICS1 metrics;
4566 IDWriteFontFace1 *fontface1;
4567 DWRITE_CARET_METRICS caret;
4568 IDWriteFontFace *fontface;
4569 IDWriteFactory *factory;
4570 IDWriteFontFile *file;
4571 IDWriteFont *font;
4572 WCHAR *path;
4573 HRESULT hr;
4574 ULONG ref;
4576 path = create_testfontfile(test_fontfile);
4577 factory = create_factory();
4579 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4580 ok(hr == S_OK, "got 0x%08x\n", hr);
4582 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4583 ok(hr == S_OK, "got 0x%08x\n", hr);
4584 IDWriteFontFile_Release(file);
4586 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4587 IDWriteFontFace_Release(fontface);
4588 if (hr != S_OK) {
4589 win_skip("GetCaretMetrics() is not supported.\n");
4590 ref = IDWriteFactory_Release(factory);
4591 ok(ref == 0, "factory not released, %u\n", ref);
4592 DELETE_FONTFILE(path);
4593 return;
4596 memset(&caret, 0xcc, sizeof(caret));
4597 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4598 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
4599 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
4600 ok(caret.offset == 0, "got %d\n", caret.offset);
4601 IDWriteFontFace1_Release(fontface1);
4602 IDWriteFactory_Release(factory);
4604 /* now with Tahoma Normal */
4605 factory = create_factory();
4606 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
4607 hr = IDWriteFont_CreateFontFace(font, &fontface);
4608 ok(hr == S_OK, "got 0x%08x\n", hr);
4609 IDWriteFont_Release(font);
4610 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4611 ok(hr == S_OK, "got 0x%08x\n", hr);
4612 IDWriteFontFace_Release(fontface);
4614 memset(&caret, 0xcc, sizeof(caret));
4615 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4616 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
4617 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
4618 ok(caret.offset == 0, "got %d\n", caret.offset);
4619 IDWriteFontFace1_Release(fontface1);
4621 /* simulated italic */
4622 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
4623 hr = IDWriteFont_CreateFontFace(font, &fontface);
4624 ok(hr == S_OK, "got 0x%08x\n", hr);
4625 IDWriteFont_Release(font);
4626 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4627 ok(hr == S_OK, "got 0x%08x\n", hr);
4628 IDWriteFontFace_Release(fontface);
4630 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
4632 memset(&caret, 0xcc, sizeof(caret));
4633 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4634 ok(caret.slopeRise == metrics.designUnitsPerEm, "got %d\n", caret.slopeRise);
4635 ok(caret.slopeRun > 0, "got %d\n", caret.slopeRun);
4636 ok(caret.offset == 0, "got %d\n", caret.offset);
4637 IDWriteFontFace1_Release(fontface1);
4639 ref = IDWriteFactory_Release(factory);
4640 ok(ref == 0, "factory not released, %u\n", ref);
4641 DELETE_FONTFILE(path);
4644 static void test_GetGlyphCount(void)
4646 IDWriteFontFace *fontface;
4647 IDWriteFactory *factory;
4648 IDWriteFontFile *file;
4649 UINT16 count;
4650 WCHAR *path;
4651 HRESULT hr;
4652 ULONG ref;
4654 path = create_testfontfile(test_fontfile);
4655 factory = create_factory();
4657 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4658 ok(hr == S_OK, "got 0x%08x\n", hr);
4660 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4661 ok(hr == S_OK, "got 0x%08x\n", hr);
4662 IDWriteFontFile_Release(file);
4664 count = IDWriteFontFace_GetGlyphCount(fontface);
4665 ok(count == 8, "got %u\n", count);
4667 IDWriteFontFace_Release(fontface);
4668 ref = IDWriteFactory_Release(factory);
4669 ok(ref == 0, "factory not released, %u\n", ref);
4670 DELETE_FONTFILE(path);
4673 static void test_GetKerningPairAdjustments(void)
4675 IDWriteFontFace1 *fontface1;
4676 IDWriteFontFace *fontface;
4677 IDWriteFactory *factory;
4678 IDWriteFontFile *file;
4679 WCHAR *path;
4680 HRESULT hr;
4681 ULONG ref;
4683 path = create_testfontfile(test_fontfile);
4684 factory = create_factory();
4686 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4687 ok(hr == S_OK, "got 0x%08x\n", hr);
4689 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4690 ok(hr == S_OK, "got 0x%08x\n", hr);
4691 IDWriteFontFile_Release(file);
4693 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4694 if (hr == S_OK) {
4695 INT32 adjustments[1];
4697 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 0, NULL, NULL);
4698 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
4700 if (0) /* crashes on native */
4701 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, NULL);
4703 adjustments[0] = 1;
4704 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, adjustments);
4705 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4706 ok(adjustments[0] == 0, "got %d\n", adjustments[0]);
4708 IDWriteFontFace1_Release(fontface1);
4710 else
4711 win_skip("GetKerningPairAdjustments() is not supported.\n");
4713 IDWriteFontFace_Release(fontface);
4714 ref = IDWriteFactory_Release(factory);
4715 ok(ref == 0, "factory not released, %u\n", ref);
4716 DELETE_FONTFILE(path);
4719 static void test_CreateRenderingParams(void)
4721 IDWriteRenderingParams2 *params2;
4722 IDWriteRenderingParams1 *params1;
4723 IDWriteRenderingParams *params;
4724 DWRITE_RENDERING_MODE mode;
4725 IDWriteFactory3 *factory3;
4726 IDWriteFactory *factory;
4727 HRESULT hr;
4728 ULONG ref;
4730 factory = create_factory();
4732 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
4733 DWRITE_RENDERING_MODE_DEFAULT, &params);
4734 ok(hr == S_OK, "got 0x%08x\n", hr);
4736 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams1, (void**)&params1);
4737 if (hr == S_OK) {
4738 FLOAT enhcontrast;
4740 /* test what enhanced contrast setting set by default to */
4741 enhcontrast = IDWriteRenderingParams1_GetGrayscaleEnhancedContrast(params1);
4742 ok(enhcontrast == 1.0, "got %.2f\n", enhcontrast);
4743 IDWriteRenderingParams1_Release(params1);
4745 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
4746 if (hr == S_OK) {
4747 DWRITE_GRID_FIT_MODE gridfit;
4749 /* default gridfit mode */
4750 gridfit = IDWriteRenderingParams2_GetGridFitMode(params2);
4751 ok(gridfit == DWRITE_GRID_FIT_MODE_DEFAULT, "got %d\n", gridfit);
4753 IDWriteRenderingParams2_Release(params2);
4755 else
4756 win_skip("IDWriteRenderingParams2 not supported.\n");
4758 else
4759 win_skip("IDWriteRenderingParams1 not supported.\n");
4761 IDWriteRenderingParams_Release(params);
4763 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
4764 ok(hr == S_OK, "got 0x%08x\n", hr);
4766 mode = IDWriteRenderingParams_GetRenderingMode(params);
4767 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
4768 IDWriteRenderingParams_Release(params);
4770 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
4771 if (hr == S_OK) {
4772 IDWriteRenderingParams3 *params3;
4774 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
4775 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_DEFAULT, &params3);
4776 ok(hr == S_OK, "got 0x%08x\n", hr);
4778 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
4779 ok(hr == S_OK, "got 0x%08x\n", hr);
4781 mode = IDWriteRenderingParams_GetRenderingMode(params);
4782 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
4784 IDWriteRenderingParams_Release(params);
4785 IDWriteRenderingParams3_Release(params3);
4786 IDWriteFactory3_Release(factory3);
4788 else
4789 win_skip("IDWriteRenderingParams3 not supported.\n");
4791 ref = IDWriteFactory_Release(factory);
4792 ok(ref == 0, "factory not released, %u\n", ref);
4795 static void test_CreateGlyphRunAnalysis(void)
4797 static const DWRITE_RENDERING_MODE rendermodes[] = {
4798 DWRITE_RENDERING_MODE_ALIASED,
4799 DWRITE_RENDERING_MODE_GDI_CLASSIC,
4800 DWRITE_RENDERING_MODE_GDI_NATURAL,
4801 DWRITE_RENDERING_MODE_NATURAL,
4802 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
4805 IDWriteGlyphRunAnalysis *analysis, *analysis2;
4806 IDWriteRenderingParams *params;
4807 IDWriteFactory3 *factory3;
4808 IDWriteFactory2 *factory2;
4809 IDWriteFactory *factory;
4810 DWRITE_GLYPH_RUN run;
4811 IDWriteFontFace *face;
4812 UINT16 glyph, glyphs[10];
4813 FLOAT advances[2];
4814 HRESULT hr;
4815 UINT32 ch;
4816 RECT rect, rect2;
4817 DWRITE_GLYPH_OFFSET offsets[2];
4818 DWRITE_GLYPH_METRICS metrics;
4819 DWRITE_FONT_METRICS fm;
4820 DWRITE_MATRIX m;
4821 ULONG size;
4822 BYTE *bits;
4823 ULONG ref;
4824 int i;
4826 factory = create_factory();
4827 face = create_fontface(factory);
4829 ch = 'A';
4830 glyph = 0;
4831 hr = IDWriteFontFace_GetGlyphIndices(face, &ch, 1, &glyph);
4832 ok(hr == S_OK, "got 0x%08x\n", hr);
4833 ok(glyph > 0, "got %u\n", glyph);
4835 hr = IDWriteFontFace_GetDesignGlyphMetrics(face, &glyph, 1, &metrics, FALSE);
4836 ok(hr == S_OK, "got 0x%08x\n", hr);
4837 advances[0] = metrics.advanceWidth;
4839 offsets[0].advanceOffset = 0.0;
4840 offsets[0].ascenderOffset = 0.0;
4842 run.fontFace = face;
4843 run.fontEmSize = 24.0;
4844 run.glyphCount = 1;
4845 run.glyphIndices = &glyph;
4846 run.glyphAdvances = advances;
4847 run.glyphOffsets = offsets;
4848 run.isSideways = FALSE;
4849 run.bidiLevel = 0;
4851 /* zero ppdip */
4852 analysis = (void*)0xdeadbeef;
4853 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 0.0, NULL,
4854 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4855 0.0, 0.0, &analysis);
4856 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4857 ok(analysis == NULL, "got %p\n", analysis);
4859 /* negative ppdip */
4860 analysis = (void*)0xdeadbeef;
4861 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, -1.0, NULL,
4862 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4863 0.0, 0.0, &analysis);
4864 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4865 ok(analysis == NULL, "got %p\n", analysis);
4867 /* default mode is not allowed */
4868 analysis = (void*)0xdeadbeef;
4869 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4870 DWRITE_RENDERING_MODE_DEFAULT, DWRITE_MEASURING_MODE_NATURAL,
4871 0.0, 0.0, &analysis);
4872 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4873 ok(analysis == NULL, "got %p\n", analysis);
4875 /* outline too */
4876 analysis = (void*)0xdeadbeef;
4877 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4878 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_MEASURING_MODE_NATURAL,
4879 0.0, 0.0, &analysis);
4880 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4881 ok(analysis == NULL, "got %p\n", analysis);
4883 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4884 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4885 0.0, 0.0, &analysis);
4886 ok(hr == S_OK, "got 0x%08x\n", hr);
4888 /* invalid texture type */
4889 memset(&rect, 0xcc, sizeof(rect));
4890 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &rect);
4891 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4892 ok(rect.left == 0 && rect.right == 0 &&
4893 rect.top == 0 && rect.bottom == 0, "unexpected rect\n");
4895 /* check how origin affects bounds */
4896 SetRectEmpty(&rect);
4897 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4898 ok(hr == S_OK, "got 0x%08x\n", hr);
4899 ok(!IsRectEmpty(&rect), "got empty rect\n");
4900 IDWriteGlyphRunAnalysis_Release(analysis);
4902 /* doubled ppdip */
4903 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
4904 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4905 0.0, 0.0, &analysis);
4906 ok(hr == S_OK, "got 0x%08x\n", hr);
4907 SetRectEmpty(&rect2);
4908 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4909 ok(hr == S_OK, "got 0x%08x\n", hr);
4910 ok(rect.right - rect.left < rect2.right - rect2.left, "expected wider rect\n");
4911 ok(rect.bottom - rect.top < rect2.bottom - rect2.top, "expected taller rect\n");
4912 IDWriteGlyphRunAnalysis_Release(analysis);
4914 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4915 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4916 10.0, -5.0, &analysis);
4917 ok(hr == S_OK, "got 0x%08x\n", hr);
4919 SetRectEmpty(&rect2);
4920 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4921 ok(hr == S_OK, "got 0x%08x\n", hr);
4922 ok(!IsRectEmpty(&rect2), "got empty rect\n");
4923 IDWriteGlyphRunAnalysis_Release(analysis);
4925 ok(!EqualRect(&rect, &rect2), "got equal bounds\n");
4926 OffsetRect(&rect, 10, -5);
4927 ok(EqualRect(&rect, &rect2), "got different bounds\n");
4929 for (i = 0; i < sizeof(rendermodes)/sizeof(rendermodes[0]); i++) {
4930 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4931 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
4932 0.0, 0.0, &analysis);
4933 ok(hr == S_OK, "got 0x%08x\n", hr);
4935 if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
4936 SetRectEmpty(&rect);
4937 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4938 ok(hr == S_OK, "got 0x%08x\n", hr);
4939 ok(!IsRectEmpty(&rect), "got empty rect\n");
4941 SetRect(&rect, 0, 0, 1, 1);
4942 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
4943 ok(hr == S_OK, "got 0x%08x\n", hr);
4944 ok(IsRectEmpty(&rect), "unexpected empty rect\n");
4946 else {
4947 SetRect(&rect, 0, 0, 1, 1);
4948 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4949 ok(hr == S_OK, "got 0x%08x\n", hr);
4950 ok(IsRectEmpty(&rect), "got empty rect\n");
4952 SetRectEmpty(&rect);
4953 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
4954 ok(hr == S_OK, "got 0x%08x\n", hr);
4955 ok(!IsRectEmpty(&rect), "got empty rect\n");
4958 IDWriteGlyphRunAnalysis_Release(analysis);
4961 IDWriteFontFace_GetMetrics(run.fontFace, &fm);
4963 /* check bbox for a single glyph run */
4964 for (run.fontEmSize = 1.0; run.fontEmSize <= 100.0; run.fontEmSize += 1.0) {
4965 DWRITE_GLYPH_METRICS gm;
4966 LONG bboxX, bboxY;
4968 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4969 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
4970 0.0, 0.0, &analysis);
4971 ok(hr == S_OK, "got 0x%08x\n", hr);
4973 SetRectEmpty(&rect);
4974 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4975 ok(hr == S_OK, "got 0x%08x\n", hr);
4977 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
4978 DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
4979 ok(hr == S_OK, "got 0x%08x\n", hr);
4981 /* metrics are in design units */
4982 bboxX = (int)floorf((gm.advanceWidth - gm.leftSideBearing - gm.rightSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
4983 bboxY = (int)floorf((gm.advanceHeight - gm.topSideBearing - gm.bottomSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
4985 rect.right -= rect.left;
4986 rect.bottom -= rect.top;
4987 ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %d, from metrics %d\n", run.fontEmSize, rect.right, bboxX);
4988 ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %d, from metrics %d\n", run.fontEmSize, rect.bottom, bboxY);
4990 IDWriteGlyphRunAnalysis_Release(analysis);
4993 /* without offsets */
4994 run.fontFace = face;
4995 run.fontEmSize = 24.0;
4996 run.glyphCount = 1;
4997 run.glyphIndices = &glyph;
4998 run.glyphAdvances = advances;
4999 run.glyphOffsets = NULL;
5000 run.isSideways = FALSE;
5001 run.bidiLevel = 0;
5003 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5004 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5005 0.0, 0.0, &analysis);
5006 ok(hr == S_OK, "got 0x%08x\n", hr);
5008 SetRectEmpty(&rect);
5009 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5010 ok(hr == S_OK, "got 0x%08x\n", hr);
5011 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5013 IDWriteGlyphRunAnalysis_Release(analysis);
5015 /* without explicit advances */
5016 run.fontFace = face;
5017 run.fontEmSize = 24.0;
5018 run.glyphCount = 1;
5019 run.glyphIndices = &glyph;
5020 run.glyphAdvances = NULL;
5021 run.glyphOffsets = NULL;
5022 run.isSideways = FALSE;
5023 run.bidiLevel = 0;
5025 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5026 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5027 0.0, 0.0, &analysis);
5028 ok(hr == S_OK, "got 0x%08x\n", hr);
5030 SetRectEmpty(&rect);
5031 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5032 ok(hr == S_OK, "got 0x%08x\n", hr);
5033 ok(!IsRectEmpty(&rect), "got empty bounds\n");
5035 IDWriteGlyphRunAnalysis_Release(analysis);
5037 /* test that advances are scaled according to ppdip too */
5038 glyphs[0] = glyphs[1] = glyph;
5039 advances[0] = advances[1] = 100.0f;
5040 run.fontFace = face;
5041 run.fontEmSize = 24.0;
5042 run.glyphCount = 2;
5043 run.glyphIndices = glyphs;
5044 run.glyphAdvances = advances;
5045 run.glyphOffsets = NULL;
5046 run.isSideways = FALSE;
5047 run.bidiLevel = 0;
5049 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5050 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5051 0.0, 0.0, &analysis);
5052 ok(hr == S_OK, "got 0x%08x\n", hr);
5054 SetRectEmpty(&rect2);
5055 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5056 ok(hr == S_OK, "got 0x%08x\n", hr);
5057 ok(!IsRectEmpty(&rect2), "got empty bounds\n");
5058 ok(!EqualRect(&rect, &rect2), "got wrong rect2\n");
5059 ok((rect2.right - rect.left) > advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
5060 IDWriteGlyphRunAnalysis_Release(analysis);
5062 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
5063 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5064 0.0, 0.0, &analysis);
5065 ok(hr == S_OK, "got 0x%08x\n", hr);
5067 SetRectEmpty(&rect);
5068 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5069 ok(hr == S_OK, "got 0x%08x\n", hr);
5070 ok((rect.right - rect.left) > 2 * advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
5071 IDWriteGlyphRunAnalysis_Release(analysis);
5073 /* with scaling transform */
5074 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5075 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5076 0.0, 0.0, &analysis);
5077 ok(hr == S_OK, "got 0x%08x\n", hr);
5079 SetRectEmpty(&rect);
5080 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5081 ok(hr == S_OK, "got 0x%08x\n", hr);
5082 ok(!IsRectEmpty(&rect), "got rect width %d\n", rect.right - rect.left);
5083 IDWriteGlyphRunAnalysis_Release(analysis);
5085 memset(&m, 0, sizeof(m));
5086 m.m11 = 2.0;
5087 m.m22 = 1.0;
5088 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5089 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5090 0.0, 0.0, &analysis);
5091 ok(hr == S_OK, "got 0x%08x\n", hr);
5093 SetRectEmpty(&rect2);
5094 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
5095 ok(hr == S_OK, "got 0x%08x\n", hr);
5096 ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %d\n", rect2.right - rect2.left);
5098 /* instances are not reused for same runs */
5099 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
5100 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
5101 0.0, 0.0, &analysis2);
5102 ok(hr == S_OK, "got 0x%08x\n", hr);
5103 ok(analysis2 != analysis, "got %p, previous instance %p\n", analysis2, analysis);
5104 IDWriteGlyphRunAnalysis_Release(analysis2);
5106 IDWriteGlyphRunAnalysis_Release(analysis);
5108 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void **)&factory2) == S_OK) {
5109 FLOAT gamma, contrast, cleartype_level;
5111 /* Invalid antialias mode. */
5112 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5113 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
5114 0.0f, 0.0f, &analysis);
5115 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5117 /* Invalid grid fit mode. */
5118 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5119 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5120 0.0f, 0.0f, &analysis);
5121 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5123 /* Invalid rendering mode. */
5124 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_OUTLINE,
5125 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5126 0.0f, 0.0f, &analysis);
5127 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5129 /* Invalid measuring mode. */
5130 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_ALIASED,
5131 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5132 0.0f, 0.0f, &analysis);
5133 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5135 /* Win8 does not accept default grid fitting mode. */
5136 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
5137 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5138 0.0f, 0.0f, &analysis);
5139 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* Win8 */, "Failed to create analysis, hr %#x.\n", hr);
5140 if (hr == S_OK)
5141 IDWriteGlyphRunAnalysis_Release(analysis);
5143 /* Natural mode, grayscale antialiased. */
5144 hr = IDWriteFactory2_CreateGlyphRunAnalysis(factory2, &run, NULL, DWRITE_RENDERING_MODE_NATURAL,
5145 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5146 0.0f, 0.0f, &analysis);
5147 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
5149 SetRect(&rect, 0, 1, 0, 1);
5150 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5151 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5152 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
5154 SetRectEmpty(&rect);
5155 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5156 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5157 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
5159 size = (rect.right - rect.left) * (rect.bottom - rect.top);
5160 bits = HeapAlloc(GetProcessHeap(), 0, size);
5162 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
5163 ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
5165 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
5166 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
5168 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
5169 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5171 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
5172 todo_wine
5173 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5175 HeapFree(GetProcessHeap(), 0, bits);
5177 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.1f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
5178 DWRITE_RENDERING_MODE_NATURAL, &params);
5179 ok(hr == S_OK, "Failed to create custom parameters, hr %#x.\n", hr);
5181 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &cleartype_level);
5182 ok(hr == S_OK, "Failed to get alpha blend params, hr %#x.\n", hr);
5183 todo_wine
5184 ok(cleartype_level == 0.0f, "Unexpected cleartype level %f.\n", cleartype_level);
5186 IDWriteRenderingParams_Release(params);
5187 IDWriteGlyphRunAnalysis_Release(analysis);
5189 IDWriteFactory2_Release(factory2);
5192 if (IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void **)&factory3) == S_OK) {
5194 /* Invalid antialias mode. */
5195 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
5196 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE + 1,
5197 0.0f, 0.0f, &analysis);
5198 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5200 /* Invalid grid fit mode. */
5201 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
5202 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED + 1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5203 0.0f, 0.0f, &analysis);
5204 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5206 /* Invalid rendering mode. */
5207 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_OUTLINE,
5208 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_ENABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5209 0.0f, 0.0f, &analysis);
5210 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5212 /* Invalid measuring mode. */
5213 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_ALIASED,
5214 DWRITE_MEASURING_MODE_GDI_NATURAL + 1, DWRITE_GRID_FIT_MODE_ENABLED,
5215 DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, 0.0f, 0.0f, &analysis);
5216 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5218 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
5219 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DEFAULT, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5220 0.0f, 0.0f, &analysis);
5221 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
5222 IDWriteGlyphRunAnalysis_Release(analysis);
5224 /* Natural mode, grayscale antialiased. */
5225 hr = IDWriteFactory3_CreateGlyphRunAnalysis(factory3, &run, NULL, DWRITE_RENDERING_MODE1_NATURAL,
5226 DWRITE_MEASURING_MODE_NATURAL, DWRITE_GRID_FIT_MODE_DISABLED, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
5227 0.0f, 0.0f, &analysis);
5228 ok(hr == S_OK, "Failed to create analysis, hr %#x.\n", hr);
5230 SetRect(&rect, 0, 1, 0, 1);
5231 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
5232 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5233 ok(IsRectEmpty(&rect), "Expected empty bbox.\n");
5235 SetRectEmpty(&rect);
5236 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
5237 ok(hr == S_OK, "Failed to get texture bounds, hr %#x.\n", hr);
5238 ok(!IsRectEmpty(&rect), "Unexpected empty bbox.\n");
5240 size = (rect.right - rect.left) * (rect.bottom - rect.top);
5241 bits = HeapAlloc(GetProcessHeap(), 0, size);
5243 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size);
5244 ok(hr == S_OK, "Failed to get alpha texture, hr %#x.\n", hr);
5246 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect, bits, size - 1);
5247 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
5249 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size);
5250 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5252 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, bits, size - 1);
5253 todo_wine
5254 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION, "Unexpected hr %#x.\n", hr);
5256 HeapFree(GetProcessHeap(), 0, bits);
5258 IDWriteGlyphRunAnalysis_Release(analysis);
5260 IDWriteFactory3_Release(factory3);
5263 IDWriteFontFace_Release(face);
5264 ref = IDWriteFactory_Release(factory);
5265 ok(ref == 0, "factory not released, %u\n", ref);
5268 #define round(x) ((int)floor((x) + 0.5))
5270 struct VDMX_Header
5272 WORD version;
5273 WORD numRecs;
5274 WORD numRatios;
5277 struct VDMX_Ratio
5279 BYTE bCharSet;
5280 BYTE xRatio;
5281 BYTE yStartRatio;
5282 BYTE yEndRatio;
5285 struct VDMX_group
5287 WORD recs;
5288 BYTE startsz;
5289 BYTE endsz;
5292 struct VDMX_vTable
5294 WORD yPelHeight;
5295 SHORT yMax;
5296 SHORT yMin;
5299 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
5301 WORD num_ratios, i, group_offset = 0;
5302 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
5303 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
5305 num_ratios = GET_BE_WORD(hdr->numRatios);
5307 for (i = 0; i < num_ratios; i++)
5309 if (!ratios[i].bCharSet) continue;
5311 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
5312 ratios[i].yEndRatio == 0) ||
5313 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
5314 ratios[i].yEndRatio >= dev_y_ratio))
5316 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
5317 break;
5320 if (group_offset)
5321 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
5322 return NULL;
5325 static BOOL get_vdmx_size(const struct VDMX_group *group, int emsize, int *a, int *d)
5327 WORD recs, i;
5328 const struct VDMX_vTable *tables;
5330 if (!group) return FALSE;
5332 recs = GET_BE_WORD(group->recs);
5333 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
5335 tables = (const struct VDMX_vTable *)(group + 1);
5336 for (i = 0; i < recs; i++)
5338 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
5339 if (ppem > emsize)
5341 /* FIXME: Supposed to interpolate */
5342 trace("FIXME interpolate %d\n", emsize);
5343 return FALSE;
5346 if (ppem == emsize)
5348 *a = (SHORT)GET_BE_WORD(tables[i].yMax);
5349 *d = -(SHORT)GET_BE_WORD(tables[i].yMin);
5350 return TRUE;
5353 return FALSE;
5356 static void test_metrics_cmp(FLOAT emsize, const DWRITE_FONT_METRICS *metrics, const DWRITE_FONT_METRICS1 *expected)
5358 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
5359 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
5360 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
5361 emsize, metrics->ascent, expected->ascent);
5362 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
5363 emsize, metrics->descent, expected->descent);
5364 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
5365 emsize, metrics->lineGap, expected->lineGap);
5366 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
5367 emsize, metrics->capHeight, expected->capHeight);
5368 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
5369 emsize, metrics->xHeight, expected->xHeight);
5370 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
5371 emsize, metrics->underlinePosition, expected->underlinePosition);
5372 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
5373 emsize, metrics->underlineThickness, expected->underlineThickness);
5374 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
5375 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
5376 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
5377 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
5380 static void test_metrics1_cmp(FLOAT emsize, const DWRITE_FONT_METRICS1 *metrics, const DWRITE_FONT_METRICS1 *expected)
5382 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
5383 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
5384 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
5385 emsize, metrics->ascent, expected->ascent);
5386 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
5387 emsize, metrics->descent, expected->descent);
5388 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
5389 emsize, metrics->lineGap, expected->lineGap);
5390 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
5391 emsize, metrics->capHeight, expected->capHeight);
5392 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
5393 emsize, metrics->xHeight, expected->xHeight);
5394 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
5395 emsize, metrics->underlinePosition, expected->underlinePosition);
5396 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
5397 emsize, metrics->underlineThickness, expected->underlineThickness);
5398 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
5399 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
5400 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
5401 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
5402 ok(metrics->glyphBoxLeft == expected->glyphBoxLeft, "%.2f box left: got %d expect %d\n",
5403 emsize, metrics->glyphBoxLeft, expected->glyphBoxLeft);
5404 if (0) { /* this is not consistent */
5405 ok(metrics->glyphBoxTop == expected->glyphBoxTop, "%.2f box top: got %d expect %d\n",
5406 emsize, metrics->glyphBoxTop, expected->glyphBoxTop);
5407 ok(metrics->glyphBoxRight == expected->glyphBoxRight, "%.2f box right: got %d expect %d\n",
5408 emsize, metrics->glyphBoxRight, expected->glyphBoxRight);
5410 ok(metrics->glyphBoxBottom == expected->glyphBoxBottom, "%.2f box bottom: got %d expect %d\n",
5411 emsize, metrics->glyphBoxBottom, expected->glyphBoxBottom);
5412 ok(metrics->subscriptPositionX == expected->subscriptPositionX, "%.2f subX: got %d expect %d\n",
5413 emsize, metrics->subscriptPositionX, expected->subscriptPositionX);
5414 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subY: got %d expect %d\n",
5415 emsize, metrics->subscriptPositionY, expected->subscriptPositionY);
5416 ok(metrics->subscriptSizeX == expected->subscriptSizeX, "%.2f subsizeX: got %d expect %d\n",
5417 emsize, metrics->subscriptSizeX, expected->subscriptSizeX);
5418 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subsizeY: got %d expect %d\n",
5419 emsize, metrics->subscriptSizeY, expected->subscriptSizeY);
5420 ok(metrics->superscriptPositionX == expected->superscriptPositionX, "%.2f supX: got %d expect %d\n",
5421 emsize, metrics->superscriptPositionX, expected->superscriptPositionX);
5422 if (0)
5423 ok(metrics->superscriptPositionY == expected->superscriptPositionY, "%.2f supY: got %d expect %d\n",
5424 emsize, metrics->superscriptPositionY, expected->superscriptPositionY);
5425 ok(metrics->superscriptSizeX == expected->superscriptSizeX, "%.2f supsizeX: got %d expect %d\n",
5426 emsize, metrics->superscriptSizeX, expected->superscriptSizeX);
5427 ok(metrics->superscriptSizeY == expected->superscriptSizeY, "%.2f supsizeY: got %d expect %d\n",
5428 emsize, metrics->superscriptSizeY, expected->superscriptSizeY);
5429 ok(metrics->hasTypographicMetrics == expected->hasTypographicMetrics, "%.2f hastypo: got %d expect %d\n",
5430 emsize, metrics->hasTypographicMetrics, expected->hasTypographicMetrics);
5433 struct compatmetrics_test {
5434 DWRITE_MATRIX m;
5435 FLOAT ppdip;
5436 FLOAT emsize;
5439 static struct compatmetrics_test compatmetrics_tests[] = {
5440 { { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0, 5.0 },
5441 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 1.0, 5.0 },
5442 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 2.0, 5.0 },
5443 { { 0.0, 0.0, 0.0, 3.0, 0.0, 0.0 }, 2.0, 5.0 },
5444 { { 0.0, 0.0, 0.0, -3.0, 0.0, 0.0 }, 2.0, 5.0 },
5445 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 2.0, 5.0 },
5446 { { 1.0, 0.0, 0.0, 1.0, 5.0, 0.0 }, 2.0, 5.0 },
5447 { { 1.0, 0.0, 0.0, 1.0, 0.0, 5.0 }, 2.0, 5.0 },
5450 static void get_expected_metrics(IDWriteFontFace *fontface, struct compatmetrics_test *ptr,
5451 DWRITE_FONT_METRICS *expected)
5453 HRESULT hr;
5455 memset(expected, 0, sizeof(*expected));
5456 hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, ptr->ppdip * fabsf(ptr->m.m22) * ptr->emsize, 1.0, NULL, expected);
5457 ok(hr == S_OK, "got %08x\n", hr);
5460 static void test_gdicompat_metrics(IDWriteFontFace *face)
5462 IDWriteFontFace1 *fontface1 = NULL;
5463 HRESULT hr;
5464 DWRITE_FONT_METRICS design_metrics, comp_metrics;
5465 DWRITE_FONT_METRICS1 design_metrics1, expected;
5466 FLOAT emsize, scale;
5467 int ascent, descent;
5468 const struct VDMX_Header *vdmx;
5469 UINT32 vdmx_len;
5470 void *vdmx_ctx;
5471 BOOL exists;
5472 const struct VDMX_group *vdmx_group = NULL;
5473 int i;
5475 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace1, (void**)&fontface1);
5476 if (hr != S_OK)
5477 win_skip("gdi compatible DWRITE_FONT_METRICS1 are not supported.\n");
5479 if (fontface1) {
5480 IDWriteFontFace1_GetMetrics(fontface1, &design_metrics1);
5481 memcpy(&design_metrics, &design_metrics1, sizeof(design_metrics));
5483 else
5484 IDWriteFontFace_GetMetrics(face, &design_metrics);
5486 hr = IDWriteFontFace_TryGetFontTable(face, MS_VDMX_TAG, (const void **)&vdmx,
5487 &vdmx_len, &vdmx_ctx, &exists);
5488 if (hr != S_OK || !exists)
5489 vdmx = NULL;
5490 else
5491 vdmx_group = find_vdmx_group(vdmx);
5493 /* negative emsize */
5494 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5495 memset(&expected, 0, sizeof(expected));
5496 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, -10.0, 1.0, NULL, &comp_metrics);
5497 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5498 test_metrics_cmp(0.0, &comp_metrics, &expected);
5500 /* zero emsize */
5501 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5502 memset(&expected, 0, sizeof(expected));
5503 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 0.0, 1.0, NULL, &comp_metrics);
5504 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5505 test_metrics_cmp(0.0, &comp_metrics, &expected);
5507 /* zero pixels per dip */
5508 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5509 memset(&expected, 0, sizeof(expected));
5510 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, 0.0, NULL, &comp_metrics);
5511 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5512 test_metrics_cmp(5.0, &comp_metrics, &expected);
5514 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
5515 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, -1.0, NULL, &comp_metrics);
5516 ok(hr == E_INVALIDARG, "got %08x\n", hr);
5517 test_metrics_cmp(5.0, &comp_metrics, &expected);
5519 for (i = 0; i < sizeof(compatmetrics_tests)/sizeof(compatmetrics_tests[0]); i++) {
5520 struct compatmetrics_test *ptr = &compatmetrics_tests[i];
5522 get_expected_metrics(face, ptr, (DWRITE_FONT_METRICS*)&expected);
5523 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, ptr->emsize, ptr->ppdip, &ptr->m, &comp_metrics);
5524 ok(hr == S_OK, "got %08x\n", hr);
5525 test_metrics_cmp(ptr->emsize, &comp_metrics, &expected);
5528 for (emsize = 5; emsize <= design_metrics.designUnitsPerEm; emsize++)
5530 DWRITE_FONT_METRICS1 comp_metrics1, expected;
5532 if (fontface1) {
5533 hr = IDWriteFontFace1_GetGdiCompatibleMetrics(fontface1, emsize, 1.0, NULL, &comp_metrics1);
5534 ok(hr == S_OK, "got %08x\n", hr);
5536 else {
5537 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, emsize, 1.0, NULL, &comp_metrics);
5538 ok(hr == S_OK, "got %08x\n", hr);
5541 scale = emsize / design_metrics.designUnitsPerEm;
5542 if (!get_vdmx_size(vdmx_group, emsize, &ascent, &descent))
5544 ascent = round(design_metrics.ascent * scale);
5545 descent = round(design_metrics.descent * scale);
5548 expected.designUnitsPerEm = design_metrics.designUnitsPerEm;
5549 expected.ascent = round(ascent / scale );
5550 expected.descent = round(descent / scale );
5551 expected.lineGap = round(round(design_metrics.lineGap * scale) / scale);
5552 expected.capHeight = round(round(design_metrics.capHeight * scale) / scale);
5553 expected.xHeight = round(round(design_metrics.xHeight * scale) / scale);
5554 expected.underlinePosition = round(round(design_metrics.underlinePosition * scale) / scale);
5555 expected.underlineThickness = round(round(design_metrics.underlineThickness * scale) / scale);
5556 expected.strikethroughPosition = round(round(design_metrics.strikethroughPosition * scale) / scale);
5557 expected.strikethroughThickness = round(round(design_metrics.strikethroughThickness * scale) / scale);
5559 if (fontface1) {
5560 expected.glyphBoxLeft = round(round(design_metrics1.glyphBoxLeft * scale) / scale);
5562 if (0) { /* those two fail on Tahoma and Win7 */
5563 expected.glyphBoxTop = round(round(design_metrics1.glyphBoxTop * scale) / scale);
5564 expected.glyphBoxRight = round(round(design_metrics1.glyphBoxRight * scale) / scale);
5566 expected.glyphBoxBottom = round(round(design_metrics1.glyphBoxBottom * scale) / scale);
5567 expected.subscriptPositionX = round(round(design_metrics1.subscriptPositionX * scale) / scale);
5568 expected.subscriptPositionY = round(round(design_metrics1.subscriptPositionY * scale) / scale);
5569 expected.subscriptSizeX = round(round(design_metrics1.subscriptSizeX * scale) / scale);
5570 expected.subscriptSizeY = round(round(design_metrics1.subscriptSizeY * scale) / scale);
5571 expected.superscriptPositionX = round(round(design_metrics1.superscriptPositionX * scale) / scale);
5572 if (0) /* this fails for 3 emsizes, Tahoma from [5, 2048] range */ {
5573 expected.superscriptPositionY = round(round(design_metrics1.superscriptPositionY * scale) / scale);
5575 expected.superscriptSizeX = round(round(design_metrics1.superscriptSizeX * scale) / scale);
5576 expected.superscriptSizeY = round(round(design_metrics1.superscriptSizeY * scale) / scale);
5577 expected.hasTypographicMetrics = design_metrics1.hasTypographicMetrics;
5579 test_metrics1_cmp(emsize, &comp_metrics1, &expected);
5581 else
5582 test_metrics_cmp(emsize, &comp_metrics, &expected);
5586 if (fontface1)
5587 IDWriteFontFace1_Release(fontface1);
5588 if (vdmx) IDWriteFontFace_ReleaseFontTable(face, vdmx_ctx);
5591 static void test_GetGdiCompatibleMetrics(void)
5593 IDWriteFactory *factory;
5594 IDWriteFont *font;
5595 IDWriteFontFace *fontface;
5596 HRESULT hr;
5597 ULONG ref;
5599 factory = create_factory();
5601 font = get_font(factory, tahomaW, DWRITE_FONT_STYLE_NORMAL);
5602 hr = IDWriteFont_CreateFontFace(font, &fontface);
5603 ok(hr == S_OK, "got 0x%08x\n", hr);
5604 IDWriteFont_Release(font);
5605 test_gdicompat_metrics(fontface);
5606 IDWriteFontFace_Release(fontface);
5608 font = get_font(factory, arialW, DWRITE_FONT_STYLE_NORMAL);
5609 if (!font)
5610 skip("Skipping tests with Arial\n");
5611 else
5613 hr = IDWriteFont_CreateFontFace(font, &fontface);
5614 ok(hr == S_OK, "got 0x%08x\n", hr);
5615 IDWriteFont_Release(font);
5617 test_gdicompat_metrics(fontface);
5618 IDWriteFontFace_Release(fontface);
5621 ref = IDWriteFactory_Release(factory);
5622 ok(ref == 0, "factory not released, %u\n", ref);
5625 static void get_expected_panose(IDWriteFont1 *font, DWRITE_PANOSE *panose)
5627 IDWriteFontFace *fontface;
5628 const TT_OS2_V2 *tt_os2;
5629 void *os2_context;
5630 UINT32 size;
5631 BOOL exists;
5632 HRESULT hr;
5634 memset(panose, 0, sizeof(*panose));
5636 hr = IDWriteFont1_CreateFontFace(font, &fontface);
5637 ok(hr == S_OK, "got 0x%08x\n", hr);
5639 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void **)&tt_os2, &size, &os2_context, &exists);
5640 ok(hr == S_OK, "got 0x%08x\n", hr);
5642 if (tt_os2) {
5643 memcpy(panose, &tt_os2->panose, sizeof(*panose));
5644 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
5647 IDWriteFontFace_Release(fontface);
5650 static void test_GetPanose(void)
5652 IDWriteFontCollection *syscollection;
5653 IDWriteFactory *factory;
5654 IDWriteFont1 *font1;
5655 IDWriteFont *font;
5656 UINT count, i;
5657 HRESULT hr;
5658 ULONG ref;
5660 factory = create_factory();
5661 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5663 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
5664 IDWriteFont_Release(font);
5666 if (FAILED(hr)) {
5667 ref = IDWriteFactory_Release(factory);
5668 ok(ref == 0, "factory not released, %u\n", ref);
5669 win_skip("GetPanose() is not supported.\n");
5670 return;
5672 IDWriteFont1_Release(font1);
5674 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
5675 ok(hr == S_OK, "got 0x%08x\n", hr);
5676 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
5678 for (i = 0; i < count; i++) {
5679 DWRITE_PANOSE panose, expected_panose;
5680 IDWriteLocalizedStrings *names;
5681 IDWriteFontFace3 *fontface3;
5682 IDWriteFontFace *fontface;
5683 IDWriteFontFamily *family;
5684 IDWriteFont1 *font1;
5685 IDWriteFont *font;
5686 WCHAR nameW[256];
5688 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
5689 ok(hr == S_OK, "got 0x%08x\n", hr);
5691 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
5692 DWRITE_FONT_STYLE_NORMAL, &font);
5693 ok(hr == S_OK, "got 0x%08x\n", hr);
5695 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void **)&font1);
5696 ok(hr == S_OK, "got 0x%08x\n", hr);
5697 IDWriteFont_Release(font);
5699 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
5700 ok(hr == S_OK, "got 0x%08x\n", hr);
5702 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
5704 IDWriteLocalizedStrings_Release(names);
5706 IDWriteFont1_GetPanose(font1, &panose);
5707 get_expected_panose(font1, &expected_panose);
5709 ok(panose.values[0] == expected_panose.values[0], "%s: values[0] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5710 panose.values[0], expected_panose.values[0]);
5711 ok(panose.values[1] == expected_panose.values[1], "%s: values[1] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5712 panose.values[1], expected_panose.values[1]);
5713 ok(panose.values[2] == expected_panose.values[2], "%s: values[2] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5714 panose.values[2], expected_panose.values[2]);
5715 ok(panose.values[3] == expected_panose.values[3], "%s: values[3] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5716 panose.values[3], expected_panose.values[3]);
5717 ok(panose.values[4] == expected_panose.values[4], "%s: values[4] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5718 panose.values[4], expected_panose.values[4]);
5719 ok(panose.values[5] == expected_panose.values[5], "%s: values[5] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5720 panose.values[5], expected_panose.values[5]);
5721 ok(panose.values[6] == expected_panose.values[6], "%s: values[6] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5722 panose.values[6], expected_panose.values[6]);
5723 ok(panose.values[7] == expected_panose.values[7], "%s: values[7] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5724 panose.values[7], expected_panose.values[7]);
5725 ok(panose.values[8] == expected_panose.values[8], "%s: values[8] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5726 panose.values[8], expected_panose.values[8]);
5727 ok(panose.values[9] == expected_panose.values[9], "%s: values[9] %#x, expected %#x.\n", wine_dbgstr_w(nameW),
5728 panose.values[9], expected_panose.values[9]);
5730 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
5731 ok(hr == S_OK, "Failed to create a font face, %#x.\n", hr);
5732 if (IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void **)&fontface3) == S_OK) {
5733 ok(!memcmp(&panose, &expected_panose, sizeof(panose)), "%s: Unexpected panose from font face.\n",
5734 wine_dbgstr_w(nameW));
5735 IDWriteFontFace3_Release(fontface3);
5737 IDWriteFontFace_Release(fontface);
5739 IDWriteFont1_Release(font1);
5740 IDWriteFontFamily_Release(family);
5743 IDWriteFontCollection_Release(syscollection);
5744 ref = IDWriteFactory_Release(factory);
5745 ok(ref == 0, "factory not released, %u\n", ref);
5748 static INT32 get_gdi_font_advance(HDC hdc, FLOAT emsize)
5750 LOGFONTW logfont;
5751 HFONT hfont;
5752 BOOL ret;
5753 ABC abc;
5755 memset(&logfont, 0, sizeof(logfont));
5756 logfont.lfHeight = (LONG)-emsize;
5757 logfont.lfWeight = FW_NORMAL;
5758 logfont.lfQuality = CLEARTYPE_QUALITY;
5759 lstrcpyW(logfont.lfFaceName, tahomaW);
5761 hfont = CreateFontIndirectW(&logfont);
5762 SelectObject(hdc, hfont);
5764 ret = GetCharABCWidthsW(hdc, 'A', 'A', &abc);
5765 ok(ret, "got %d\n", ret);
5767 DeleteObject(hfont);
5769 return abc.abcA + abc.abcB + abc.abcC;
5772 static void test_GetGdiCompatibleGlyphAdvances(void)
5774 IDWriteFontFace1 *fontface1;
5775 IDWriteFontFace *fontface;
5776 IDWriteFactory *factory;
5777 IDWriteFont *font;
5778 HRESULT hr;
5779 HDC hdc;
5780 UINT32 codepoint;
5781 UINT16 glyph;
5782 FLOAT emsize;
5783 DWRITE_FONT_METRICS1 fm;
5784 INT32 advance;
5785 ULONG ref;
5787 factory = create_factory();
5788 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5790 hr = IDWriteFont_CreateFontFace(font, &fontface);
5791 ok(hr == S_OK, "got 0x%08x\n", hr);
5792 IDWriteFont_Release(font);
5794 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
5795 IDWriteFontFace_Release(fontface);
5797 if (hr != S_OK) {
5798 ref = IDWriteFactory_Release(factory);
5799 ok(ref == 0, "factory not released, %u\n", ref);
5800 win_skip("GetGdiCompatibleGlyphAdvances() is not supported\n");
5801 return;
5804 codepoint = 'A';
5805 glyph = 0;
5806 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &glyph);
5807 ok(hr == S_OK, "got 0x%08x\n", hr);
5808 ok(glyph > 0, "got %u\n", glyph);
5810 /* zero emsize */
5811 advance = 1;
5812 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 0.0,
5813 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5814 ok(hr == S_OK, "got 0x%08x\n", hr);
5815 ok(advance == 0, "got %d\n", advance);
5817 /* negative emsize */
5818 advance = 1;
5819 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, -1.0,
5820 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5821 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5822 ok(advance == 0, "got %d\n", advance);
5824 /* zero ppdip */
5825 advance = 1;
5826 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
5827 0.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5828 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5829 ok(advance == 0, "got %d\n", advance);
5831 /* negative ppdip */
5832 advance = 1;
5833 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
5834 -1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5835 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5836 ok(advance == 0, "got %d\n", advance);
5838 IDWriteFontFace1_GetMetrics(fontface1, &fm);
5840 hdc = CreateCompatibleDC(0);
5842 for (emsize = 1.0; emsize <= fm.designUnitsPerEm; emsize += 1.0) {
5843 INT32 gdi_advance;
5845 gdi_advance = get_gdi_font_advance(hdc, emsize);
5846 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emsize,
5847 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5848 ok(hr == S_OK, "got 0x%08x\n", hr);
5850 /* advance is in design units */
5851 advance = (int)floorf(emsize * advance / fm.designUnitsPerEm + 0.5f);
5852 ok((advance - gdi_advance) <= 2, "%.0f: got advance %d, expected %d\n", emsize, advance, gdi_advance);
5855 DeleteObject(hdc);
5857 IDWriteFontFace1_Release(fontface1);
5858 ref = IDWriteFactory_Release(factory);
5859 ok(ref == 0, "factory not released, %u\n", ref);
5862 static WORD get_gasp_flags(IDWriteFontFace *fontface, FLOAT emsize, FLOAT ppdip)
5864 WORD num_recs, version;
5865 const WORD *ptr;
5866 WORD flags = 0;
5867 UINT32 size;
5868 BOOL exists;
5869 void *ctxt;
5870 HRESULT hr;
5872 emsize *= ppdip;
5874 exists = FALSE;
5875 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GASP_TAG,
5876 (const void**)&ptr, &size, &ctxt, &exists);
5877 ok(hr == S_OK, "got 0x%08x\n", hr);
5879 if (!exists)
5880 goto done;
5882 version = GET_BE_WORD( *ptr++ );
5883 num_recs = GET_BE_WORD( *ptr++ );
5884 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
5885 ok(0, "unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
5886 goto done;
5889 while (num_recs--)
5891 flags = GET_BE_WORD( *(ptr + 1) );
5892 if (emsize <= GET_BE_WORD( *ptr )) break;
5893 ptr += 2;
5896 done:
5897 IDWriteFontFace_ReleaseFontTable(fontface, ctxt);
5898 return flags;
5901 #define GASP_GRIDFIT 0x0001
5902 #define GASP_DOGRAY 0x0002
5903 #define GASP_SYMMETRIC_GRIDFIT 0x0004
5904 #define GASP_SYMMETRIC_SMOOTHING 0x0008
5906 static BOOL g_is_vista;
5907 static DWRITE_RENDERING_MODE get_expected_rendering_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
5908 DWRITE_OUTLINE_THRESHOLD threshold)
5910 static const FLOAT aa_threshold = 100.0f;
5911 static const FLOAT a_threshold = 350.0f;
5912 static const FLOAT naturalemsize = 20.0f;
5913 FLOAT v;
5915 /* outline threshold */
5916 if (g_is_vista)
5917 v = mode == DWRITE_MEASURING_MODE_NATURAL ? aa_threshold : a_threshold;
5918 else
5919 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
5921 if (emsize >= v)
5922 return DWRITE_RENDERING_MODE_OUTLINE;
5924 switch (mode)
5926 case DWRITE_MEASURING_MODE_NATURAL:
5927 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (emsize <= naturalemsize))
5928 return DWRITE_RENDERING_MODE_NATURAL;
5929 else
5930 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
5931 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5932 return DWRITE_RENDERING_MODE_GDI_CLASSIC;
5933 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5934 return DWRITE_RENDERING_MODE_GDI_NATURAL;
5935 default:
5939 /* should be unreachable */
5940 return DWRITE_RENDERING_MODE_DEFAULT;
5943 static DWRITE_GRID_FIT_MODE get_expected_gridfit_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
5944 DWRITE_OUTLINE_THRESHOLD threshold)
5946 static const FLOAT aa_threshold = 100.0f;
5947 static const FLOAT a_threshold = 350.0f;
5948 FLOAT v;
5950 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
5951 if (emsize >= v)
5952 return DWRITE_GRID_FIT_MODE_DISABLED;
5954 if (mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
5955 return DWRITE_GRID_FIT_MODE_ENABLED;
5957 return (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
5960 struct recommendedmode_test
5962 DWRITE_MEASURING_MODE measuring;
5963 DWRITE_OUTLINE_THRESHOLD threshold;
5966 static const struct recommendedmode_test recmode_tests[] = {
5967 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5968 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5969 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5972 static const struct recommendedmode_test recmode_tests1[] = {
5973 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5974 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5975 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5976 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5977 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5978 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5981 static void test_GetRecommendedRenderingMode(void)
5983 IDWriteRenderingParams *params;
5984 IDWriteFontFace3 *fontface3;
5985 IDWriteFontFace2 *fontface2;
5986 IDWriteFontFace1 *fontface1;
5987 IDWriteFontFace *fontface;
5988 DWRITE_RENDERING_MODE mode;
5989 IDWriteFactory *factory;
5990 FLOAT emsize;
5991 HRESULT hr;
5992 ULONG ref;
5994 factory = create_factory();
5995 fontface = create_fontface(factory);
5997 fontface1 = NULL;
5998 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5999 if (hr != S_OK)
6000 win_skip("IDWriteFontFace1::GetRecommendedRenderingMode() is not supported.\n");
6002 fontface2 = NULL;
6003 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6004 if (hr != S_OK)
6005 win_skip("IDWriteFontFace2::GetRecommendedRenderingMode() is not supported.\n");
6007 fontface3 = NULL;
6008 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
6009 if (hr != S_OK)
6010 win_skip("IDWriteFontFace3::GetRecommendedRenderingMode() is not supported.\n");
6012 if (0) /* crashes on native */
6013 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6014 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, NULL);
6016 mode = 10;
6017 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
6018 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode);
6019 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6020 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
6022 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
6023 ok(hr == S_OK, "got 0x%08x\n", hr);
6025 /* detect old dwrite version, that is using higher threshold value */
6026 g_is_vista = fontface1 == NULL;
6028 for (emsize = 1.0; emsize < 500.0; emsize += 1.0) {
6029 DWRITE_RENDERING_MODE expected;
6030 FLOAT ppdip;
6031 WORD gasp;
6032 int i;
6034 for (i = 0; i < sizeof(recmode_tests)/sizeof(recmode_tests[0]); i++) {
6035 ppdip = 1.0f;
6036 mode = 10;
6037 gasp = get_gasp_flags(fontface, emsize, ppdip);
6038 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6039 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6040 ok(hr == S_OK, "got 0x%08x\n", hr);
6041 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6043 /* some ppdip variants */
6044 ppdip = 0.5f;
6045 mode = 10;
6046 gasp = get_gasp_flags(fontface, emsize, ppdip);
6047 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6048 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6049 ok(hr == S_OK, "got 0x%08x\n", hr);
6050 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6052 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6053 Win8 and Win10 handle this as expected. */
6054 if (emsize > 20.0f) {
6055 ppdip = 1.5f;
6056 mode = 10;
6057 gasp = get_gasp_flags(fontface, emsize, ppdip);
6058 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6059 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6060 ok(hr == S_OK, "got 0x%08x\n", hr);
6061 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6063 ppdip = 2.0f;
6064 mode = 10;
6065 gasp = get_gasp_flags(fontface, emsize, ppdip);
6066 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
6067 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
6068 ok(hr == S_OK, "got 0x%08x\n", hr);
6069 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
6073 /* IDWriteFontFace1 offers another variant of this method */
6074 if (fontface1) {
6075 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
6076 FLOAT dpi;
6078 ppdip = 1.0f;
6079 dpi = 96.0f * ppdip;
6080 mode = 10;
6081 gasp = get_gasp_flags(fontface, emsize, ppdip);
6082 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6083 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6084 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6085 ok(hr == S_OK, "got 0x%08x\n", hr);
6086 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6088 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
6089 Win8 and Win10 handle this as expected. */
6090 if (emsize > 20.0f) {
6091 ppdip = 2.0f;
6092 dpi = 96.0f * ppdip;
6093 mode = 10;
6094 gasp = get_gasp_flags(fontface, emsize, ppdip);
6095 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6096 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6097 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6098 ok(hr == S_OK, "got 0x%08x\n", hr);
6099 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6101 ppdip = 0.5f;
6102 dpi = 96.0f * ppdip;
6103 mode = 10;
6104 gasp = get_gasp_flags(fontface, emsize, ppdip);
6105 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6106 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
6107 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6108 ok(hr == S_OK, "got 0x%08x\n", hr);
6109 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6111 /* try different dpis for X and Y direction */
6112 ppdip = 1.0f;
6113 dpi = 96.0f * ppdip;
6114 mode = 10;
6115 gasp = get_gasp_flags(fontface, emsize, ppdip);
6116 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6117 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6118 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6119 ok(hr == S_OK, "got 0x%08x\n", hr);
6120 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6122 ppdip = 1.0f;
6123 dpi = 96.0f * ppdip;
6124 mode = 10;
6125 gasp = get_gasp_flags(fontface, emsize, ppdip);
6126 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6127 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
6128 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6129 ok(hr == S_OK, "got 0x%08x\n", hr);
6130 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6132 ppdip = 2.0f;
6133 dpi = 96.0f * ppdip;
6134 mode = 10;
6135 gasp = get_gasp_flags(fontface, emsize, ppdip);
6136 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6137 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
6138 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6139 ok(hr == S_OK, "got 0x%08x\n", hr);
6140 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6142 ppdip = 2.0f;
6143 dpi = 96.0f * ppdip;
6144 mode = 10;
6145 gasp = get_gasp_flags(fontface, emsize, ppdip);
6146 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6147 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
6148 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
6149 ok(hr == S_OK, "got 0x%08x\n", hr);
6150 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
6155 /* IDWriteFontFace2 - another one */
6156 if (fontface2) {
6157 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
6159 gasp = get_gasp_flags(fontface, emsize, 1.0f);
6160 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
6161 mode = 10;
6162 expected = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6163 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6164 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, emsize, 96.0f, 96.0f,
6165 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode, &gridfit);
6166 ok(hr == S_OK, "got 0x%08x\n", hr);
6167 ok(mode == expected, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode, gasp, expected);
6168 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
6169 gasp, expected_gridfit);
6173 /* IDWriteFontFace3 - and another one */
6174 if (fontface3) {
6175 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
6176 DWRITE_RENDERING_MODE1 mode1, expected1;
6178 gasp = get_gasp_flags(fontface, emsize, 1.0f);
6179 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
6180 mode1 = 10;
6181 expected1 = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6182 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
6183 hr = IDWriteFontFace3_GetRecommendedRenderingMode(fontface3, emsize, 96.0f, 96.0f,
6184 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode1, &gridfit);
6185 ok(hr == S_OK, "got 0x%08x\n", hr);
6186 ok(mode1 == expected1, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode1, gasp, expected1);
6187 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
6188 gasp, expected_gridfit);
6193 IDWriteRenderingParams_Release(params);
6195 /* test how parameters override returned modes */
6196 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
6197 DWRITE_RENDERING_MODE_GDI_CLASSIC, &params);
6198 ok(hr == S_OK, "got 0x%08x\n", hr);
6200 mode = 10;
6201 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode);
6202 ok(hr == S_OK, "got 0x%08x\n", hr);
6203 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
6205 IDWriteRenderingParams_Release(params);
6207 if (fontface2) {
6208 IDWriteRenderingParams2 *params2;
6209 IDWriteFactory2 *factory2;
6210 DWRITE_GRID_FIT_MODE gridfit;
6212 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
6213 ok(hr == S_OK, "got 0x%08x\n", hr);
6215 hr = IDWriteFactory2_CreateCustomRenderingParams(factory2, 1.0, 0.0, 0.0, 0.5, DWRITE_PIXEL_GEOMETRY_FLAT,
6216 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_GRID_FIT_MODE_ENABLED, &params2);
6217 ok(hr == S_OK, "got 0x%08x\n", hr);
6219 mode = 10;
6220 gridfit = 10;
6221 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
6222 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6223 NULL, &mode, &gridfit);
6224 ok(hr == S_OK, "got 0x%08x\n", hr);
6225 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
6226 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6228 mode = 10;
6229 gridfit = 10;
6230 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
6231 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6232 (IDWriteRenderingParams*)params2, &mode, &gridfit);
6233 ok(hr == S_OK, "got 0x%08x\n", hr);
6234 ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode);
6235 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6237 IDWriteRenderingParams2_Release(params2);
6238 IDWriteFactory2_Release(factory2);
6241 if (fontface3) {
6242 IDWriteRenderingParams3 *params3;
6243 IDWriteRenderingParams2 *params2;
6244 IDWriteRenderingParams *params;
6245 IDWriteFactory3 *factory3;
6246 DWRITE_GRID_FIT_MODE gridfit;
6247 DWRITE_RENDERING_MODE1 mode1;
6249 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
6250 ok(hr == S_OK, "got 0x%08x\n", hr);
6252 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 0.5f, DWRITE_PIXEL_GEOMETRY_FLAT,
6253 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_ENABLED, &params3);
6254 ok(hr == S_OK, "got 0x%08x\n", hr);
6256 mode1 = IDWriteRenderingParams3_GetRenderingMode1(params3);
6257 ok(mode1 == DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, "got %d\n", mode1);
6259 mode = IDWriteRenderingParams3_GetRenderingMode(params3);
6260 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6262 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
6263 ok(hr == S_OK, "got 0x%08x\n", hr);
6264 ok(params == (IDWriteRenderingParams*)params3, "got %p, %p\n", params3, params);
6265 mode = IDWriteRenderingParams_GetRenderingMode(params);
6266 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6267 IDWriteRenderingParams_Release(params);
6269 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams2, (void**)&params2);
6270 ok(hr == S_OK, "got 0x%08x\n", hr);
6271 ok(params2 == (IDWriteRenderingParams2*)params3, "got %p, %p\n", params3, params2);
6272 mode = IDWriteRenderingParams2_GetRenderingMode(params2);
6273 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6274 IDWriteRenderingParams2_Release(params2);
6276 mode = 10;
6277 gridfit = 10;
6278 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
6279 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6280 NULL, &mode, &gridfit);
6281 ok(hr == S_OK, "got 0x%08x\n", hr);
6282 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
6283 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6285 mode = 10;
6286 gridfit = 10;
6287 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
6288 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6289 (IDWriteRenderingParams*)params3, &mode, &gridfit);
6290 ok(hr == S_OK, "got 0x%08x\n", hr);
6291 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
6292 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
6294 IDWriteRenderingParams3_Release(params3);
6295 IDWriteFactory3_Release(factory3);
6298 if (fontface3)
6299 IDWriteFontFace3_Release(fontface3);
6300 if (fontface2)
6301 IDWriteFontFace2_Release(fontface2);
6302 if (fontface1)
6303 IDWriteFontFace1_Release(fontface1);
6304 IDWriteFontFace_Release(fontface);
6305 ref = IDWriteFactory_Release(factory);
6306 ok(ref == 0, "factory not released, %u\n", ref);
6309 static inline BOOL float_eq(FLOAT left, FLOAT right)
6311 int x = *(int *)&left;
6312 int y = *(int *)&right;
6314 if (x < 0)
6315 x = INT_MIN - x;
6316 if (y < 0)
6317 y = INT_MIN - y;
6319 return abs(x - y) <= 8;
6322 static void test_GetAlphaBlendParams(void)
6324 static const DWRITE_RENDERING_MODE rendermodes[] = {
6325 DWRITE_RENDERING_MODE_ALIASED,
6326 DWRITE_RENDERING_MODE_GDI_CLASSIC,
6327 DWRITE_RENDERING_MODE_GDI_NATURAL,
6328 DWRITE_RENDERING_MODE_NATURAL,
6329 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
6332 IDWriteGlyphRunAnalysis *analysis;
6333 FLOAT gamma, contrast, ctlevel;
6334 IDWriteRenderingParams *params;
6335 DWRITE_GLYPH_METRICS metrics;
6336 DWRITE_GLYPH_OFFSET offset;
6337 IDWriteFontFace *fontface;
6338 IDWriteFactory *factory;
6339 DWRITE_GLYPH_RUN run;
6340 FLOAT advance, expected_gdi_gamma;
6341 UINT value = 0;
6342 UINT16 glyph;
6343 UINT32 ch, i;
6344 HRESULT hr;
6345 ULONG ref;
6346 BOOL ret;
6348 factory = create_factory();
6349 fontface = create_fontface(factory);
6351 ch = 'A';
6352 glyph = 0;
6353 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
6354 ok(hr == S_OK, "got 0x%08x\n", hr);
6355 ok(glyph > 0, "got %u\n", glyph);
6357 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
6358 ok(hr == S_OK, "got 0x%08x\n", hr);
6359 advance = metrics.advanceWidth;
6361 offset.advanceOffset = 0.0;
6362 offset.ascenderOffset = 0.0;
6364 run.fontFace = fontface;
6365 run.fontEmSize = 24.0;
6366 run.glyphCount = 1;
6367 run.glyphIndices = &glyph;
6368 run.glyphAdvances = &advance;
6369 run.glyphOffsets = &offset;
6370 run.isSideways = FALSE;
6371 run.bidiLevel = 0;
6373 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.9, 0.3, 0.1, DWRITE_PIXEL_GEOMETRY_RGB,
6374 DWRITE_RENDERING_MODE_DEFAULT, &params);
6375 ok(hr == S_OK, "got 0x%08x\n", hr);
6377 value = 0;
6378 ret = SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
6379 ok(ret, "got %d\n", ret);
6380 expected_gdi_gamma = (FLOAT)(value / 1000.0);
6382 for (i = 0; i < sizeof(rendermodes)/sizeof(rendermodes[0]); i++) {
6383 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
6384 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
6385 0.0, 0.0, &analysis);
6386 ok(hr == S_OK, "got 0x%08x\n", hr);
6388 gamma = contrast = ctlevel = -1.0;
6389 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, NULL, &gamma, &contrast, &ctlevel);
6390 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6391 ok(gamma == -1.0, "got %.2f\n", gamma);
6392 ok(contrast == -1.0, "got %.2f\n", contrast);
6393 ok(ctlevel == -1.0, "got %.2f\n", ctlevel);
6395 gamma = contrast = ctlevel = -1.0;
6396 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &ctlevel);
6397 ok(hr == S_OK, "got 0x%08x\n", hr);
6399 if (rendermodes[i] == DWRITE_RENDERING_MODE_GDI_CLASSIC || rendermodes[i] == DWRITE_RENDERING_MODE_GDI_NATURAL) {
6400 ok(float_eq(gamma, expected_gdi_gamma), "got %.2f, expected %.2f\n", gamma, expected_gdi_gamma);
6401 ok(contrast == 0.0f, "got %.2f\n", contrast);
6402 ok(ctlevel == 1.0f, "got %.2f\n", ctlevel);
6404 else {
6405 ok(gamma == 0.9f, "got %.2f\n", gamma);
6406 ok(contrast == 0.3f, "got %.2f\n", contrast);
6407 ok(ctlevel == 0.1f, "got %.2f\n", ctlevel);
6410 IDWriteGlyphRunAnalysis_Release(analysis);
6413 IDWriteRenderingParams_Release(params);
6414 IDWriteFontFace_Release(fontface);
6415 ref = IDWriteFactory_Release(factory);
6416 ok(ref == 0, "factory not released, %u\n", ref);
6419 static void test_CreateAlphaTexture(void)
6421 IDWriteGlyphRunAnalysis *analysis;
6422 DWRITE_GLYPH_METRICS metrics;
6423 DWRITE_GLYPH_OFFSET offset;
6424 IDWriteFontFace *fontface;
6425 IDWriteFactory *factory;
6426 DWRITE_GLYPH_RUN run;
6427 UINT32 ch, size;
6428 BYTE buff[1024];
6429 RECT bounds, r;
6430 FLOAT advance;
6431 UINT16 glyph;
6432 HRESULT hr;
6433 ULONG ref;
6435 factory = create_factory();
6436 fontface = create_fontface(factory);
6438 ch = 'A';
6439 glyph = 0;
6440 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
6441 ok(hr == S_OK, "got 0x%08x\n", hr);
6442 ok(glyph > 0, "got %u\n", glyph);
6444 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
6445 ok(hr == S_OK, "got 0x%08x\n", hr);
6446 advance = metrics.advanceWidth;
6448 offset.advanceOffset = 0.0;
6449 offset.ascenderOffset = 0.0;
6451 run.fontFace = fontface;
6452 run.fontEmSize = 24.0;
6453 run.glyphCount = 1;
6454 run.glyphIndices = &glyph;
6455 run.glyphAdvances = &advance;
6456 run.glyphOffsets = &offset;
6457 run.isSideways = FALSE;
6458 run.bidiLevel = 0;
6460 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
6461 DWRITE_RENDERING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
6462 0.0, 0.0, &analysis);
6463 ok(hr == S_OK, "got 0x%08x\n", hr);
6465 SetRectEmpty(&bounds);
6466 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
6467 ok(hr == S_OK, "got 0x%08x\n", hr);
6468 ok(!IsRectEmpty(&bounds), "got empty rect\n");
6469 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top)*3;
6470 ok(sizeof(buff) >= size, "required %u\n", size);
6472 /* invalid type value */
6473 memset(buff, 0xcf, sizeof(buff));
6474 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &bounds, buff, sizeof(buff));
6475 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6476 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6478 memset(buff, 0xcf, sizeof(buff));
6479 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, 2);
6480 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6481 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6483 /* vista version allows texture type mismatch, mark it broken for now */
6484 memset(buff, 0xcf, sizeof(buff));
6485 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, sizeof(buff));
6486 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
6487 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
6489 memset(buff, 0xcf, sizeof(buff));
6490 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, size-1);
6491 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6492 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6494 IDWriteGlyphRunAnalysis_Release(analysis);
6496 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
6497 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
6498 0.0, 0.0, &analysis);
6499 ok(hr == S_OK, "got 0x%08x\n", hr);
6501 SetRectEmpty(&bounds);
6502 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
6503 ok(hr == S_OK, "got 0x%08x\n", hr);
6504 ok(!IsRectEmpty(&bounds), "got empty rect\n");
6505 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
6506 ok(sizeof(buff) >= size, "required %u\n", size);
6508 memset(buff, 0xcf, sizeof(buff));
6509 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, sizeof(buff));
6510 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6511 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6513 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, NULL, sizeof(buff));
6514 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6516 memset(buff, 0xcf, sizeof(buff));
6517 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, 0);
6518 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6519 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6521 /* buffer size is not enough */
6522 memset(buff, 0xcf, sizeof(buff));
6523 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, size-1);
6524 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6525 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6527 /* request texture for rectangle that doesn't intersect */
6528 memset(buff, 0xcf, sizeof(buff));
6529 r = bounds;
6530 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
6531 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
6532 ok(hr == S_OK, "got 0x%08x\n", hr);
6533 ok(buff[0] == 0, "got %1x\n", buff[0]);
6535 memset(buff, 0xcf, sizeof(buff));
6536 r = bounds;
6537 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
6538 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
6539 ok(hr == S_OK, "got 0x%08x\n", hr);
6540 ok(buff[0] == 0, "got %1x\n", buff[0]);
6542 /* request texture for rectangle that doesn't intersect, small buffer */
6543 memset(buff, 0xcf, sizeof(buff));
6544 r = bounds;
6545 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
6546 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, size-1);
6547 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
6548 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
6550 /* vista version allows texture type mismatch, mark it broken for now */
6551 memset(buff, 0xcf, sizeof(buff));
6552 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, sizeof(buff));
6553 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
6554 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
6556 IDWriteGlyphRunAnalysis_Release(analysis);
6557 IDWriteFontFace_Release(fontface);
6558 ref = IDWriteFactory_Release(factory);
6559 ok(ref == 0, "factory not released, %u\n", ref);
6562 static void test_IsSymbolFont(void)
6564 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
6565 IDWriteFontCollection *collection;
6566 IDWriteFontFace *fontface;
6567 IDWriteFactory *factory;
6568 IDWriteFont *font;
6569 HRESULT hr;
6570 ULONG ref;
6571 BOOL ret;
6573 factory = create_factory();
6575 /* Tahoma */
6576 fontface = create_fontface(factory);
6577 ret = IDWriteFontFace_IsSymbolFont(fontface);
6578 ok(!ret, "got %d\n", ret);
6580 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
6581 ok(hr == S_OK, "got 0x%08x\n", hr);
6583 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font);
6584 ok(hr == S_OK, "got 0x%08x\n", hr);
6586 ret = IDWriteFont_IsSymbolFont(font);
6587 ok(!ret, "got %d\n", ret);
6589 IDWriteFontCollection_Release(collection);
6590 IDWriteFont_Release(font);
6591 IDWriteFontFace_Release(fontface);
6593 /* Symbol */
6594 font = get_font(factory, symbolW, DWRITE_FONT_STYLE_NORMAL);
6595 ret = IDWriteFont_IsSymbolFont(font);
6596 ok(ret, "got %d\n", ret);
6598 hr = IDWriteFont_CreateFontFace(font, &fontface);
6599 ok(hr == S_OK, "got 0x%08x\n", hr);
6600 ret = IDWriteFontFace_IsSymbolFont(fontface);
6601 ok(ret, "got %d\n", ret);
6602 IDWriteFontFace_Release(fontface);
6603 IDWriteFont_Release(font);
6605 ref = IDWriteFactory_Release(factory);
6606 ok(ref == 0, "factory not released, %u\n", ref);
6609 struct CPAL_Header_0
6611 USHORT version;
6612 USHORT numPaletteEntries;
6613 USHORT numPalette;
6614 USHORT numColorRecords;
6615 ULONG offsetFirstColorRecord;
6616 USHORT colorRecordIndices[1];
6619 static void test_GetPaletteEntries(void)
6621 IDWriteFontFace2 *fontface2;
6622 IDWriteFontFace *fontface;
6623 IDWriteFactory *factory;
6624 IDWriteFont *font;
6625 DWRITE_COLOR_F color;
6626 UINT32 palettecount, entrycount, size, colorrecords;
6627 void *ctxt;
6628 const struct CPAL_Header_0 *cpal_header;
6629 HRESULT hr;
6630 BOOL exists;
6631 ULONG ref;
6633 factory = create_factory();
6635 /* Tahoma, no color support */
6636 fontface = create_fontface(factory);
6637 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6638 IDWriteFontFace_Release(fontface);
6639 if (hr != S_OK) {
6640 ref = IDWriteFactory_Release(factory);
6641 ok(ref == 0, "factory not released, %u\n", ref);
6642 win_skip("GetPaletteEntries() is not supported.\n");
6643 return;
6646 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 1, &color);
6647 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6648 IDWriteFontFace2_Release(fontface2);
6650 /* Segoe UI Emoji, with color support */
6651 font = get_font(factory, emojiW, DWRITE_FONT_STYLE_NORMAL);
6652 if (!font) {
6653 ref = IDWriteFactory_Release(factory);
6654 ok(ref == 0, "factory not released, %u\n", ref);
6655 skip("Segoe UI Emoji font not found.\n");
6656 return;
6659 hr = IDWriteFont_CreateFontFace(font, &fontface);
6660 ok(hr == S_OK, "got 0x%08x\n", hr);
6661 IDWriteFont_Release(font);
6663 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6664 ok(hr == S_OK, "got 0x%08x\n", hr);
6665 IDWriteFontFace_Release(fontface);
6667 palettecount = IDWriteFontFace2_GetColorPaletteCount(fontface2);
6668 ok(palettecount >= 1, "got %u\n", palettecount);
6670 entrycount = IDWriteFontFace2_GetPaletteEntryCount(fontface2);
6671 ok(entrycount >= 1, "got %u\n", entrycount);
6673 exists = FALSE;
6674 hr = IDWriteFontFace2_TryGetFontTable(fontface2, MS_CPAL_TAG, (const void**)&cpal_header, &size, &ctxt, &exists);
6675 ok(hr == S_OK, "got 0x%08x\n", hr);
6676 ok(exists, "got %d\n", exists);
6677 colorrecords = GET_BE_WORD(cpal_header->numColorRecords);
6678 ok(colorrecords >= 1, "got %u\n", colorrecords);
6680 /* invalid palette index */
6681 color.r = color.g = color.b = color.a = 123.0;
6682 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, palettecount, 0, 1, &color);
6683 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6684 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6685 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6687 /* invalid entry index */
6688 color.r = color.g = color.b = color.a = 123.0;
6689 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount, 1, &color);
6690 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6691 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6692 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6694 color.r = color.g = color.b = color.a = 123.0;
6695 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount - 1, 1, &color);
6696 ok(hr == S_OK, "got 0x%08x\n", hr);
6697 ok(color.r != 123.0 && color.g != 123.0 && color.b != 123.0 && color.a != 123.0,
6698 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6700 /* zero return length */
6701 color.r = color.g = color.b = color.a = 123.0;
6702 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 0, &color);
6703 ok(hr == S_OK, "got 0x%08x\n", hr);
6704 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6705 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6707 IDWriteFontFace2_Release(fontface2);
6708 ref = IDWriteFactory_Release(factory);
6709 ok(ref == 0, "factory not released, %u\n", ref);
6712 static void test_TranslateColorGlyphRun(void)
6714 IDWriteColorGlyphRunEnumerator *layers;
6715 const DWRITE_COLOR_GLYPH_RUN *colorrun;
6716 IDWriteFontFace2 *fontface2;
6717 IDWriteFontFace *fontface;
6718 IDWriteFactory2 *factory;
6719 DWRITE_GLYPH_RUN run;
6720 UINT32 codepoints[2];
6721 IDWriteFont *font;
6722 UINT16 glyphs[2];
6723 BOOL hasrun;
6724 HRESULT hr;
6725 ULONG ref;
6727 factory = create_factory_iid(&IID_IDWriteFactory2);
6728 if (!factory) {
6729 win_skip("TranslateColorGlyphRun() is not supported.\n");
6730 return;
6733 /* Tahoma, no color support */
6734 fontface = create_fontface((IDWriteFactory *)factory);
6736 codepoints[0] = 'A';
6737 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6738 ok(hr == S_OK, "got 0x%08x\n", hr);
6740 run.fontFace = fontface;
6741 run.fontEmSize = 20.0f;
6742 run.glyphCount = 1;
6743 run.glyphIndices = glyphs;
6744 run.glyphAdvances = NULL;
6745 run.glyphOffsets = NULL;
6746 run.isSideways = FALSE;
6747 run.bidiLevel = 0;
6749 layers = (void*)0xdeadbeef;
6750 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6751 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6752 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6753 ok(layers == NULL, "got %p\n", layers);
6754 IDWriteFontFace_Release(fontface);
6756 /* Segoe UI Emoji, with color support */
6757 font = get_font((IDWriteFactory *)factory, emojiW, DWRITE_FONT_STYLE_NORMAL);
6758 if (!font) {
6759 IDWriteFactory2_Release(factory);
6760 skip("Segoe UI Emoji font not found.\n");
6761 return;
6764 hr = IDWriteFont_CreateFontFace(font, &fontface);
6765 ok(hr == S_OK, "got 0x%08x\n", hr);
6766 IDWriteFont_Release(font);
6768 codepoints[0] = 0x26c4;
6769 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6770 ok(hr == S_OK, "got 0x%08x\n", hr);
6772 run.fontFace = fontface;
6774 layers = NULL;
6775 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6776 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6777 ok(hr == S_OK, "got 0x%08x\n", hr);
6778 ok(layers != NULL, "got %p\n", layers);
6780 for (;;) {
6781 hasrun = FALSE;
6782 hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &hasrun);
6783 ok(hr == S_OK, "got 0x%08x\n", hr);
6785 if (!hasrun)
6786 break;
6788 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
6789 ok(hr == S_OK, "got 0x%08x\n", hr);
6790 ok(colorrun->glyphRun.fontFace != NULL, "got fontface %p\n", colorrun->glyphRun.fontFace);
6791 ok(colorrun->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun->glyphRun.fontEmSize);
6792 ok(colorrun->glyphRun.glyphCount > 0, "got wrong glyph count %u\n", colorrun->glyphRun.glyphCount);
6793 ok(colorrun->glyphRun.glyphIndices != NULL, "got null glyph indices %p\n", colorrun->glyphRun.glyphIndices);
6794 ok(colorrun->glyphRun.glyphAdvances != NULL, "got null glyph advances %p\n", colorrun->glyphRun.glyphAdvances);
6797 /* iterated all way through */
6798 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
6799 ok(hr == E_NOT_VALID_STATE, "got 0x%08x\n", hr);
6801 IDWriteColorGlyphRunEnumerator_Release(layers);
6803 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6804 ok(hr == S_OK, "got 0x%08x\n", hr);
6806 /* invalid palette index */
6807 layers = (void*)0xdeadbeef;
6808 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6809 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2),
6810 &layers);
6811 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6812 ok(layers == NULL, "got %p\n", layers);
6814 layers = NULL;
6815 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6816 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2) - 1,
6817 &layers);
6818 ok(hr == S_OK, "got 0x%08x\n", hr);
6819 IDWriteColorGlyphRunEnumerator_Release(layers);
6821 /* color font, glyph without color info */
6822 codepoints[0] = 'A';
6823 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6824 ok(hr == S_OK, "got 0x%08x\n", hr);
6826 layers = (void*)0xdeadbeef;
6827 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6828 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6829 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6830 ok(layers == NULL, "got %p\n", layers);
6832 /* one glyph with, one without */
6833 codepoints[0] = 'A';
6834 codepoints[1] = 0x26c4;
6836 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 2, glyphs);
6837 ok(hr == S_OK, "got 0x%08x\n", hr);
6839 run.glyphCount = 2;
6841 layers = NULL;
6842 hr = IDWriteFactory2_TranslateColorGlyphRun(factory, 0.0f, 0.0f, &run, NULL,
6843 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6844 ok(hr == S_OK, "got 0x%08x\n", hr);
6845 ok(layers != NULL, "got %p\n", layers);
6846 IDWriteColorGlyphRunEnumerator_Release(layers);
6848 IDWriteFontFace2_Release(fontface2);
6849 IDWriteFontFace_Release(fontface);
6850 ref = IDWriteFactory2_Release(factory);
6851 ok(ref == 0, "factory not released, %u\n", ref);
6854 static void test_HasCharacter(void)
6856 IDWriteFactory3 *factory3;
6857 IDWriteFactory *factory;
6858 IDWriteFont3 *font3;
6859 IDWriteFont *font;
6860 HRESULT hr;
6861 ULONG ref;
6862 BOOL ret;
6864 factory = create_factory();
6866 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6867 ok(font != NULL, "failed to create font\n");
6869 /* Win8 is broken, QI claims to support IDWriteFont3, but in fact it does not */
6870 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
6871 if (hr == S_OK) {
6872 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
6873 ok(hr == S_OK, "got 0x%08x\n", hr);
6875 ret = IDWriteFont3_HasCharacter(font3, 'A');
6876 ok(ret, "got %d\n", ret);
6878 IDWriteFont3_Release(font3);
6879 IDWriteFactory3_Release(factory3);
6881 else
6882 win_skip("IDWriteFont3 is not supported.\n");
6884 IDWriteFont_Release(font);
6885 ref = IDWriteFactory_Release(factory);
6886 ok(ref == 0, "factory not released, %u\n", ref);
6889 static void test_CreateFontFaceReference(void)
6891 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
6892 IDWriteFontFace3 *fontface, *fontface1;
6893 IDWriteFontFaceReference *ref, *ref1;
6894 IDWriteFontFile *file, *file1;
6895 IDWriteFactory3 *factory;
6896 IDWriteFont3 *font3;
6897 IDWriteFont *font;
6898 ULONG refcount;
6899 UINT32 index;
6900 WCHAR *path;
6901 HRESULT hr;
6902 BOOL ret;
6904 factory = create_factory_iid(&IID_IDWriteFactory3);
6905 if (!factory) {
6906 win_skip("CreateFontFaceReference() is not supported.\n");
6907 return;
6910 path = create_testfontfile(test_fontfile);
6912 hr = IDWriteFactory3_CreateFontFaceReference(factory, NULL, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6913 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6915 /* out of range simulation flags */
6916 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, ~0u, &ref);
6917 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6919 /* test file is not a collection, but reference could still be created with non-zero face index */
6920 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6921 ok(hr == S_OK, "got 0x%08x\n", hr);
6923 index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
6924 ok(index == 1, "got %u\n", index);
6926 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
6927 ok(hr == S_OK, "got 0x%08x\n", hr);
6928 IDWriteFontFile_Release(file);
6930 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
6931 todo_wine
6932 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
6934 IDWriteFontFaceReference_Release(ref);
6936 /* path however has to be valid */
6937 hr = IDWriteFactory3_CreateFontFaceReference(factory, dummyW, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6938 todo_wine
6939 ok(hr == DWRITE_E_FILENOTFOUND, "got 0x%08x\n", hr);
6940 if (hr == S_OK)
6941 IDWriteFontFaceReference_Release(ref);
6943 EXPECT_REF(factory, 1);
6944 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6945 ok(hr == S_OK, "got 0x%08x\n", hr);
6946 EXPECT_REF(factory, 2);
6948 /* new file is returned */
6949 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
6950 ok(hr == S_OK, "got 0x%08x\n", hr);
6952 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
6953 ok(hr == S_OK, "got 0x%08x\n", hr);
6954 ok(file != file1, "got %p, previous file %p\n", file1, file);
6956 IDWriteFontFile_Release(file);
6957 IDWriteFontFile_Release(file1);
6959 /* references are not reused */
6960 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
6961 ok(hr == S_OK, "got 0x%08x\n", hr);
6962 ok(ref1 != ref, "got %p, previous ref %p\n", ref1, ref);
6964 /* created fontfaces are cached */
6965 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
6966 ok(hr == S_OK, "got 0x%08x\n", hr);
6968 hr = IDWriteFontFaceReference_CreateFontFace(ref1, &fontface1);
6969 ok(hr == S_OK, "got 0x%08x\n", hr);
6970 ok(fontface == fontface1, "got %p, expected %p\n", fontface1, fontface);
6971 IDWriteFontFace3_Release(fontface);
6972 IDWriteFontFace3_Release(fontface1);
6974 /* reference equality */
6975 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6976 ok(ret, "got %d\n", ret);
6977 IDWriteFontFaceReference_Release(ref1);
6979 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
6980 ok(hr == S_OK, "got 0x%08x\n", hr);
6981 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6982 ok(!ret, "got %d\n", ret);
6983 IDWriteFontFaceReference_Release(ref1);
6985 hr = IDWriteFactory3_CreateFontFaceReference(factory, path, NULL, 0, DWRITE_FONT_SIMULATIONS_BOLD, &ref1);
6986 ok(hr == S_OK, "got 0x%08x\n", hr);
6987 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6988 ok(!ret, "got %d\n", ret);
6989 IDWriteFontFaceReference_Release(ref1);
6991 IDWriteFontFaceReference_Release(ref);
6993 /* create reference from a file */
6994 hr = IDWriteFactory3_CreateFontFileReference(factory, path, NULL, &file);
6995 ok(hr == S_OK, "got 0x%08x\n", hr);
6997 hr = IDWriteFactory3_CreateFontFaceReference_(factory, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6998 ok(hr == S_OK, "got 0x%08x\n", hr);
7000 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
7001 ok(hr == S_OK, "got 0x%08x\n", hr);
7002 ok(file != file1, "got %p, previous file %p\n", file1, file);
7004 IDWriteFontFaceReference_Release(ref);
7005 IDWriteFontFile_Release(file);
7006 IDWriteFontFile_Release(file1);
7008 /* references returned from IDWriteFont3 */
7009 font = get_tahoma_instance((IDWriteFactory *)factory, DWRITE_FONT_STYLE_NORMAL);
7010 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
7011 ok(hr == S_OK, "got 0x%08x\n", hr);
7012 IDWriteFont_Release(font);
7014 hr = IDWriteFont3_GetFontFaceReference(font3, &ref);
7015 ok(hr == S_OK, "got 0x%08x\n", hr);
7017 hr = IDWriteFont3_GetFontFaceReference(font3, &ref1);
7018 ok(hr == S_OK, "got 0x%08x\n", hr);
7019 ok(ref != ref1, "got %p, %p\n", ref1, ref);
7021 IDWriteFontFaceReference_Release(ref);
7022 IDWriteFontFaceReference_Release(ref1);
7024 /* references returned from IDWriteFontFace3 */
7025 hr = IDWriteFont3_CreateFontFace(font3, &fontface);
7026 ok(hr == S_OK, "got 0x%08x\n", hr);
7028 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref);
7029 todo_wine
7030 ok(hr == S_OK, "got 0x%08x\n", hr);
7032 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref1);
7033 todo_wine
7034 ok(hr == S_OK, "got 0x%08x\n", hr);
7035 if (hr == S_OK)
7036 ok(ref == ref1, "got %p, %p\n", ref1, ref);
7038 if (hr == S_OK) {
7039 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface1);
7040 ok(hr == S_OK, "got 0x%08x\n", hr);
7041 ok(fontface1 == fontface, "got %p, %p\n", fontface1, fontface);
7042 IDWriteFontFace3_Release(fontface1);
7044 IDWriteFontFaceReference_Release(ref);
7045 IDWriteFontFaceReference_Release(ref1);
7047 IDWriteFontFace3_Release(fontface);
7048 IDWriteFont3_Release(font3);
7050 refcount = IDWriteFactory3_Release(factory);
7051 ok(refcount == 0, "factory not released, %u\n", refcount);
7052 DELETE_FONTFILE(path);
7055 static void get_expected_fontsig(IDWriteFont *font, FONTSIGNATURE *fontsig)
7057 void *os2_context;
7058 IDWriteFontFace *fontface;
7059 const TT_OS2_V2 *tt_os2;
7060 UINT32 size;
7061 BOOL exists;
7062 HRESULT hr;
7064 memset(fontsig, 0, sizeof(*fontsig));
7066 hr = IDWriteFont_CreateFontFace(font, &fontface);
7067 ok(hr == S_OK, "got 0x%08x\n", hr);
7069 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void**)&tt_os2, &size, &os2_context, &exists);
7070 ok(hr == S_OK, "got 0x%08x\n", hr);
7072 if (tt_os2) {
7073 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
7074 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
7075 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
7076 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
7078 if (GET_BE_WORD(tt_os2->version) == 0) {
7079 fontsig->fsCsb[0] = 0;
7080 fontsig->fsCsb[1] = 0;
7082 else {
7083 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
7084 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
7087 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
7090 IDWriteFontFace_Release(fontface);
7093 static void test_GetFontSignature(void)
7095 IDWriteFontCollection *syscollection;
7096 IDWriteGdiInterop1 *interop1;
7097 IDWriteGdiInterop *interop;
7098 IDWriteFactory *factory;
7099 FONTSIGNATURE fontsig;
7100 UINT count, i;
7101 HRESULT hr;
7102 ULONG ref;
7104 factory = create_factory();
7106 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
7107 ok(hr == S_OK, "got 0x%08x\n", hr);
7109 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
7110 IDWriteGdiInterop_Release(interop);
7111 if (FAILED(hr)) {
7112 win_skip("GetFontSignature() is not supported.\n");
7113 IDWriteGdiInterop_Release(interop);
7114 IDWriteFactory_Release(factory);
7115 return;
7117 ok(hr == S_OK, "got 0x%08x\n", hr);
7119 hr = IDWriteGdiInterop1_GetFontSignature(interop1, NULL, &fontsig);
7120 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
7122 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
7123 ok(hr == S_OK, "got 0x%08x\n", hr);
7124 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
7126 for (i = 0; i < count; i++) {
7127 FONTSIGNATURE expected_signature;
7128 IDWriteLocalizedStrings *names;
7129 IDWriteFontFamily *family;
7130 IDWriteFont *font;
7131 WCHAR nameW[256];
7133 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
7134 ok(hr == S_OK, "got 0x%08x\n", hr);
7136 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
7137 DWRITE_FONT_STYLE_NORMAL, &font);
7138 ok(hr == S_OK, "got 0x%08x\n", hr);
7140 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7141 ok(hr == S_OK, "got 0x%08x\n", hr);
7143 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
7145 IDWriteLocalizedStrings_Release(names);
7147 hr = IDWriteGdiInterop1_GetFontSignature(interop1, font, &fontsig);
7148 ok(hr == S_OK, "got 0x%08x\n", hr);
7150 get_expected_fontsig(font, &expected_signature);
7152 ok(fontsig.fsUsb[0] == expected_signature.fsUsb[0], "%s: fsUsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7153 fontsig.fsUsb[0], expected_signature.fsUsb[0]);
7154 ok(fontsig.fsUsb[1] == expected_signature.fsUsb[1], "%s: fsUsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7155 fontsig.fsUsb[1], expected_signature.fsUsb[1]);
7156 ok(fontsig.fsUsb[2] == expected_signature.fsUsb[2], "%s: fsUsb[2] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7157 fontsig.fsUsb[2], expected_signature.fsUsb[2]);
7158 ok(fontsig.fsUsb[3] == expected_signature.fsUsb[3], "%s: fsUsb[3] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7159 fontsig.fsUsb[3], expected_signature.fsUsb[3]);
7161 ok(fontsig.fsCsb[0] == expected_signature.fsCsb[0], "%s: fsCsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7162 fontsig.fsCsb[0], expected_signature.fsCsb[0]);
7163 ok(fontsig.fsCsb[1] == expected_signature.fsCsb[1], "%s: fsCsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
7164 fontsig.fsCsb[1], expected_signature.fsCsb[1]);
7166 IDWriteFont_Release(font);
7167 IDWriteFontFamily_Release(family);
7170 IDWriteGdiInterop1_Release(interop1);
7171 IDWriteFontCollection_Release(syscollection);
7172 ref = IDWriteFactory_Release(factory);
7173 ok(ref == 0, "factory not released, %u\n", ref);
7176 static void test_font_properties(void)
7178 IDWriteFontFace3 *fontface3;
7179 IDWriteFontFace *fontface;
7180 IDWriteFactory *factory;
7181 DWRITE_FONT_STYLE style;
7182 IDWriteFont *font;
7183 HRESULT hr;
7184 ULONG ref;
7186 factory = create_factory();
7188 /* this creates simulated font */
7189 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
7191 style = IDWriteFont_GetStyle(font);
7192 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
7194 hr = IDWriteFont_CreateFontFace(font, &fontface);
7195 ok(hr == S_OK, "got 0x%08x\n", hr);
7197 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
7198 IDWriteFontFace_Release(fontface);
7199 if (hr == S_OK) {
7200 style = IDWriteFontFace3_GetStyle(fontface3);
7201 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
7203 IDWriteFontFace3_Release(fontface3);
7206 IDWriteFont_Release(font);
7207 ref = IDWriteFactory_Release(factory);
7208 ok(ref == 0, "factory not released, %u\n", ref);
7211 static BOOL has_vertical_glyph_variants(IDWriteFontFace1 *fontface)
7213 const OT_FeatureList *featurelist;
7214 const OT_LookupList *lookup_list;
7215 BOOL exists = FALSE, ret = FALSE;
7216 const GSUB_Header *header;
7217 const void *data;
7218 void *context;
7219 UINT32 size;
7220 HRESULT hr;
7221 UINT16 i;
7223 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
7224 ok(hr == S_OK, "got 0x%08x\n", hr);
7226 if (!exists)
7227 return FALSE;
7229 header = data;
7230 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
7231 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
7233 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
7234 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
7235 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
7236 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
7237 const GSUB_SingleSubstFormat2 *subst2;
7238 const OT_LookupTable *lookup_table;
7239 UINT32 offset;
7241 if (lookup_count == 0)
7242 continue;
7244 for (i = 0; i < lookup_count; i++) {
7245 /* check if lookup is empty */
7246 index = GET_BE_WORD(feature->LookupListIndex[i]);
7247 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
7249 type = GET_BE_WORD(lookup_table->LookupType);
7250 ok(type == 1 || type == 7, "got unexpected lookup type %u\n", type);
7252 count = GET_BE_WORD(lookup_table->SubTableCount);
7253 if (count == 0)
7254 continue;
7256 ok(count > 0, "got unexpected subtable count %u\n", count);
7258 offset = GET_BE_WORD(lookup_table->SubTable[0]);
7259 if (type == 7) {
7260 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
7261 if (GET_BE_WORD(ext->SubstFormat) == 1)
7262 offset += GET_BE_DWORD(ext->ExtensionOffset);
7263 else
7264 ok(0, "Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
7267 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
7268 index = GET_BE_WORD(subst2->SubstFormat);
7269 if (index == 1)
7270 ok(0, "validate Single Substitution Format 1\n");
7271 else if (index == 2) {
7272 /* SimSun-ExtB has 0 glyph count for this substitution */
7273 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
7274 ret = TRUE;
7275 break;
7278 else
7279 ok(0, "unknown Single Substitution Format, %u\n", index);
7284 IDWriteFontFace1_ReleaseFontTable(fontface, context);
7286 return ret;
7289 static void test_HasVerticalGlyphVariants(void)
7291 IDWriteFontCollection *syscollection;
7292 IDWriteFontFace1 *fontface1;
7293 IDWriteFontFace *fontface;
7294 IDWriteFactory *factory;
7295 UINT32 count, i;
7296 HRESULT hr;
7297 ULONG ref;
7299 factory = create_factory();
7300 fontface = create_fontface(factory);
7302 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
7303 IDWriteFontFace_Release(fontface);
7304 if (hr != S_OK) {
7305 win_skip("HasVerticalGlyphVariants() is not supported.\n");
7306 IDWriteFactory_Release(factory);
7307 return;
7309 IDWriteFontFace1_Release(fontface1);
7311 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
7312 ok(hr == S_OK, "got 0x%08x\n", hr);
7313 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
7315 for (i = 0; i < count; i++) {
7316 IDWriteLocalizedStrings *names;
7317 BOOL expected_vert, has_vert;
7318 IDWriteFontFamily *family;
7319 IDWriteFont *font;
7320 WCHAR nameW[256];
7322 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
7323 ok(hr == S_OK, "got 0x%08x\n", hr);
7325 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
7326 DWRITE_FONT_STYLE_NORMAL, &font);
7327 ok(hr == S_OK, "got 0x%08x\n", hr);
7329 hr = IDWriteFont_CreateFontFace(font, &fontface);
7330 ok(hr == S_OK, "got 0x%08x\n", hr);
7332 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
7333 ok(hr == S_OK, "got 0x%08x\n", hr);
7335 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7336 ok(hr == S_OK, "got 0x%08x\n", hr);
7338 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
7340 expected_vert = has_vertical_glyph_variants(fontface1);
7341 has_vert = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
7343 ok(expected_vert == has_vert, "%s: expected vertical feature %d, got %d\n",
7344 wine_dbgstr_w(nameW), expected_vert, has_vert);
7346 IDWriteLocalizedStrings_Release(names);
7347 IDWriteFont_Release(font);
7349 IDWriteFontFace1_Release(fontface1);
7350 IDWriteFontFace_Release(fontface);
7351 IDWriteFontFamily_Release(family);
7354 IDWriteFontCollection_Release(syscollection);
7355 ref = IDWriteFactory_Release(factory);
7356 ok(ref == 0, "factory not released, %u\n", ref);
7359 static void test_HasKerningPairs(void)
7361 IDWriteFontCollection *syscollection;
7362 IDWriteFontFace1 *fontface1;
7363 IDWriteFontFace *fontface;
7364 IDWriteFactory *factory;
7365 UINT32 count, i;
7366 HRESULT hr;
7367 ULONG ref;
7369 factory = create_factory();
7370 fontface = create_fontface(factory);
7372 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
7373 IDWriteFontFace_Release(fontface);
7374 if (hr != S_OK) {
7375 win_skip("HasKerningPairs() is not supported.\n");
7376 IDWriteFactory_Release(factory);
7377 return;
7379 IDWriteFontFace1_Release(fontface1);
7381 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
7382 ok(hr == S_OK, "got 0x%08x\n", hr);
7383 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
7385 for (i = 0; i < count; i++) {
7386 IDWriteLocalizedStrings *names;
7387 BOOL exists, has_kerningpairs;
7388 IDWriteFontFamily *family;
7389 IDWriteFont *font;
7390 WCHAR nameW[256];
7391 const void *data;
7392 void *context;
7393 UINT32 size;
7395 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
7396 ok(hr == S_OK, "got 0x%08x\n", hr);
7398 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
7399 DWRITE_FONT_STYLE_NORMAL, &font);
7400 ok(hr == S_OK, "got 0x%08x\n", hr);
7402 hr = IDWriteFont_CreateFontFace(font, &fontface);
7403 ok(hr == S_OK, "got 0x%08x\n", hr);
7405 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
7406 ok(hr == S_OK, "got 0x%08x\n", hr);
7408 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
7409 ok(hr == S_OK, "got 0x%08x\n", hr);
7411 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
7413 exists = FALSE;
7414 hr = IDWriteFontFace1_TryGetFontTable(fontface1, MS_KERN_TAG, &data, &size, &context, &exists);
7415 ok(hr == S_OK, "got 0x%08x\n", hr);
7416 IDWriteFontFace1_ReleaseFontTable(fontface1, context);
7418 has_kerningpairs = IDWriteFontFace1_HasKerningPairs(fontface1);
7419 if (!exists)
7420 ok(!has_kerningpairs, "%s: expected %d, got %d\n", wine_dbgstr_w(nameW), exists, has_kerningpairs);
7422 IDWriteLocalizedStrings_Release(names);
7423 IDWriteFont_Release(font);
7425 IDWriteFontFace1_Release(fontface1);
7426 IDWriteFontFace_Release(fontface);
7427 IDWriteFontFamily_Release(family);
7430 IDWriteFontCollection_Release(syscollection);
7431 ref = IDWriteFactory_Release(factory);
7432 ok(ref == 0, "factory not released, %u\n", ref);
7435 static void test_ComputeGlyphOrigins(void)
7437 IDWriteFactory4 *factory;
7438 DWRITE_GLYPH_RUN run;
7439 HRESULT hr;
7440 D2D1_POINT_2F origins[2];
7441 D2D1_POINT_2F baseline_origin;
7442 UINT16 glyphs[2];
7443 FLOAT advances[2];
7444 DWRITE_MATRIX m;
7445 ULONG ref;
7447 factory = create_factory_iid(&IID_IDWriteFactory4);
7448 if (!factory) {
7449 win_skip("ComputeGlyphOrigins() is not supported.\n");
7450 return;
7453 advances[0] = 10.0f;
7454 advances[1] = 20.0f;
7456 run.fontFace = NULL;
7457 run.fontEmSize = 16.0f;
7458 run.glyphCount = 2;
7459 run.glyphIndices = glyphs;
7460 run.glyphAdvances = advances;
7461 run.glyphOffsets = NULL;
7462 run.isSideways = FALSE;
7463 run.bidiLevel = 0;
7465 baseline_origin.x = 123.0f;
7466 baseline_origin.y = 321.0f;
7468 memset(origins, 0, sizeof(origins));
7469 hr = IDWriteFactory4_ComputeGlyphOrigins_(factory, &run, baseline_origin, origins);
7470 ok(hr == S_OK, "got 0x%08x\n", hr);
7471 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
7472 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
7474 memset(origins, 0, sizeof(origins));
7475 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
7476 NULL, origins);
7477 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
7478 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
7480 /* transform is not applied to returned origins */
7481 m.m11 = 2.0f;
7482 m.m12 = 0.0f;
7483 m.m21 = 0.0f;
7484 m.m22 = 1.0f;
7485 m.dx = 0.0f;
7486 m.dy = 0.0f;
7488 memset(origins, 0, sizeof(origins));
7489 hr = IDWriteFactory4_ComputeGlyphOrigins(factory, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin,
7490 &m, origins);
7491 ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y);
7492 ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y);
7494 ref = IDWriteFactory4_Release(factory);
7495 ok(ref == 0, "factory not released, %u\n", ref);
7498 static void test_object_lifetime(void)
7500 IDWriteFontCollection *collection, *collection2;
7501 IDWriteFontList *fontlist, *fontlist2;
7502 IDWriteGdiInterop *interop, *interop2;
7503 IDWriteFontFamily *family, *family2;
7504 IDWriteFontFace *fontface;
7505 IDWriteFont *font, *font2;
7506 IDWriteFactory *factory;
7507 HRESULT hr;
7508 ULONG ref;
7510 factory = create_factory();
7511 EXPECT_REF(factory, 1);
7513 /* system collection takes factory reference */
7514 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
7515 ok(hr == S_OK, "got %#x\n", hr);
7517 EXPECT_REF(collection, 1);
7518 EXPECT_REF(factory, 2);
7520 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection2, FALSE);
7521 ok(hr == S_OK, "got %#x\n", hr);
7522 ok(collection2 == collection, "expected same collection\n");
7524 EXPECT_REF(collection, 2);
7525 EXPECT_REF(factory, 2);
7527 IDWriteFontCollection_Release(collection2);
7529 IDWriteFontCollection_AddRef(collection);
7530 EXPECT_REF(collection, 2);
7531 EXPECT_REF(factory, 2);
7532 IDWriteFontCollection_Release(collection);
7534 EXPECT_REF(collection, 1);
7536 /* family takes collection reference */
7537 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
7538 ok(hr == S_OK, "got %#x\n", hr);
7540 EXPECT_REF(family, 1);
7541 EXPECT_REF(collection, 2);
7542 EXPECT_REF(factory, 2);
7544 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family2);
7545 ok(hr == S_OK, "got %#x\n", hr);
7547 EXPECT_REF(family2, 1);
7548 EXPECT_REF(collection, 3);
7549 EXPECT_REF(factory, 2);
7551 IDWriteFontFamily_Release(family2);
7553 EXPECT_REF(family, 1);
7554 EXPECT_REF(collection, 2);
7555 EXPECT_REF(factory, 2);
7557 /* font takes family reference */
7558 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
7559 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
7560 ok(hr == S_OK, "got %#x\n", hr);
7562 EXPECT_REF(family, 2);
7563 EXPECT_REF(collection, 2);
7564 EXPECT_REF(factory, 2);
7566 hr = IDWriteFont_GetFontFamily(font, &family2);
7567 ok(hr == S_OK, "got %#x\n", hr);
7568 ok(family2 == family, "unexpected family pointer\n");
7569 IDWriteFontFamily_Release(family2);
7571 EXPECT_REF(font, 1);
7572 EXPECT_REF(factory, 2);
7574 /* Fontface takes factory reference and nothing else. */
7575 hr = IDWriteFont_CreateFontFace(font, &fontface);
7576 ok(hr == S_OK, "got %#x\n", hr);
7578 EXPECT_REF(font, 1);
7579 EXPECT_REF_BROKEN(fontface, 1, 2);
7580 EXPECT_REF(family, 2);
7581 EXPECT_REF(collection, 2);
7582 EXPECT_REF_BROKEN(factory, 3, 2);
7584 /* get font from fontface */
7585 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
7586 ok(hr == S_OK, "got %#x\n", hr);
7588 EXPECT_REF(font, 1);
7589 EXPECT_REF(font2, 1);
7590 EXPECT_REF_BROKEN(fontface, 1, 2);
7591 EXPECT_REF(family, 2);
7592 EXPECT_REF(collection, 3);
7593 EXPECT_REF_BROKEN(factory, 3, 2);
7595 IDWriteFont_Release(font2);
7596 IDWriteFontFace_Release(fontface);
7598 EXPECT_REF(font, 1);
7599 EXPECT_REF(family, 2);
7600 EXPECT_REF(collection, 2);
7601 EXPECT_REF(factory, 2);
7603 IDWriteFont_Release(font);
7605 EXPECT_REF(family, 1);
7606 EXPECT_REF(collection, 2);
7607 EXPECT_REF(factory, 2);
7609 /* Matching fonts list takes family reference. */
7610 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
7611 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
7612 ok(hr == S_OK, "got %#x\n", hr);
7614 EXPECT_REF(family, 2);
7615 EXPECT_REF(collection, 2);
7616 EXPECT_REF(factory, 2);
7618 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
7619 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
7620 ok(hr == S_OK, "got %#x\n", hr);
7621 ok(fontlist2 != fontlist, "unexpected font list\n");
7622 IDWriteFontList_Release(fontlist2);
7624 IDWriteFontList_Release(fontlist);
7626 IDWriteFontFamily_Release(family);
7627 EXPECT_REF(collection, 1);
7629 EXPECT_REF(factory, 2);
7630 ref = IDWriteFontCollection_Release(collection);
7631 ok(ref == 0, "collection not released, %u\n", ref);
7632 EXPECT_REF(factory, 1);
7634 /* GDI interop object takes factory reference */
7635 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
7636 ok(hr == S_OK, "got %#x\n", hr);
7637 EXPECT_REF(interop, 1);
7638 EXPECT_REF(factory, 2);
7640 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
7641 ok(hr == S_OK, "got %#x\n", hr);
7642 ok(interop == interop2, "got unexpected interop pointer\n");
7644 EXPECT_REF(interop, 2);
7645 EXPECT_REF(factory, 2);
7647 IDWriteGdiInterop_Release(interop2);
7648 ref = IDWriteGdiInterop_Release(interop);
7649 ok(ref == 0, "interop not released, %u\n", ref);
7651 ref = IDWriteFactory_Release(factory);
7652 ok(ref == 0, "factory not released, %u\n", ref);
7655 struct testowner_object
7657 IUnknown IUnknown_iface;
7658 LONG ref;
7661 static inline struct testowner_object *impl_from_IUnknown(IUnknown *iface)
7663 return CONTAINING_RECORD(iface, struct testowner_object, IUnknown_iface);
7666 static HRESULT WINAPI testowner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
7668 if (IsEqualIID(riid, &IID_IUnknown)) {
7669 *obj = iface;
7670 IUnknown_AddRef(iface);
7671 return S_OK;
7674 *obj = NULL;
7675 return E_NOINTERFACE;
7678 static ULONG WINAPI testowner_AddRef(IUnknown *iface)
7680 struct testowner_object *object = impl_from_IUnknown(iface);
7681 return InterlockedIncrement(&object->ref);
7684 static ULONG WINAPI testowner_Release(IUnknown *iface)
7686 struct testowner_object *object = impl_from_IUnknown(iface);
7687 return InterlockedDecrement(&object->ref);
7690 static const IUnknownVtbl testownervtbl = {
7691 testowner_QueryInterface,
7692 testowner_AddRef,
7693 testowner_Release,
7696 static void testowner_init(struct testowner_object *object)
7698 object->IUnknown_iface.lpVtbl = &testownervtbl;
7699 object->ref = 1;
7702 static void test_inmemory_file_loader(void)
7704 IDWriteFontFileStream *stream, *stream2, *stream3;
7705 IDWriteFontFileLoader *loader, *loader2;
7706 IDWriteInMemoryFontFileLoader *inmemory;
7707 struct testowner_object ownerobject;
7708 const void *key, *data, *frag_start;
7709 UINT64 file_size, size, writetime;
7710 IDWriteFontFile *file, *file2;
7711 IDWriteFontFace *fontface;
7712 void *context, *context2;
7713 IDWriteFactory5 *factory;
7714 UINT32 count, key_size;
7715 DWORD ref_key;
7716 HRESULT hr;
7717 ULONG ref;
7719 factory = create_factory_iid(&IID_IDWriteFactory5);
7720 if (!factory) {
7721 win_skip("CreateInMemoryFontFileLoader() is not supported\n");
7722 return;
7725 EXPECT_REF(factory, 1);
7726 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
7727 ok(hr == S_OK, "got %#x\n", hr);
7728 EXPECT_REF(factory, 1);
7730 testowner_init(&ownerobject);
7731 fontface = create_fontface((IDWriteFactory *)factory);
7733 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader2);
7734 ok(hr == S_OK, "got %#x\n", hr);
7735 ok(loader != loader2, "unexpected pointer\n");
7736 IDWriteFontFileLoader_Release(loader2);
7738 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&inmemory);
7739 ok(hr == S_OK, "got %#x\n", hr);
7740 IDWriteFontFileLoader_Release(loader);
7741 EXPECT_REF(inmemory, 1);
7743 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7744 ok(!count, "Unexpected file count %u.\n", count);
7746 /* Use whole font blob to construct in-memory file. */
7747 count = 1;
7748 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
7749 ok(hr == S_OK, "got %#x\n", hr);
7751 hr = IDWriteFontFile_GetLoader(file, &loader);
7752 ok(hr == S_OK, "got %#x\n", hr);
7754 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
7755 ok(hr == S_OK, "got %#x\n", hr);
7757 hr = IDWriteFontFileLoader_CreateStreamFromKey(loader, key, key_size, &stream);
7758 ok(hr == S_OK, "got %#x\n", hr);
7759 IDWriteFontFileLoader_Release(loader);
7760 IDWriteFontFile_Release(file);
7762 hr = IDWriteFontFileStream_GetFileSize(stream, &file_size);
7763 ok(hr == S_OK, "got %#x\n", hr);
7765 hr = IDWriteFontFileStream_ReadFileFragment(stream, &data, 0, file_size, &context);
7766 ok(hr == S_OK, "got %#x\n", hr);
7768 /* Not registered yet. */
7769 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7770 file_size, NULL, &file);
7771 ok(hr == E_INVALIDARG, "got %#x\n", hr);
7773 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7774 ok(count == 1, "Unexpected file count %u.\n", count);
7776 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7777 ok(hr == S_OK, "got %#x\n", hr);
7778 EXPECT_REF(inmemory, 2);
7780 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
7781 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7782 file_size, &ownerobject.IUnknown_iface, &file);
7783 ok(hr == S_OK, "got %#x\n", hr);
7784 EXPECT_REF(&ownerobject.IUnknown_iface, 2);
7785 EXPECT_REF(inmemory, 3);
7787 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7788 ok(count == 2, "Unexpected file count %u.\n", count);
7790 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7791 file_size, &ownerobject.IUnknown_iface, &file2);
7792 ok(hr == S_OK, "got %#x\n", hr);
7793 ok(file2 != file, "got unexpected file\n");
7794 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7795 EXPECT_REF(inmemory, 4);
7797 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7798 ok(count == 3, "Unexpected file count %u.\n", count);
7800 /* Check in-memory reference key format. */
7801 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
7802 ok(hr == S_OK, "got %#x\n", hr);
7804 ok(key && *(DWORD*)key == 1, "got wrong ref key\n");
7805 ok(key_size == 4, "ref key size %u\n", key_size);
7807 hr = IDWriteFontFile_GetReferenceKey(file2, &key, &key_size);
7808 ok(hr == S_OK, "got %#x\n", hr);
7810 ok(key && *(DWORD*)key == 2, "got wrong ref key\n");
7811 ok(key_size == 4, "ref key size %u\n", key_size);
7813 EXPECT_REF(inmemory, 4);
7814 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream2);
7815 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
7816 EXPECT_REF(stream2, 1);
7817 EXPECT_REF(inmemory, 4);
7819 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, key, key_size, &stream3);
7820 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
7822 ok(stream2 != stream3, "Unexpected stream.\n");
7824 IDWriteFontFileStream_Release(stream2);
7825 IDWriteFontFileStream_Release(stream3);
7827 /* Release file at index 1, create new one to see if index is reused. */
7828 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7829 ref = IDWriteFontFile_Release(file);
7830 ok(ref == 0, "File object not released, %u.\n", ref);
7831 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7833 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7834 ok(count == 3, "Unexpected file count %u.\n", count);
7836 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7837 ref = IDWriteFontFile_Release(file2);
7838 ok(ref == 0, "File object not released, %u.\n", ref);
7839 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7841 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7842 ok(count == 3, "Unexpected file count %u.\n", count);
7844 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7845 ok(hr == S_OK, "got %#x\n", hr);
7846 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7848 EXPECT_REF(&ownerobject.IUnknown_iface, 3);
7849 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
7850 ok(ref == 0, "loader not released, %u.\n", ref);
7851 EXPECT_REF(&ownerobject.IUnknown_iface, 1);
7853 /* Test reference key for first added file. */
7854 hr = IDWriteFactory5_CreateInMemoryFontFileLoader(factory, &loader);
7855 ok(hr == S_OK, "Failed to create loader, hr %#x.\n", hr);
7857 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteInMemoryFontFileLoader, (void **)&inmemory);
7858 ok(hr == S_OK, "Failed to get in-memory interface, hr %#x.\n", hr);
7859 IDWriteFontFileLoader_Release(loader);
7861 hr = IDWriteFactory5_RegisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7862 ok(hr == S_OK, "Failed to register loader, hr %#x.\n", hr);
7864 ref_key = 0;
7865 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
7866 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7868 hr = IDWriteInMemoryFontFileLoader_CreateInMemoryFontFileReference(inmemory, (IDWriteFactory *)factory, data,
7869 file_size, &ownerobject.IUnknown_iface, &file);
7870 ok(hr == S_OK, "Failed to create in-memory file reference, hr %#x.\n", hr);
7872 ref_key = 0;
7873 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key), &stream2);
7874 ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
7876 context2 = (void *)0xdeadbeef;
7877 hr = IDWriteFontFileStream_ReadFileFragment(stream2, &frag_start, 0, file_size, &context2);
7878 ok(hr == S_OK, "Failed to read a fragment, hr %#x.\n", hr);
7879 ok(context == NULL, "Unexpected context %p.\n", context2);
7880 ok(frag_start == data, "Unexpected fragment pointer %p.\n", frag_start);
7882 hr = IDWriteFontFileStream_GetFileSize(stream2, &size);
7883 ok(hr == S_OK, "Failed to get file size, hr %#x.\n", hr);
7884 ok(size == file_size, "Unexpected file size.\n");
7886 IDWriteFontFileStream_ReleaseFileFragment(stream2, context2);
7888 writetime = 1;
7889 hr = IDWriteFontFileStream_GetLastWriteTime(stream2, &writetime);
7890 ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
7891 ok(writetime == 0, "Unexpected writetime.\n");
7893 IDWriteFontFileStream_Release(stream2);
7895 ref_key = 0;
7896 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, NULL, sizeof(ref_key) - 1, &stream2);
7897 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7899 ref_key = 0;
7900 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) - 1, &stream2);
7901 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7903 ref_key = 0;
7904 hr = IDWriteInMemoryFontFileLoader_CreateStreamFromKey(inmemory, &ref_key, sizeof(ref_key) + 1, &stream2);
7905 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
7907 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7908 ok(count == 1, "Unexpected file count %u.\n", count);
7910 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
7911 ok(hr == S_OK, "Failed to get reference key, hr %#x.\n", hr);
7913 ok(key && *(DWORD*)key == 0, "Unexpected reference key.\n");
7914 ok(key_size == 4, "Unexpected key size %u.\n", key_size);
7916 IDWriteFontFile_Release(file);
7918 count = IDWriteInMemoryFontFileLoader_GetFileCount(inmemory);
7919 ok(count == 1, "Unexpected file count %u.\n", count);
7921 hr = IDWriteFactory5_UnregisterFontFileLoader(factory, (IDWriteFontFileLoader *)inmemory);
7922 ok(hr == S_OK, "Failed to unregister loader, hr %#x.\n", hr);
7924 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
7925 IDWriteFontFileStream_Release(stream);
7926 IDWriteFontFace_Release(fontface);
7928 ref = IDWriteInMemoryFontFileLoader_Release(inmemory);
7929 ok(ref == 0, "loader not released, %u.\n", ref);
7931 ref = IDWriteFactory5_Release(factory);
7932 ok(ref == 0, "factory not released, %u\n", ref);
7935 static BOOL face_has_table(IDWriteFontFace4 *fontface, UINT32 tag)
7937 BOOL exists = FALSE;
7938 const void *data;
7939 void *context;
7940 UINT32 size;
7941 HRESULT hr;
7943 hr = IDWriteFontFace4_TryGetFontTable(fontface, tag, &data, &size, &context, &exists);
7944 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
7945 if (exists)
7946 IDWriteFontFace4_ReleaseFontTable(fontface, context);
7948 return exists;
7951 static DWORD get_sbix_formats(IDWriteFontFace4 *fontface)
7953 UINT32 size, s, num_strikes;
7954 const sbix_header *header;
7955 UINT16 g, num_glyphs;
7956 BOOL exists = FALSE;
7957 const maxp *maxp;
7958 const void *data;
7959 DWORD ret = 0;
7960 void *context;
7961 HRESULT hr;
7963 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_MAXP_TAG, &data, &size, &context, &exists);
7964 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
7965 ok(exists, "Expected maxp table\n");
7967 if (!exists)
7968 return 0;
7970 maxp = data;
7971 num_glyphs = GET_BE_WORD(maxp->numGlyphs);
7973 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_SBIX_TAG, &data, &size, &context, &exists);
7974 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
7975 ok(exists, "Expected sbix table\n");
7977 header = data;
7978 num_strikes = GET_BE_DWORD(header->numStrikes);
7980 for (s = 0; s < num_strikes; s++) {
7981 sbix_strike *strike = (sbix_strike *)((BYTE *)header + GET_BE_DWORD(header->strikeOffset[s]));
7983 for (g = 0; g < num_glyphs; g++) {
7984 DWORD offset = GET_BE_DWORD(strike->glyphDataOffsets[g]);
7985 DWORD offset_next = GET_BE_DWORD(strike->glyphDataOffsets[g + 1]);
7986 sbix_glyph_data *glyph_data;
7987 DWORD format;
7989 if (offset == offset_next)
7990 continue;
7992 glyph_data = (sbix_glyph_data *)((BYTE *)strike + offset);
7993 switch (format = glyph_data->graphicType)
7995 case MS_PNG__TAG:
7996 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
7997 break;
7998 case MS_JPG__TAG:
7999 ret |= DWRITE_GLYPH_IMAGE_FORMATS_JPEG;
8000 break;
8001 case MS_TIFF_TAG:
8002 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TIFF;
8003 break;
8004 default:
8005 ok(0, "unexpected format, %#x\n", GET_BE_DWORD(format));
8010 IDWriteFontFace4_ReleaseFontTable(fontface, context);
8012 return ret;
8015 static DWORD get_cblc_formats(IDWriteFontFace4 *fontface)
8017 CBLCBitmapSizeTable *sizes;
8018 UINT32 num_sizes, size, s;
8019 BOOL exists = FALSE;
8020 CBLCHeader *header;
8021 DWORD ret = 0;
8022 void *context;
8023 HRESULT hr;
8025 hr = IDWriteFontFace4_TryGetFontTable(fontface, MS_CBLC_TAG, (const void **)&header, &size, &context, &exists);
8026 ok(hr == S_OK, "TryGetFontTable() failed, %#x\n", hr);
8027 ok(exists, "Expected CBLC table\n");
8029 if (!exists)
8030 return 0;
8032 num_sizes = GET_BE_DWORD(header->numSizes);
8033 sizes = (CBLCBitmapSizeTable *)(header + 1);
8035 for (s = 0; s < num_sizes; s++) {
8036 BYTE bpp = sizes->bitDepth;
8038 if (bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8)
8039 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PNG;
8040 else if (bpp == 32)
8041 ret |= DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8;
8044 IDWriteFontFace4_ReleaseFontTable(fontface, context);
8046 return ret;
8049 static DWORD get_face_glyph_image_formats(IDWriteFontFace4 *fontface)
8051 DWORD ret = DWRITE_GLYPH_IMAGE_FORMATS_NONE;
8053 if (face_has_table(fontface, MS_GLYF_TAG))
8054 ret |= DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE;
8056 if (face_has_table(fontface, MS_CFF__TAG) ||
8057 face_has_table(fontface, MS_CFF2_TAG))
8058 ret |= DWRITE_GLYPH_IMAGE_FORMATS_CFF;
8060 if (face_has_table(fontface, MS_COLR_TAG))
8061 ret |= DWRITE_GLYPH_IMAGE_FORMATS_COLR;
8063 if (face_has_table(fontface, MS_SVG__TAG))
8064 ret |= DWRITE_GLYPH_IMAGE_FORMATS_SVG;
8066 if (face_has_table(fontface, MS_SBIX_TAG))
8067 ret |= get_sbix_formats(fontface);
8069 if (face_has_table(fontface, MS_CBLC_TAG))
8070 ret |= get_cblc_formats(fontface);
8072 return ret;
8075 static void test_GetGlyphImageFormats(void)
8077 IDWriteFontCollection *syscollection;
8078 IDWriteFactory *factory;
8079 UINT32 i, count;
8080 HRESULT hr;
8081 ULONG ref;
8082 IDWriteFontFace *fontface;
8083 IDWriteFontFace4 *fontface4;
8085 factory = create_factory();
8087 fontface = create_fontface(factory);
8088 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
8089 IDWriteFontFace_Release(fontface);
8090 if (FAILED(hr)) {
8091 win_skip("GetGlyphImageFormats() is not supported\n");
8092 IDWriteFactory_Release(factory);
8093 return;
8095 IDWriteFontFace4_Release(fontface4);
8097 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
8098 ok(hr == S_OK, "got 0x%08x\n", hr);
8099 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
8101 for (i = 0; i < count; i++) {
8102 WCHAR familynameW[256], facenameW[128];
8103 IDWriteLocalizedStrings *names;
8104 IDWriteFontFamily *family;
8105 UINT32 j, fontcount;
8106 IDWriteFont *font;
8108 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
8109 ok(hr == S_OK, "got 0x%08x\n", hr);
8111 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
8112 ok(hr == S_OK, "got 0x%08x\n", hr);
8114 get_enus_string(names, familynameW, sizeof(familynameW)/sizeof(*familynameW));
8115 IDWriteLocalizedStrings_Release(names);
8117 fontcount = IDWriteFontFamily_GetFontCount(family);
8118 for (j = 0; j < fontcount; j++) {
8119 DWORD formats, expected_formats;
8121 hr = IDWriteFontFamily_GetFont(family, j, &font);
8122 ok(hr == S_OK, "got 0x%08x\n", hr);
8124 hr = IDWriteFont_CreateFontFace(font, &fontface);
8125 ok(hr == S_OK, "got 0x%08x\n", hr);
8127 hr = IDWriteFont_GetFaceNames(font, &names);
8128 ok(hr == S_OK, "got 0x%08x\n", hr);
8130 get_enus_string(names, facenameW, sizeof(facenameW)/sizeof(*facenameW));
8132 IDWriteLocalizedStrings_Release(names);
8134 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace4, (void **)&fontface4);
8136 /* Mask describes font as a whole. */
8137 formats = IDWriteFontFace4_GetGlyphImageFormats(fontface4);
8138 expected_formats = get_face_glyph_image_formats(fontface4);
8139 ok(formats == expected_formats, "%s - %s, expected formats %#x, got formats %#x.\n",
8140 wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), expected_formats, formats);
8142 IDWriteFontFace4_Release(fontface4);
8143 IDWriteFontFace_Release(fontface);
8144 IDWriteFont_Release(font);
8147 IDWriteFontFamily_Release(family);
8150 IDWriteFontCollection_Release(syscollection);
8151 ref = IDWriteFactory_Release(factory);
8152 ok(ref == 0, "factory not released, %u\n", ref);
8155 static void test_CreateCustomRenderingParams(void)
8157 static const struct custom_params_test
8159 FLOAT gamma;
8160 FLOAT contrast;
8161 FLOAT cleartype_level;
8162 DWRITE_PIXEL_GEOMETRY geometry;
8163 DWRITE_RENDERING_MODE rendering_mode;
8164 HRESULT hr;
8165 } params_tests[] =
8167 { 0.0f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8168 { 0.0f, 0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8169 { 0.0f, 0.0f, 0.1f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8170 { -0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8171 { 0.1f, -0.1f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8172 { 0.1f, 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 },
8174 { 0.01f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_FLAT, DWRITE_RENDERING_MODE_NATURAL },
8175 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR + 1, DWRITE_RENDERING_MODE_NATURAL, E_INVALIDARG },
8176 { 0.1f, 0.0f, 0.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_OUTLINE + 1, E_INVALIDARG },
8177 { 0.1f, 0.0f, 2.0f, DWRITE_PIXEL_GEOMETRY_BGR, DWRITE_RENDERING_MODE_NATURAL },
8179 IDWriteFactory *factory;
8180 unsigned int i;
8181 HRESULT hr;
8182 ULONG ref;
8184 factory = create_factory();
8186 for (i = 0; i < sizeof(params_tests)/sizeof(*params_tests); i++) {
8187 IDWriteRenderingParams *params;
8189 params = (void *)0xdeadbeef;
8190 hr = IDWriteFactory_CreateCustomRenderingParams(factory, params_tests[i].gamma, params_tests[i].contrast,
8191 params_tests[i].cleartype_level, params_tests[i].geometry, params_tests[i].rendering_mode, &params);
8192 ok(hr == params_tests[i].hr, "%u: unexpected hr %#x, expected %#x.\n", i, hr, params_tests[i].hr);
8194 if (hr == S_OK) {
8195 ok(params_tests[i].gamma == IDWriteRenderingParams_GetGamma(params), "%u: unexpected gamma %f, expected %f.\n",
8196 i, IDWriteRenderingParams_GetGamma(params), params_tests[i].gamma);
8197 ok(params_tests[i].contrast == IDWriteRenderingParams_GetEnhancedContrast(params),
8198 "%u: unexpected contrast %f, expected %f.\n",
8199 i, IDWriteRenderingParams_GetEnhancedContrast(params), params_tests[i].contrast);
8200 ok(params_tests[i].cleartype_level == IDWriteRenderingParams_GetClearTypeLevel(params),
8201 "%u: unexpected ClearType level %f, expected %f.\n",
8202 i, IDWriteRenderingParams_GetClearTypeLevel(params), params_tests[i].cleartype_level);
8203 ok(params_tests[i].geometry == IDWriteRenderingParams_GetPixelGeometry(params),
8204 "%u: unexpected pixel geometry %u, expected %u.\n", i, IDWriteRenderingParams_GetPixelGeometry(params),
8205 params_tests[i].geometry);
8206 ok(params_tests[i].rendering_mode == IDWriteRenderingParams_GetRenderingMode(params),
8207 "%u: unexpected rendering mode %u, expected %u.\n", i, IDWriteRenderingParams_GetRenderingMode(params),
8208 params_tests[i].rendering_mode);
8209 IDWriteRenderingParams_Release(params);
8211 else
8212 ok(params == NULL, "%u: expected NULL interface pointer on failure.\n", i);
8215 ref = IDWriteFactory_Release(factory);
8216 ok(ref == 0, "factory not released, %u\n", ref);
8219 static void test_localfontfileloader(void)
8221 IDWriteFontFileLoader *loader, *loader2;
8222 IDWriteFactory *factory, *factory2;
8223 IDWriteFontFile *file, *file2;
8224 WCHAR *path;
8225 HRESULT hr;
8226 ULONG ref;
8228 factory = create_factory();
8229 factory2 = create_factory();
8231 path = create_testfontfile(test_fontfile);
8233 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
8234 ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
8236 hr = IDWriteFactory_CreateFontFileReference(factory2, path, NULL, &file2);
8237 ok(hr == S_OK, "Failed to create file reference, hr %#x.\n", hr);
8238 ok(file != file2, "Unexpected file instance.\n");
8240 hr = IDWriteFontFile_GetLoader(file, &loader);
8241 ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
8243 hr = IDWriteFontFile_GetLoader(file2, &loader2);
8244 ok(hr == S_OK, "Failed to get loader, hr %#x.\n", hr);
8245 ok(loader == loader2, "Unexpected loader instance\n");
8247 IDWriteFontFile_Release(file);
8248 IDWriteFontFile_Release(file2);
8249 IDWriteFontFileLoader_Release(loader);
8250 IDWriteFontFileLoader_Release(loader2);
8251 ref = IDWriteFactory_Release(factory);
8252 ok(ref == 0, "factory not released, %u\n", ref);
8253 DELETE_FONTFILE(path);
8256 static void test_AnalyzeContainerType(void)
8258 struct WOFFHeader2 woff2_header;
8259 struct WOFFHeader woff_header;
8260 DWRITE_CONTAINER_TYPE type;
8261 IDWriteFactory5 *factory;
8263 factory = create_factory_iid(&IID_IDWriteFactory5);
8264 if (!factory) {
8265 win_skip("AnalyzeContainerType() is not supported.\n");
8266 return;
8269 type = IDWriteFactory5_AnalyzeContainerType(factory, NULL, 0);
8270 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8272 type = IDWriteFactory5_AnalyzeContainerType(factory, (void const *)0xdeadbeef, 0);
8273 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8275 memset(&woff_header, 0xff, sizeof(woff_header));
8276 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
8277 woff_header.length = 0;
8278 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header));
8279 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
8281 memset(&woff_header, 0xff, sizeof(woff_header));
8282 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
8283 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature));
8284 ok(type == DWRITE_CONTAINER_TYPE_WOFF, "Unexpected container type %u.\n", type);
8286 memset(&woff_header, 0xff, sizeof(woff_header));
8287 woff_header.signature = GET_LE_DWORD(MS_WOFF_TAG);
8288 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff_header, sizeof(woff_header.signature) - 1);
8289 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8291 memset(&woff2_header, 0xff, sizeof(woff2_header));
8292 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
8293 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header));
8294 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
8296 memset(&woff2_header, 0xff, sizeof(woff2_header));
8297 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
8298 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature));
8299 ok(type == DWRITE_CONTAINER_TYPE_WOFF2, "Unexpected container type %u.\n", type);
8301 memset(&woff2_header, 0xff, sizeof(woff2_header));
8302 woff2_header.signature = GET_LE_DWORD(MS_WOF2_TAG);
8303 type = IDWriteFactory5_AnalyzeContainerType(factory, &woff2_header, sizeof(woff2_header.signature) - 1);
8304 ok(type == DWRITE_CONTAINER_TYPE_UNKNOWN, "Unexpected container type %u.\n", type);
8306 IDWriteFactory5_Release(factory);
8309 static void test_fontsetbuilder(void)
8311 IDWriteFontCollection1 *collection;
8312 IDWriteFontSetBuilder *builder;
8313 IDWriteFactory3 *factory;
8314 UINT32 count, i, ref;
8315 HRESULT hr;
8317 factory = create_factory_iid(&IID_IDWriteFactory3);
8318 if (!factory) {
8319 skip("IDWriteFontSetBuilder is not supported.\n");
8320 return;
8323 EXPECT_REF(factory, 1);
8324 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
8325 todo_wine
8326 ok(hr == S_OK, "Failed to create font set builder, hr %#x.\n", hr);
8328 if (FAILED(hr)) {
8329 IDWriteFactory3_Release(factory);
8330 return;
8333 EXPECT_REF(factory, 2);
8334 IDWriteFontSetBuilder_Release(builder);
8336 hr = IDWriteFactory3_GetSystemFontCollection(factory, FALSE, &collection, FALSE);
8337 ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
8338 count = IDWriteFontCollection1_GetFontFamilyCount(collection);
8340 for (i = 0; i < count; i++) {
8341 IDWriteFontFamily1 *family;
8342 UINT32 j, fontcount;
8343 IDWriteFont3 *font;
8345 hr = IDWriteFontCollection1_GetFontFamily(collection, i, &family);
8346 ok(hr == S_OK, "Failed to get family, hr %#x.\n", hr);
8348 fontcount = IDWriteFontFamily1_GetFontCount(family);
8349 for (j = 0; j < fontcount; j++) {
8350 IDWriteFontFaceReference *ref, *ref2;
8351 IDWriteFontSet *fontset;
8352 UINT32 setcount, id;
8354 hr = IDWriteFontFamily1_GetFont(family, j, &font);
8355 ok(hr == S_OK, "Failed to get font, hr %#x.\n", hr);
8357 /* Create a set with a single font reference, test set properties. */
8358 hr = IDWriteFactory3_CreateFontSetBuilder(factory, &builder);
8359 ok(hr == S_OK, "Failed to create font set builder, hr %#x.\n", hr);
8361 hr = IDWriteFont3_GetFontFaceReference(font, &ref);
8362 ok(hr == S_OK, "Failed to get fontface reference, hr %#x.\n", hr);
8364 EXPECT_REF(ref, 1);
8365 hr = IDWriteFontSetBuilder_AddFontFaceReference(builder, ref);
8366 ok(hr == S_OK, "Failed to add fontface reference, hr %#x.\n", hr);
8367 EXPECT_REF(ref, 1);
8369 hr = IDWriteFontSetBuilder_CreateFontSet(builder, &fontset);
8370 ok(hr == S_OK, "Failed to create a font set, hr %#x.\n", hr);
8372 setcount = IDWriteFontSet_GetFontCount(fontset);
8373 ok(setcount == 1, "Unexpected font count %u.\n", setcount);
8375 hr = IDWriteFontSet_GetFontFaceReference(fontset, 0, &ref2);
8376 ok(hr == S_OK, "Failed to get font face reference, hr %#x.\n", hr);
8377 ok(ref2 != ref, "Unexpected reference.\n");
8378 IDWriteFontFaceReference_Release(ref2);
8380 for (id = DWRITE_FONT_PROPERTY_ID_FAMILY_NAME; id < DWRITE_FONT_PROPERTY_ID_TOTAL; id++) {
8381 static const WCHAR fmtW[] = {'%','u',0};
8382 IDWriteLocalizedStrings *values;
8383 WCHAR buffW[255], buff2W[255];
8384 UINT32 c, ivalue;
8385 BOOL exists;
8387 hr = IDWriteFontSet_GetPropertyValues(fontset, 0, id, &exists, &values);
8388 ok(hr == S_OK, "Failed to get property value, hr %#x.\n", hr);
8390 if (!exists)
8391 continue;
8393 switch (id)
8395 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
8396 ivalue = IDWriteFont3_GetWeight(font);
8397 break;
8398 case DWRITE_FONT_PROPERTY_ID_STRETCH:
8399 ivalue = IDWriteFont3_GetStretch(font);
8400 break;
8401 case DWRITE_FONT_PROPERTY_ID_STYLE:
8402 ivalue = IDWriteFont3_GetStyle(font);
8403 break;
8404 default:
8408 switch (id)
8410 case DWRITE_FONT_PROPERTY_ID_WEIGHT:
8411 case DWRITE_FONT_PROPERTY_ID_STRETCH:
8412 case DWRITE_FONT_PROPERTY_ID_STYLE:
8413 c = IDWriteLocalizedStrings_GetCount(values);
8414 ok(c == 1, "Unexpected string count %u.\n", c);
8416 buffW[0] = 'a';
8417 hr = IDWriteLocalizedStrings_GetLocaleName(values, 0, buffW, sizeof(buffW)/sizeof(buffW[0]));
8418 ok(hr == S_OK, "Failed to get locale name, hr %#x.\n", hr);
8419 ok(!*buffW, "Unexpected locale %s.\n", wine_dbgstr_w(buffW));
8421 buff2W[0] = 0;
8422 hr = IDWriteLocalizedStrings_GetString(values, 0, buff2W, sizeof(buff2W)/sizeof(buff2W[0]));
8423 ok(hr == S_OK, "Failed to get property string, hr %#x.\n", hr);
8425 wsprintfW(buffW, fmtW, ivalue);
8426 ok(!lstrcmpW(buffW, buff2W), "Unexpected property value %s, expected %s.\n", wine_dbgstr_w(buff2W),
8427 wine_dbgstr_w(buffW));
8428 break;
8429 default:
8433 IDWriteLocalizedStrings_Release(values);
8436 IDWriteFontSet_Release(fontset);
8437 IDWriteFontFaceReference_Release(ref);
8438 IDWriteFontSetBuilder_Release(builder);
8440 IDWriteFont3_Release(font);
8443 IDWriteFontFamily1_Release(family);
8446 IDWriteFontCollection1_Release(collection);
8448 ref = IDWriteFactory3_Release(factory);
8449 ok(ref == 0, "factory not released, %u\n", ref);
8452 START_TEST(font)
8454 IDWriteFactory *factory;
8456 if (!(factory = create_factory())) {
8457 win_skip("failed to create factory\n");
8458 return;
8461 test_object_lifetime();
8462 test_CreateFontFromLOGFONT();
8463 test_CreateBitmapRenderTarget();
8464 test_GetFontFamily();
8465 test_GetFamilyNames();
8466 test_CreateFontFace();
8467 test_GetMetrics();
8468 test_system_fontcollection();
8469 test_ConvertFontFaceToLOGFONT();
8470 test_CustomFontCollection();
8471 test_CreateCustomFontFileReference();
8472 test_CreateFontFileReference();
8473 test_shared_isolated();
8474 test_GetUnicodeRanges();
8475 test_GetFontFromFontFace();
8476 test_GetFirstMatchingFont();
8477 test_GetMatchingFonts();
8478 test_GetInformationalStrings();
8479 test_GetGdiInterop();
8480 test_CreateFontFaceFromHdc();
8481 test_GetSimulations();
8482 test_GetFaceNames();
8483 test_TryGetFontTable();
8484 test_ConvertFontToLOGFONT();
8485 test_CreateStreamFromKey();
8486 test_ReadFileFragment();
8487 test_GetDesignGlyphMetrics();
8488 test_GetDesignGlyphAdvances();
8489 test_IsMonospacedFont();
8490 test_GetGlyphRunOutline();
8491 test_GetEudcFontCollection();
8492 test_GetCaretMetrics();
8493 test_GetGlyphCount();
8494 test_GetKerningPairAdjustments();
8495 test_CreateRenderingParams();
8496 test_CreateGlyphRunAnalysis();
8497 test_GetGdiCompatibleMetrics();
8498 test_GetPanose();
8499 test_GetGdiCompatibleGlyphAdvances();
8500 test_GetRecommendedRenderingMode();
8501 test_GetAlphaBlendParams();
8502 test_CreateAlphaTexture();
8503 test_IsSymbolFont();
8504 test_GetPaletteEntries();
8505 test_TranslateColorGlyphRun();
8506 test_HasCharacter();
8507 test_CreateFontFaceReference();
8508 test_GetFontSignature();
8509 test_font_properties();
8510 test_HasVerticalGlyphVariants();
8511 test_HasKerningPairs();
8512 test_ComputeGlyphOrigins();
8513 test_inmemory_file_loader();
8514 test_GetGlyphImageFormats();
8515 test_CreateCustomRenderingParams();
8516 test_localfontfileloader();
8517 test_AnalyzeContainerType();
8518 test_fontsetbuilder();
8520 IDWriteFactory_Release(factory);