dwrite: Improve ConvertFontFaceToLOGFONT using same logic IDWriteFont uses.
[wine.git] / dlls / dwrite / tests / font.c
blobd5126fffbb95699273790145c14e70744343df50
1 /*
2 * Font related tests
4 * Copyright 2012, 2014-2016 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')
45 #ifdef WORDS_BIGENDIAN
46 #define GET_BE_WORD(x) (x)
47 #define GET_BE_DWORD(x) (x)
48 #else
49 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
50 #define GET_BE_DWORD(x) RtlUlongByteSwap(x)
51 #endif
53 #define EXPECT_HR(hr,hr_exp) \
54 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
56 #define DEFINE_EXPECT(func) \
57 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
59 #define SET_EXPECT(func) \
60 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
62 #define CHECK_EXPECT2(func) \
63 do { \
64 ok(expect_ ##func, "unexpected call " #func "\n"); \
65 called_ ## func = TRUE; \
66 }while(0)
68 #define CHECK_EXPECT(func) \
69 do { \
70 CHECK_EXPECT2(func); \
71 expect_ ## func = FALSE; \
72 }while(0)
74 #define CHECK_CALLED(func) \
75 do { \
76 ok(called_ ## func, "expected " #func "\n"); \
77 expect_ ## func = called_ ## func = FALSE; \
78 }while(0)
80 #define CLEAR_CALLED(func) \
81 expect_ ## func = called_ ## func = FALSE
83 DEFINE_EXPECT(setfillmode);
85 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
86 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
88 ULONG rc;
89 IUnknown_AddRef(obj);
90 rc = IUnknown_Release(obj);
91 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
94 static inline void *heap_alloc(size_t len)
96 return HeapAlloc(GetProcessHeap(), 0, len);
99 static inline BOOL heap_free(void *mem)
101 return HeapFree(GetProcessHeap(), 0, mem);
104 static const WCHAR test_fontfile[] = {'w','i','n','e','_','t','e','s','t','_','f','o','n','t','.','t','t','f',0};
105 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
106 static const WCHAR arialW[] = {'A','r','i','a','l',0};
107 static const WCHAR tahomaUppercaseW[] = {'T','A','H','O','M','A',0};
108 static const WCHAR tahomaStrangecaseW[] = {'t','A','h','O','m','A',0};
109 static const WCHAR blahW[] = {'B','l','a','h','!',0};
110 static const WCHAR emojiW[] = {'S','e','g','o','e',' ','U','I',' ','E','m','o','j','i',0};
112 /* PANOSE is 10 bytes in size, need to pack the structure properly */
113 #include "pshpack2.h"
114 typedef struct
116 ULONG version;
117 ULONG revision;
118 ULONG checksumadj;
119 ULONG magic;
120 USHORT flags;
121 USHORT unitsPerEm;
122 ULONGLONG created;
123 ULONGLONG modified;
124 SHORT xMin;
125 SHORT yMin;
126 SHORT xMax;
127 SHORT yMax;
128 USHORT macStyle;
129 USHORT lowestRecPPEM;
130 SHORT direction_hint;
131 SHORT index_format;
132 SHORT glyphdata_format;
133 } TT_HEAD;
135 enum TT_HEAD_MACSTYLE
137 TT_HEAD_MACSTYLE_BOLD = 1 << 0,
138 TT_HEAD_MACSTYLE_ITALIC = 1 << 1,
139 TT_HEAD_MACSTYLE_UNDERLINE = 1 << 2,
140 TT_HEAD_MACSTYLE_OUTLINE = 1 << 3,
141 TT_HEAD_MACSTYLE_SHADOW = 1 << 4,
142 TT_HEAD_MACSTYLE_CONDENSED = 1 << 5,
143 TT_HEAD_MACSTYLE_EXTENDED = 1 << 6,
146 typedef struct
148 USHORT version;
149 SHORT xAvgCharWidth;
150 USHORT usWeightClass;
151 USHORT usWidthClass;
152 SHORT fsType;
153 SHORT ySubscriptXSize;
154 SHORT ySubscriptYSize;
155 SHORT ySubscriptXOffset;
156 SHORT ySubscriptYOffset;
157 SHORT ySuperscriptXSize;
158 SHORT ySuperscriptYSize;
159 SHORT ySuperscriptXOffset;
160 SHORT ySuperscriptYOffset;
161 SHORT yStrikeoutSize;
162 SHORT yStrikeoutPosition;
163 SHORT sFamilyClass;
164 PANOSE panose;
165 ULONG ulUnicodeRange1;
166 ULONG ulUnicodeRange2;
167 ULONG ulUnicodeRange3;
168 ULONG ulUnicodeRange4;
169 CHAR achVendID[4];
170 USHORT fsSelection;
171 USHORT usFirstCharIndex;
172 USHORT usLastCharIndex;
173 /* According to the Apple spec, original version didn't have the below fields,
174 * version numbers were taken from the OpenType spec.
176 /* version 0 (TrueType 1.5) */
177 USHORT sTypoAscender;
178 USHORT sTypoDescender;
179 USHORT sTypoLineGap;
180 USHORT usWinAscent;
181 USHORT usWinDescent;
182 /* version 1 (TrueType 1.66) */
183 ULONG ulCodePageRange1;
184 ULONG ulCodePageRange2;
185 /* version 2 (OpenType 1.2) */
186 SHORT sxHeight;
187 SHORT sCapHeight;
188 USHORT usDefaultChar;
189 USHORT usBreakChar;
190 USHORT usMaxContext;
191 } TT_OS2_V2;
193 enum OS2_FSSELECTION {
194 OS2_FSSELECTION_ITALIC = 1 << 0,
195 OS2_FSSELECTION_UNDERSCORE = 1 << 1,
196 OS2_FSSELECTION_NEGATIVE = 1 << 2,
197 OS2_FSSELECTION_OUTLINED = 1 << 3,
198 OS2_FSSELECTION_STRIKEOUT = 1 << 4,
199 OS2_FSSELECTION_BOLD = 1 << 5,
200 OS2_FSSELECTION_REGULAR = 1 << 6,
201 OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7,
202 OS2_FSSELECTION_WWS = 1 << 8,
203 OS2_FSSELECTION_OBLIQUE = 1 << 9
206 typedef struct {
207 ULONG Version;
208 ULONG italicAngle;
209 SHORT underlinePosition;
210 SHORT underlineThickness;
211 ULONG fixed_pitch;
212 ULONG minmemType42;
213 ULONG maxmemType42;
214 ULONG minmemType1;
215 ULONG maxmemType1;
216 } TT_POST;
218 typedef struct {
219 ULONG version;
220 SHORT ascender;
221 SHORT descender;
222 SHORT linegap;
223 USHORT advanceWidthMax;
224 SHORT minLeftSideBearing;
225 SHORT minRightSideBearing;
226 SHORT xMaxExtent;
227 SHORT caretSlopeRise;
228 SHORT caretSlopeRun;
229 SHORT caretOffset;
230 SHORT reserved[4];
231 SHORT metricDataFormat;
232 USHORT numberOfHMetrics;
233 } TT_HHEA;
235 typedef struct {
236 DWORD version;
237 WORD ScriptList;
238 WORD FeatureList;
239 WORD LookupList;
240 } GSUB_Header;
242 typedef struct {
243 CHAR FeatureTag[4];
244 WORD Feature;
245 } OT_FeatureRecord;
247 typedef struct {
248 WORD FeatureCount;
249 OT_FeatureRecord FeatureRecord[1];
250 } OT_FeatureList;
252 typedef struct {
253 WORD FeatureParams;
254 WORD LookupCount;
255 WORD LookupListIndex[1];
256 } OT_Feature;
258 typedef struct {
259 WORD LookupCount;
260 WORD Lookup[1];
261 } OT_LookupList;
263 typedef struct {
264 WORD LookupType;
265 WORD LookupFlag;
266 WORD SubTableCount;
267 WORD SubTable[1];
268 } OT_LookupTable;
270 typedef struct {
271 WORD SubstFormat;
272 WORD Coverage;
273 WORD DeltaGlyphID;
274 } GSUB_SingleSubstFormat1;
276 typedef struct {
277 WORD SubstFormat;
278 WORD Coverage;
279 WORD GlyphCount;
280 WORD Substitute[1];
281 } GSUB_SingleSubstFormat2;
283 typedef struct {
284 WORD SubstFormat;
285 WORD ExtensionLookupType;
286 DWORD ExtensionOffset;
287 } GSUB_ExtensionPosFormat1;
289 #include "poppack.h"
291 static IDWriteFactory *create_factory(void)
293 IDWriteFactory *factory;
294 HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
295 ok(hr == S_OK, "got 0x%08x\n", hr);
296 return factory;
299 static IDWriteFontFace *create_fontface(IDWriteFactory *factory)
301 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
302 IDWriteGdiInterop *interop;
303 IDWriteFontFace *fontface;
304 IDWriteFont *font;
305 LOGFONTW logfont;
306 HRESULT hr;
308 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
309 ok(hr == S_OK, "got 0x%08x\n", hr);
311 memset(&logfont, 0, sizeof(logfont));
312 logfont.lfHeight = 12;
313 logfont.lfWidth = 12;
314 logfont.lfWeight = FW_NORMAL;
315 logfont.lfItalic = 1;
316 lstrcpyW(logfont.lfFaceName, tahomaW);
318 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
319 ok(hr == S_OK, "got 0x%08x\n", hr);
321 hr = IDWriteFont_CreateFontFace(font, &fontface);
322 ok(hr == S_OK, "got 0x%08x\n", hr);
324 IDWriteFont_Release(font);
325 IDWriteGdiInterop_Release(interop);
327 return fontface;
330 static IDWriteFont *get_font(IDWriteFactory *factory, const WCHAR *name, DWRITE_FONT_STYLE style)
332 IDWriteFontCollection *collection;
333 IDWriteFontFamily *family;
334 IDWriteFont *font = NULL;
335 UINT32 index;
336 BOOL exists;
337 HRESULT hr;
339 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
340 ok(hr == S_OK, "got 0x%08x\n", hr);
342 index = ~0;
343 exists = FALSE;
344 hr = IDWriteFontCollection_FindFamilyName(collection, name, &index, &exists);
345 ok(hr == S_OK, "got 0x%08x\n", hr);
346 if (!exists) goto not_found;
348 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
349 ok(hr == S_OK, "got 0x%08x\n", hr);
351 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
352 DWRITE_FONT_STRETCH_NORMAL, style, &font);
353 ok(hr == S_OK, "got 0x%08x\n", hr);
355 IDWriteFontFamily_Release(family);
356 not_found:
357 IDWriteFontCollection_Release(collection);
358 return font;
361 static IDWriteFont *get_tahoma_instance(IDWriteFactory *factory, DWRITE_FONT_STYLE style)
363 IDWriteFont *font = get_font(factory, tahomaW, style);
364 ok(font != NULL, "failed to get Tahoma\n");
365 return font;
368 static WCHAR *create_testfontfile(const WCHAR *filename)
370 static WCHAR pathW[MAX_PATH];
371 DWORD written;
372 HANDLE file;
373 HRSRC res;
374 void *ptr;
376 GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
377 lstrcatW(pathW, filename);
379 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
380 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW),
381 GetLastError());
383 res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
384 ok( res != 0, "couldn't find resource\n" );
385 ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
386 WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
387 ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
388 CloseHandle( file );
390 return pathW;
393 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
394 static void _delete_testfontfile(const WCHAR *filename, int line)
396 BOOL ret = DeleteFileW(filename);
397 ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError());
400 struct test_fontenumerator
402 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
403 LONG ref;
405 DWORD index;
406 IDWriteFontFile *font_file;
409 static inline struct test_fontenumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
411 return CONTAINING_RECORD(iface, struct test_fontenumerator, IDWriteFontFileEnumerator_iface);
414 static HRESULT WINAPI singlefontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
416 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
418 *obj = iface;
419 IDWriteFontFileEnumerator_AddRef(iface);
420 return S_OK;
422 return E_NOINTERFACE;
425 static ULONG WINAPI singlefontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
427 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
428 return InterlockedIncrement(&This->ref);
431 static ULONG WINAPI singlefontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
433 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
434 ULONG ref = InterlockedDecrement(&This->ref);
435 if (!ref) {
436 IDWriteFontFile_Release(This->font_file);
437 heap_free(This);
439 return ref;
442 static HRESULT WINAPI singlefontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **font_file)
444 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
445 IDWriteFontFile_AddRef(This->font_file);
446 *font_file = This->font_file;
447 return S_OK;
450 static HRESULT WINAPI singlefontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
452 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
454 if (This->index > 1) {
455 *current = FALSE;
456 return S_OK;
459 This->index++;
460 *current = TRUE;
461 return S_OK;
464 static const struct IDWriteFontFileEnumeratorVtbl singlefontfileenumeratorvtbl =
466 singlefontfileenumerator_QueryInterface,
467 singlefontfileenumerator_AddRef,
468 singlefontfileenumerator_Release,
469 singlefontfileenumerator_MoveNext,
470 singlefontfileenumerator_GetCurrentFontFile
473 static HRESULT create_enumerator(IDWriteFontFile *font_file, IDWriteFontFileEnumerator **ret)
475 struct test_fontenumerator *enumerator;
477 enumerator = heap_alloc(sizeof(struct test_fontenumerator));
478 if (!enumerator)
479 return E_OUTOFMEMORY;
481 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &singlefontfileenumeratorvtbl;
482 enumerator->ref = 1;
483 enumerator->index = 0;
484 enumerator->font_file = font_file;
485 IDWriteFontFile_AddRef(font_file);
487 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
488 return S_OK;
491 struct test_fontcollectionloader
493 IDWriteFontCollectionLoader IDWriteFontFileCollectionLoader_iface;
494 IDWriteFontFileLoader *loader;
497 static inline struct test_fontcollectionloader *impl_from_IDWriteFontFileCollectionLoader(IDWriteFontCollectionLoader* iface)
499 return CONTAINING_RECORD(iface, struct test_fontcollectionloader, IDWriteFontFileCollectionLoader_iface);
502 static HRESULT WINAPI resourcecollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
504 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontCollectionLoader))
506 *obj = iface;
507 IDWriteFontCollectionLoader_AddRef(iface);
508 return S_OK;
510 return E_NOINTERFACE;
513 static ULONG WINAPI resourcecollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
515 return 2;
518 static ULONG WINAPI resourcecollectionloader_Release(IDWriteFontCollectionLoader *iface)
520 return 1;
523 static HRESULT WINAPI resourcecollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory,
524 const void * collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator ** fontFileEnumerator)
526 struct test_fontcollectionloader *This = impl_from_IDWriteFontFileCollectionLoader(iface);
527 IDWriteFontFile *font_file;
528 HRESULT hr;
530 IDWriteFactory_CreateCustomFontFileReference(factory, collectionKey, collectionKeySize, This->loader, &font_file);
532 hr = create_enumerator(font_file, fontFileEnumerator);
533 ok(hr == S_OK, "got 0x%08x\n", hr);
535 IDWriteFontFile_Release(font_file);
536 return hr;
539 static const struct IDWriteFontCollectionLoaderVtbl resourcecollectionloadervtbl = {
540 resourcecollectionloader_QueryInterface,
541 resourcecollectionloader_AddRef,
542 resourcecollectionloader_Release,
543 resourcecollectionloader_CreateEnumeratorFromKey
546 /* Here is a functional custom font set of interfaces */
547 struct test_fontdatastream
549 IDWriteFontFileStream IDWriteFontFileStream_iface;
550 LONG ref;
552 LPVOID data;
553 DWORD size;
556 static inline struct test_fontdatastream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream* iface)
558 return CONTAINING_RECORD(iface, struct test_fontdatastream, IDWriteFontFileStream_iface);
561 static HRESULT WINAPI fontdatastream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
563 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
565 *obj = iface;
566 IDWriteFontFileStream_AddRef(iface);
567 return S_OK;
569 *obj = NULL;
570 return E_NOINTERFACE;
573 static ULONG WINAPI fontdatastream_AddRef(IDWriteFontFileStream *iface)
575 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
576 ULONG ref = InterlockedIncrement(&This->ref);
577 return ref;
580 static ULONG WINAPI fontdatastream_Release(IDWriteFontFileStream *iface)
582 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
583 ULONG ref = InterlockedDecrement(&This->ref);
584 if (ref == 0)
585 HeapFree(GetProcessHeap(), 0, This);
586 return ref;
589 static HRESULT WINAPI fontdatastream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
591 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
592 *fragment_context = NULL;
593 if (offset+fragment_size > This->size)
595 *fragment_start = NULL;
596 return E_FAIL;
598 else
600 *fragment_start = (BYTE*)This->data + offset;
601 return S_OK;
605 static void WINAPI fontdatastream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
607 /* Do Nothing */
610 static HRESULT WINAPI fontdatastream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
612 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
613 *size = This->size;
614 return S_OK;
617 static HRESULT WINAPI fontdatastream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
619 return E_NOTIMPL;
622 static const IDWriteFontFileStreamVtbl fontdatastreamvtbl =
624 fontdatastream_QueryInterface,
625 fontdatastream_AddRef,
626 fontdatastream_Release,
627 fontdatastream_ReadFileFragment,
628 fontdatastream_ReleaseFileFragment,
629 fontdatastream_GetFileSize,
630 fontdatastream_GetLastWriteTime
633 static HRESULT create_fontdatastream(LPVOID data, UINT size, IDWriteFontFileStream** iface)
635 struct test_fontdatastream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct test_fontdatastream));
636 if (!This)
637 return E_OUTOFMEMORY;
639 This->data = data;
640 This->size = size;
641 This->ref = 1;
642 This->IDWriteFontFileStream_iface.lpVtbl = &fontdatastreamvtbl;
644 *iface = &This->IDWriteFontFileStream_iface;
645 return S_OK;
648 static HRESULT WINAPI resourcefontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
650 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
652 *obj = iface;
653 return S_OK;
655 *obj = NULL;
656 return E_NOINTERFACE;
659 static ULONG WINAPI resourcefontfileloader_AddRef(IDWriteFontFileLoader *iface)
661 return 2;
664 static ULONG WINAPI resourcefontfileloader_Release(IDWriteFontFileLoader *iface)
666 return 1;
669 static HRESULT WINAPI resourcefontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
670 IDWriteFontFileStream **stream)
672 LPVOID data;
673 DWORD size;
674 HGLOBAL mem;
676 mem = LoadResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
677 ok(mem != NULL, "Failed to lock font resource\n");
678 if (mem)
680 size = SizeofResource(GetModuleHandleA(NULL), *(HRSRC*)ref_key);
681 data = LockResource(mem);
682 return create_fontdatastream(data, size, stream);
684 return E_FAIL;
687 static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = {
688 resourcefontfileloader_QueryInterface,
689 resourcefontfileloader_AddRef,
690 resourcefontfileloader_Release,
691 resourcefontfileloader_CreateStreamFromKey
694 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
696 static D2D1_POINT_2F g_startpoints[2];
697 static int g_startpoint_count;
699 static HRESULT WINAPI test_geometrysink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **ret)
701 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
702 IsEqualIID(riid, &IID_IUnknown))
704 *ret = iface;
705 ID2D1SimplifiedGeometrySink_AddRef(iface);
706 return S_OK;
709 *ret = NULL;
710 return E_NOINTERFACE;
713 static ULONG WINAPI test_geometrysink_AddRef(ID2D1SimplifiedGeometrySink *iface)
715 return 2;
718 static ULONG WINAPI test_geometrysink_Release(ID2D1SimplifiedGeometrySink *iface)
720 return 1;
723 static void WINAPI test_geometrysink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
725 CHECK_EXPECT(setfillmode);
726 ok(mode == D2D1_FILL_MODE_WINDING, "fill mode %d\n", mode);
729 static void WINAPI test_geometrysink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT flags)
731 ok(0, "unexpected SetSegmentFlags() - flags %d\n", flags);
734 static void WINAPI test_geometrysink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
735 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
737 ok(figureBegin == D2D1_FIGURE_BEGIN_FILLED, "begin figure %d\n", figureBegin);
738 if (g_startpoint_count < sizeof(g_startpoints)/sizeof(g_startpoints[0]))
739 g_startpoints[g_startpoint_count] = startPoint;
740 g_startpoint_count++;
743 static void WINAPI test_geometrysink_AddLines(ID2D1SimplifiedGeometrySink *iface,
744 const D2D1_POINT_2F *points, UINT32 count)
748 static void WINAPI test_geometrysink_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
749 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
753 static void WINAPI test_geometrysink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
755 ok(figureEnd == D2D1_FIGURE_END_CLOSED, "end figure %d\n", figureEnd);
758 static HRESULT WINAPI test_geometrysink_Close(ID2D1SimplifiedGeometrySink *iface)
760 ok(0, "unexpected Close()\n");
761 return E_NOTIMPL;
764 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink_vtbl = {
765 test_geometrysink_QueryInterface,
766 test_geometrysink_AddRef,
767 test_geometrysink_Release,
768 test_geometrysink_SetFillMode,
769 test_geometrysink_SetSegmentFlags,
770 test_geometrysink_BeginFigure,
771 test_geometrysink_AddLines,
772 test_geometrysink_AddBeziers,
773 test_geometrysink_EndFigure,
774 test_geometrysink_Close
777 static void WINAPI test_geometrysink2_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
778 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
780 ok(0, "unexpected call\n");
783 static void WINAPI test_geometrysink2_AddLines(ID2D1SimplifiedGeometrySink *iface,
784 const D2D1_POINT_2F *points, UINT32 count)
786 ok(0, "unexpected call\n");
789 static void WINAPI test_geometrysink2_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
790 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
792 ok(0, "unexpected call\n");
795 static void WINAPI test_geometrysink2_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
797 ok(0, "unexpected call\n");
800 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink2_vtbl = {
801 test_geometrysink_QueryInterface,
802 test_geometrysink_AddRef,
803 test_geometrysink_Release,
804 test_geometrysink_SetFillMode,
805 test_geometrysink_SetSegmentFlags,
806 test_geometrysink2_BeginFigure,
807 test_geometrysink2_AddLines,
808 test_geometrysink2_AddBeziers,
809 test_geometrysink2_EndFigure,
810 test_geometrysink_Close
813 static ID2D1SimplifiedGeometrySink test_geomsink = { &test_geometrysink_vtbl };
814 static ID2D1SimplifiedGeometrySink test_geomsink2 = { &test_geometrysink2_vtbl };
816 static void test_CreateFontFromLOGFONT(void)
818 static const WCHAR tahomaspW[] = {'T','a','h','o','m','a',' ',0};
819 IDWriteGdiInterop1 *interop1;
820 IDWriteGdiInterop *interop;
821 DWRITE_FONT_WEIGHT weight;
822 DWRITE_FONT_STYLE style;
823 IDWriteFont *font;
824 LOGFONTW logfont;
825 LONG weights[][2] = {
826 {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
827 {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
828 { 0, DWRITE_FONT_WEIGHT_NORMAL},
829 { 50, DWRITE_FONT_WEIGHT_NORMAL},
830 {150, DWRITE_FONT_WEIGHT_NORMAL},
831 {250, DWRITE_FONT_WEIGHT_NORMAL},
832 {350, DWRITE_FONT_WEIGHT_NORMAL},
833 {450, DWRITE_FONT_WEIGHT_NORMAL},
834 {650, DWRITE_FONT_WEIGHT_BOLD},
835 {750, DWRITE_FONT_WEIGHT_BOLD},
836 {850, DWRITE_FONT_WEIGHT_BOLD},
837 {950, DWRITE_FONT_WEIGHT_BOLD},
838 {960, DWRITE_FONT_WEIGHT_BOLD},
840 OUTLINETEXTMETRICW otm;
841 IDWriteFactory *factory;
842 HRESULT hr;
843 BOOL ret;
844 HDC hdc;
845 HFONT hfont;
846 BOOL exists;
847 int i;
848 UINT r;
850 factory = create_factory();
852 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
853 EXPECT_HR(hr, S_OK);
855 if (0)
856 /* null out parameter crashes this call */
857 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
859 font = (void*)0xdeadbeef;
860 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
861 EXPECT_HR(hr, E_INVALIDARG);
862 ok(font == NULL, "got %p\n", font);
864 memset(&logfont, 0, sizeof(logfont));
865 logfont.lfHeight = 12;
866 logfont.lfWidth = 12;
867 logfont.lfWeight = FW_NORMAL;
868 logfont.lfItalic = 1;
869 lstrcpyW(logfont.lfFaceName, tahomaW);
871 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
872 EXPECT_HR(hr, S_OK);
874 hfont = CreateFontIndirectW(&logfont);
875 hdc = CreateCompatibleDC(0);
876 SelectObject(hdc, hfont);
878 otm.otmSize = sizeof(otm);
879 r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
880 ok(r, "got %d\n", r);
881 DeleteDC(hdc);
882 DeleteObject(hfont);
884 exists = TRUE;
885 hr = IDWriteFont_HasCharacter(font, 0xd800, &exists);
886 ok(hr == S_OK, "got 0x%08x\n", hr);
887 ok(exists == FALSE, "got %d\n", exists);
889 exists = FALSE;
890 hr = IDWriteFont_HasCharacter(font, 0x20, &exists);
891 ok(hr == S_OK, "got 0x%08x\n", hr);
892 ok(exists == TRUE, "got %d\n", exists);
894 /* now check properties */
895 weight = IDWriteFont_GetWeight(font);
896 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
898 style = IDWriteFont_GetStyle(font);
899 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
900 ok(otm.otmfsSelection & 1, "got 0x%08x\n", otm.otmfsSelection);
902 ret = IDWriteFont_IsSymbolFont(font);
903 ok(!ret, "got %d\n", ret);
905 IDWriteFont_Release(font);
907 /* weight values */
908 for (i = 0; i < sizeof(weights)/(2*sizeof(LONG)); i++)
910 memset(&logfont, 0, sizeof(logfont));
911 logfont.lfHeight = 12;
912 logfont.lfWidth = 12;
913 logfont.lfWeight = weights[i][0];
914 lstrcpyW(logfont.lfFaceName, tahomaW);
916 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
917 EXPECT_HR(hr, S_OK);
919 weight = IDWriteFont_GetWeight(font);
920 ok(weight == weights[i][1],
921 "%d: got %d, expected %d\n", i, weight, weights[i][1]);
923 IDWriteFont_Release(font);
926 /* weight not from enum */
927 memset(&logfont, 0, sizeof(logfont));
928 logfont.lfHeight = 12;
929 logfont.lfWidth = 12;
930 logfont.lfWeight = 550;
931 lstrcpyW(logfont.lfFaceName, tahomaW);
933 font = NULL;
934 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
935 ok(hr == S_OK, "got 0x%08x\n", hr);
937 weight = IDWriteFont_GetWeight(font);
938 ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
939 "got %d\n", weight);
940 IDWriteFont_Release(font);
942 /* empty or nonexistent face name */
943 memset(&logfont, 0, sizeof(logfont));
944 logfont.lfHeight = 12;
945 logfont.lfWidth = 12;
946 logfont.lfWeight = FW_NORMAL;
947 lstrcpyW(logfont.lfFaceName, blahW);
949 font = (void*)0xdeadbeef;
950 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
951 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
952 ok(font == NULL, "got %p\n", font);
954 /* Try with name 'Tahoma ' */
955 memset(&logfont, 0, sizeof(logfont));
956 logfont.lfHeight = 12;
957 logfont.lfWidth = 12;
958 logfont.lfWeight = FW_NORMAL;
959 lstrcpyW(logfont.lfFaceName, tahomaspW);
961 font = (void*)0xdeadbeef;
962 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
963 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
964 ok(font == NULL, "got %p\n", font);
966 /* empty string as a facename */
967 memset(&logfont, 0, sizeof(logfont));
968 logfont.lfHeight = 12;
969 logfont.lfWidth = 12;
970 logfont.lfWeight = FW_NORMAL;
972 font = (void*)0xdeadbeef;
973 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
974 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
975 ok(font == NULL, "got %p\n", font);
977 /* IDWriteGdiInterop1::CreateFontFromLOGFONT() */
978 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
979 if (hr == S_OK) {
980 memset(&logfont, 0, sizeof(logfont));
981 logfont.lfHeight = 12;
982 logfont.lfWidth = 12;
983 logfont.lfWeight = FW_NORMAL;
984 logfont.lfItalic = 1;
985 lstrcpyW(logfont.lfFaceName, tahomaW);
987 hr = IDWriteGdiInterop1_CreateFontFromLOGFONT(interop1, &logfont, NULL, &font);
988 ok(hr == S_OK, "got 0x%08x\n", hr);
990 IDWriteFont_Release(font);
991 IDWriteGdiInterop1_Release(interop1);
993 else
994 win_skip("IDWriteGdiInterop1 is not supported, skipping CreateFontFromLOGFONT() tests.\n");
996 IDWriteGdiInterop_Release(interop);
997 IDWriteFactory_Release(factory);
1000 static void test_CreateBitmapRenderTarget(void)
1002 IDWriteBitmapRenderTarget *target, *target2;
1003 IDWriteBitmapRenderTarget1 *target1;
1004 IDWriteGdiInterop *interop;
1005 IDWriteFactory *factory;
1006 HBITMAP hbm, hbm2;
1007 DWRITE_MATRIX m;
1008 DIBSECTION ds;
1009 XFORM xform;
1010 COLORREF c;
1011 HRESULT hr;
1012 FLOAT pdip;
1013 SIZE size;
1014 HDC hdc;
1015 int ret;
1017 factory = create_factory();
1019 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1020 EXPECT_HR(hr, S_OK);
1022 target = NULL;
1023 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
1024 EXPECT_HR(hr, S_OK);
1026 if (0) /* crashes on native */
1027 hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
1029 size.cx = size.cy = -1;
1030 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1031 EXPECT_HR(hr, S_OK);
1032 ok(size.cx == 0, "got %d\n", size.cx);
1033 ok(size.cy == 0, "got %d\n", size.cy);
1035 target2 = NULL;
1036 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
1037 EXPECT_HR(hr, S_OK);
1038 ok(target != target2, "got %p, %p\n", target2, target);
1039 IDWriteBitmapRenderTarget_Release(target2);
1041 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1042 ok(hdc != NULL, "got %p\n", hdc);
1044 /* test mode */
1045 ret = GetGraphicsMode(hdc);
1046 ok(ret == GM_ADVANCED, "got %d\n", ret);
1048 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1049 ok(hbm != NULL, "got %p\n", hbm);
1051 /* check DIB properties */
1052 ret = GetObjectW(hbm, sizeof(ds), &ds);
1053 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1054 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1055 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1056 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1057 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1058 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1060 IDWriteBitmapRenderTarget_Release(target);
1062 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1063 ok(!hbm, "got %p\n", hbm);
1065 target = NULL;
1066 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
1067 EXPECT_HR(hr, S_OK);
1069 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
1070 ok(hdc != NULL, "got %p\n", hdc);
1072 /* test context settings */
1073 c = GetTextColor(hdc);
1074 ok(c == RGB(0, 0, 0), "got 0x%08x\n", c);
1075 ret = GetBkMode(hdc);
1076 ok(ret == OPAQUE, "got %d\n", ret);
1077 c = GetBkColor(hdc);
1078 ok(c == RGB(255, 255, 255), "got 0x%08x\n", c);
1080 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
1081 ok(hbm != NULL, "got %p\n", hbm);
1083 /* check DIB properties */
1084 ret = GetObjectW(hbm, sizeof(ds), &ds);
1085 ok(ret == sizeof(ds), "got %d\n", ret);
1086 ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
1087 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1088 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1089 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1090 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1092 size.cx = size.cy = -1;
1093 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1094 EXPECT_HR(hr, S_OK);
1095 ok(size.cx == 10, "got %d\n", size.cx);
1096 ok(size.cy == 5, "got %d\n", size.cy);
1098 /* resize to same size */
1099 hr = IDWriteBitmapRenderTarget_Resize(target, 10, 5);
1100 ok(hr == S_OK, "got 0x%08x\n", hr);
1102 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1103 ok(hbm2 == hbm, "got %p, %p\n", hbm2, hbm);
1105 /* shrink */
1106 hr = IDWriteBitmapRenderTarget_Resize(target, 5, 5);
1107 ok(hr == S_OK, "got 0x%08x\n", hr);
1109 size.cx = size.cy = -1;
1110 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1111 ok(hr == S_OK, "got 0x%08x\n", hr);
1112 ok(size.cx == 5, "got %d\n", size.cx);
1113 ok(size.cy == 5, "got %d\n", size.cy);
1115 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1116 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1118 hr = IDWriteBitmapRenderTarget_Resize(target, 20, 5);
1119 ok(hr == S_OK, "got 0x%08x\n", hr);
1121 size.cx = size.cy = -1;
1122 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1123 ok(hr == S_OK, "got 0x%08x\n", hr);
1124 ok(size.cx == 20, "got %d\n", size.cx);
1125 ok(size.cy == 5, "got %d\n", size.cy);
1127 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1128 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1130 hr = IDWriteBitmapRenderTarget_Resize(target, 1, 5);
1131 ok(hr == S_OK, "got 0x%08x\n", hr);
1133 size.cx = size.cy = -1;
1134 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1135 ok(hr == S_OK, "got 0x%08x\n", hr);
1136 ok(size.cx == 1, "got %d\n", size.cx);
1137 ok(size.cy == 5, "got %d\n", size.cy);
1139 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1140 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1142 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1143 ok(ret == sizeof(ds), "got %d\n", ret);
1144 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1145 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
1146 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1147 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
1148 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
1150 /* empty rectangle */
1151 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 5);
1152 ok(hr == S_OK, "got 0x%08x\n", hr);
1154 size.cx = size.cy = -1;
1155 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
1156 ok(hr == S_OK, "got 0x%08x\n", hr);
1157 ok(size.cx == 0, "got %d\n", size.cx);
1158 ok(size.cy == 5, "got %d\n", size.cy);
1160 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
1161 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
1163 ret = GetObjectW(hbm2, sizeof(ds), &ds);
1164 ok(ret == sizeof(BITMAP), "got %d\n", ret);
1165 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
1166 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
1167 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
1168 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
1169 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
1171 /* transform tests, current hdc transform is not immediately affected */
1172 if (0) /* crashes on native */
1173 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, NULL);
1175 memset(&m, 0xcc, sizeof(m));
1176 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1177 ok(hr == S_OK, "got 0x%08x\n", hr);
1178 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);
1179 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1180 ret = GetWorldTransform(hdc, &xform);
1181 ok(ret, "got %d\n", ret);
1182 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1183 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1185 memset(&m, 0, sizeof(m));
1186 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1187 ok(hr == S_OK, "got 0x%08x\n", hr);
1189 memset(&m, 0xcc, sizeof(m));
1190 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1191 ok(hr == S_OK, "got 0x%08x\n", hr);
1192 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);
1193 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1194 ret = GetWorldTransform(hdc, &xform);
1195 ok(ret, "got %d\n", ret);
1196 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1197 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1199 memset(&m, 0, sizeof(m));
1200 m.m11 = 2.0; m.m22 = 1.0;
1201 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
1202 ok(hr == S_OK, "got 0x%08x\n", hr);
1203 ret = GetWorldTransform(hdc, &xform);
1204 ok(ret, "got %d\n", ret);
1205 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
1206 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
1208 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, NULL);
1209 ok(hr == S_OK, "got 0x%08x\n", hr);
1211 memset(&m, 0xcc, sizeof(m));
1212 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
1213 ok(hr == S_OK, "got 0x%08x\n", hr);
1214 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);
1215 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
1217 /* pixels per dip */
1218 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1219 ok(pdip == 1.0, "got %.2f\n", pdip);
1221 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
1222 ok(hr == S_OK, "got 0x%08x\n", hr);
1224 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, -1.0);
1225 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1227 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 0.0);
1228 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1230 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
1231 ok(pdip == 2.0, "got %.2f\n", pdip);
1233 hr = IDWriteBitmapRenderTarget_QueryInterface(target, &IID_IDWriteBitmapRenderTarget1, (void**)&target1);
1234 if (hr == S_OK) {
1235 DWRITE_TEXT_ANTIALIAS_MODE mode;
1237 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1238 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1240 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE+1);
1241 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1243 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1244 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
1246 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
1247 ok(hr == S_OK, "got 0x%08x\n", hr);
1249 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1250 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, "got %d\n", mode);
1252 IDWriteBitmapRenderTarget1_Release(target1);
1254 else
1255 win_skip("IDWriteBitmapRenderTarget1 is not supported.\n");
1257 IDWriteBitmapRenderTarget_Release(target);
1258 IDWriteGdiInterop_Release(interop);
1259 IDWriteFactory_Release(factory);
1262 static void test_GetFontFamily(void)
1264 IDWriteFontCollection *collection, *collection2;
1265 IDWriteFontCollection *syscoll;
1266 IDWriteFontFamily *family, *family2;
1267 IDWriteFontFamily1 *family1;
1268 IDWriteGdiInterop *interop;
1269 IDWriteFont *font, *font2;
1270 IDWriteFactory *factory;
1271 LOGFONTW logfont;
1272 HRESULT hr;
1274 factory = create_factory();
1276 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1277 EXPECT_HR(hr, S_OK);
1279 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1280 ok(hr == S_OK, "got 0x%08x\n", hr);
1282 memset(&logfont, 0, sizeof(logfont));
1283 logfont.lfHeight = 12;
1284 logfont.lfWidth = 12;
1285 logfont.lfWeight = FW_NORMAL;
1286 logfont.lfItalic = 1;
1287 lstrcpyW(logfont.lfFaceName, tahomaW);
1289 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1290 ok(hr == S_OK, "got 0x%08x\n", hr);
1292 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1293 ok(hr == S_OK, "got 0x%08x\n", hr);
1294 ok(font2 != font, "got %p, %p\n", font2, font);
1296 if (0) /* crashes on native */
1297 hr = IDWriteFont_GetFontFamily(font, NULL);
1299 EXPECT_REF(font, 1);
1300 hr = IDWriteFont_GetFontFamily(font, &family);
1301 EXPECT_HR(hr, S_OK);
1302 EXPECT_REF(font, 1);
1303 EXPECT_REF(family, 2);
1305 hr = IDWriteFont_GetFontFamily(font, &family2);
1306 EXPECT_HR(hr, S_OK);
1307 ok(family2 == family, "got %p, previous %p\n", family2, family);
1308 EXPECT_REF(font, 1);
1309 EXPECT_REF(family, 3);
1310 IDWriteFontFamily_Release(family2);
1312 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
1313 EXPECT_HR(hr, E_NOINTERFACE);
1314 ok(family2 == NULL, "got %p\n", family2);
1316 hr = IDWriteFont_GetFontFamily(font2, &family2);
1317 ok(hr == S_OK, "got 0x%08x\n", hr);
1318 ok(family2 != family, "got %p, %p\n", family2, family);
1320 collection = NULL;
1321 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
1322 ok(hr == S_OK, "got 0x%08x\n", hr);
1324 collection2 = NULL;
1325 hr = IDWriteFontFamily_GetFontCollection(family2, &collection2);
1326 ok(hr == S_OK, "got 0x%08x\n", hr);
1327 ok(collection == collection2, "got %p, %p\n", collection, collection2);
1328 ok(collection == syscoll, "got %p, %p\n", collection, syscoll);
1330 IDWriteFont_Release(font);
1331 IDWriteFont_Release(font2);
1333 hr = IDWriteFontFamily_QueryInterface(family, &IID_IDWriteFontFamily1, (void**)&family1);
1334 if (hr == S_OK) {
1335 IDWriteFontFaceReference *ref, *ref1;
1336 IDWriteFontList *fontlist;
1337 IDWriteFont3 *font3;
1338 IDWriteFont1 *font1;
1340 font3 = (void*)0xdeadbeef;
1341 hr = IDWriteFontFamily1_GetFont(family1, ~0u, &font3);
1342 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1343 ok(font3 == NULL, "got %p\n", font3);
1345 hr = IDWriteFontFamily1_GetFont(family1, 0, &font3);
1346 ok(hr == S_OK, "got 0x%08x\n", hr);
1348 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont, (void**)&font);
1349 ok(hr == S_OK, "got 0x%08x\n", hr);
1350 IDWriteFont_Release(font);
1352 hr = IDWriteFont3_QueryInterface(font3, &IID_IDWriteFont1, (void**)&font1);
1353 ok(hr == S_OK, "got 0x%08x\n", hr);
1354 IDWriteFont1_Release(font1);
1356 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList1, (void**)&fontlist);
1357 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1359 hr = IDWriteFontFamily1_QueryInterface(family1, &IID_IDWriteFontList, (void**)&fontlist);
1360 ok(hr == S_OK, "got 0x%08x\n", hr);
1361 IDWriteFontList_Release(fontlist);
1363 IDWriteFont3_Release(font3);
1365 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref);
1366 ok(hr == S_OK, "got 0x%08x\n", hr);
1368 hr = IDWriteFontFamily1_GetFontFaceReference(family1, 0, &ref1);
1369 ok(hr == S_OK, "got 0x%08x\n", hr);
1370 ok(ref != ref1, "got %p, %p\n", ref, ref1);
1372 IDWriteFontFaceReference_Release(ref);
1373 IDWriteFontFaceReference_Release(ref1);
1375 IDWriteFontFamily1_Release(family1);
1377 else
1378 win_skip("IDWriteFontFamily1 is not supported.\n");
1380 IDWriteFontCollection_Release(syscoll);
1381 IDWriteFontCollection_Release(collection2);
1382 IDWriteFontCollection_Release(collection);
1383 IDWriteFontFamily_Release(family2);
1384 IDWriteFontFamily_Release(family);
1385 IDWriteGdiInterop_Release(interop);
1386 IDWriteFactory_Release(factory);
1389 static void test_GetFamilyNames(void)
1391 IDWriteFontFamily *family;
1392 IDWriteLocalizedStrings *names, *names2;
1393 IDWriteGdiInterop *interop;
1394 IDWriteFactory *factory;
1395 IDWriteFont *font;
1396 LOGFONTW logfont;
1397 WCHAR buffer[100];
1398 HRESULT hr;
1399 UINT32 len;
1401 factory = create_factory();
1403 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1404 EXPECT_HR(hr, S_OK);
1406 memset(&logfont, 0, sizeof(logfont));
1407 logfont.lfHeight = 12;
1408 logfont.lfWidth = 12;
1409 logfont.lfWeight = FW_NORMAL;
1410 logfont.lfItalic = 1;
1411 lstrcpyW(logfont.lfFaceName, tahomaW);
1413 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1414 EXPECT_HR(hr, S_OK);
1416 hr = IDWriteFont_GetFontFamily(font, &family);
1417 EXPECT_HR(hr, S_OK);
1419 if (0) /* crashes on native */
1420 hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
1422 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1423 ok(hr == S_OK, "got 0x%08x\n", hr);
1424 EXPECT_REF(names, 1);
1426 hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
1427 ok(hr == S_OK, "got 0x%08x\n", hr);
1428 EXPECT_REF(names2, 1);
1429 ok(names != names2, "got %p, was %p\n", names2, names);
1431 IDWriteLocalizedStrings_Release(names2);
1433 /* GetStringLength */
1434 if (0) /* crashes on native */
1435 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
1437 len = 100;
1438 hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
1439 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1440 ok(len == (UINT32)-1, "got %u\n", len);
1442 len = 0;
1443 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
1444 ok(hr == S_OK, "got 0x%08x\n", hr);
1445 ok(len > 0, "got %u\n", len);
1447 /* GetString */
1448 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
1449 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1451 hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
1452 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1454 if (0)
1455 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
1457 buffer[0] = 1;
1458 hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
1459 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1460 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1462 buffer[0] = 1;
1463 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
1464 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1465 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1467 buffer[0] = 1;
1468 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
1469 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1470 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1472 buffer[0] = 0;
1473 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1474 ok(hr == S_OK, "got 0x%08x\n", hr);
1475 ok(buffer[0] != 0, "got %x\n", buffer[0]);
1477 IDWriteLocalizedStrings_Release(names);
1479 IDWriteFontFamily_Release(family);
1480 IDWriteFont_Release(font);
1481 IDWriteGdiInterop_Release(interop);
1482 IDWriteFactory_Release(factory);
1485 static void test_CreateFontFace(void)
1487 IDWriteFontFace *fontface, *fontface2;
1488 IDWriteFontCollection *collection;
1489 DWRITE_FONT_FILE_TYPE file_type;
1490 DWRITE_FONT_FACE_TYPE face_type;
1491 IDWriteGdiInterop *interop;
1492 IDWriteFont *font, *font2;
1493 IDWriteFontFamily *family;
1494 IDWriteFactory *factory;
1495 IDWriteFontFile *file;
1496 LOGFONTW logfont;
1497 BOOL supported;
1498 UINT32 count;
1499 WCHAR *path;
1500 HRESULT hr;
1502 factory = create_factory();
1504 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1505 EXPECT_HR(hr, S_OK);
1507 memset(&logfont, 0, sizeof(logfont));
1508 logfont.lfHeight = 12;
1509 logfont.lfWidth = 12;
1510 logfont.lfWeight = FW_NORMAL;
1511 logfont.lfItalic = 1;
1512 lstrcpyW(logfont.lfFaceName, tahomaW);
1514 font = NULL;
1515 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1516 ok(hr == S_OK, "got 0x%08x\n", hr);
1518 font2 = NULL;
1519 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1520 ok(hr == S_OK, "got 0x%08x\n", hr);
1521 ok(font != font2, "got %p, %p\n", font, font2);
1523 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
1524 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1526 if (0) /* crashes on native */
1527 hr = IDWriteFont_CreateFontFace(font, NULL);
1529 fontface = NULL;
1530 hr = IDWriteFont_CreateFontFace(font, &fontface);
1531 ok(hr == S_OK, "got 0x%08x\n", hr);
1533 fontface2 = NULL;
1534 hr = IDWriteFont_CreateFontFace(font, &fontface2);
1535 ok(hr == S_OK, "got 0x%08x\n", hr);
1536 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1537 IDWriteFontFace_Release(fontface2);
1539 fontface2 = NULL;
1540 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1541 ok(hr == S_OK, "got 0x%08x\n", hr);
1542 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1543 IDWriteFontFace_Release(fontface2);
1545 IDWriteFont_Release(font2);
1546 IDWriteFont_Release(font);
1548 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFont, (void**)&font);
1549 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL), "got 0x%08x\n", hr);
1551 IDWriteFontFace_Release(fontface);
1552 IDWriteGdiInterop_Release(interop);
1554 /* Create from system collection */
1555 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1556 ok(hr == S_OK, "got 0x%08x\n", hr);
1558 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
1559 ok(hr == S_OK, "got 0x%08x\n", hr);
1561 font = NULL;
1562 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1563 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1564 ok(hr == S_OK, "got 0x%08x\n", hr);
1566 font2 = NULL;
1567 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1568 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
1569 ok(hr == S_OK, "got 0x%08x\n", hr);
1570 ok(font != font2, "got %p, %p\n", font, font2);
1572 fontface = NULL;
1573 hr = IDWriteFont_CreateFontFace(font, &fontface);
1574 ok(hr == S_OK, "got 0x%08x\n", hr);
1576 fontface2 = NULL;
1577 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1578 ok(hr == S_OK, "got 0x%08x\n", hr);
1579 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1581 IDWriteFontFace_Release(fontface);
1582 IDWriteFontFace_Release(fontface2);
1583 IDWriteFont_Release(font2);
1584 IDWriteFont_Release(font);
1585 IDWriteFontFamily_Release(family);
1586 IDWriteFontCollection_Release(collection);
1588 /* IDWriteFactory::CreateFontFace() */
1589 path = create_testfontfile(test_fontfile);
1590 factory = create_factory();
1592 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
1593 ok(hr == S_OK, "got 0x%08x\n",hr);
1595 supported = FALSE;
1596 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1597 face_type = DWRITE_FONT_FACE_TYPE_CFF;
1598 count = 0;
1599 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &count);
1600 ok(hr == S_OK, "got 0x%08x\n", hr);
1601 ok(supported == TRUE, "got %i\n", supported);
1602 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
1603 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
1604 ok(count == 1, "got %i\n", count);
1606 /* invalid simulation flags */
1607 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, ~0u, &fontface);
1608 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1610 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0xf, &fontface);
1611 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1613 /* try mismatching face type, the one that's not supported */
1614 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1615 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
1617 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION, 1, &file, 0,
1618 DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1619 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* < win10 */, "got 0x%08x\n", hr);
1621 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_RAW_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1622 todo_wine
1623 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == E_INVALIDARG) /* older versions */, "got 0x%08x\n", hr);
1625 fontface = (void*)0xdeadbeef;
1626 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TYPE1, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1627 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1628 ok(fontface == NULL, "got %p\n", fontface);
1630 fontface = (void*)0xdeadbeef;
1631 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_VECTOR, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1632 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1633 ok(fontface == NULL, "got %p\n", fontface);
1635 fontface = (void*)0xdeadbeef;
1636 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_BITMAP, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1637 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1638 ok(fontface == NULL, "got %p\n", fontface);
1640 fontface = NULL;
1641 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_UNKNOWN, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1642 todo_wine
1643 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* < win10 */, "got 0x%08x\n", hr);
1644 if (hr == S_OK) {
1645 ok(fontface != NULL, "got %p\n", fontface);
1646 face_type = IDWriteFontFace_GetType(fontface);
1647 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %d\n", face_type);
1648 IDWriteFontFace_Release(fontface);
1651 IDWriteFontFile_Release(file);
1652 IDWriteFactory_Release(factory);
1653 DELETE_FONTFILE(path);
1656 static void get_expected_font_metrics(IDWriteFontFace *fontface, DWRITE_FONT_METRICS1 *metrics)
1658 void *os2_context, *head_context, *post_context, *hhea_context;
1659 const TT_OS2_V2 *tt_os2;
1660 const TT_HEAD *tt_head;
1661 const TT_POST *tt_post;
1662 const TT_HHEA *tt_hhea;
1663 UINT32 size;
1664 BOOL exists;
1665 HRESULT hr;
1667 memset(metrics, 0, sizeof(*metrics));
1669 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void**)&tt_os2, &size, &os2_context, &exists);
1670 ok(hr == S_OK, "got 0x%08x\n", hr);
1671 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void**)&tt_head, &size, &head_context, &exists);
1672 ok(hr == S_OK, "got 0x%08x\n", hr);
1673 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HHEA_TAG, (const void**)&tt_hhea, &size, &hhea_context, &exists);
1674 ok(hr == S_OK, "got 0x%08x\n", hr);
1675 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_POST_TAG, (const void**)&tt_post, &size, &post_context, &exists);
1676 ok(hr == S_OK, "got 0x%08x\n", hr);
1678 if (tt_head) {
1679 metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm);
1680 metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin);
1681 metrics->glyphBoxTop = GET_BE_WORD(tt_head->yMax);
1682 metrics->glyphBoxRight = GET_BE_WORD(tt_head->xMax);
1683 metrics->glyphBoxBottom = GET_BE_WORD(tt_head->yMin);
1686 if (tt_os2) {
1687 if (GET_BE_WORD(tt_os2->fsSelection) & OS2_FSSELECTION_USE_TYPO_METRICS) {
1688 SHORT descent = GET_BE_WORD(tt_os2->sTypoDescender);
1689 metrics->ascent = GET_BE_WORD(tt_os2->sTypoAscender);
1690 metrics->descent = descent < 0 ? -descent : 0;
1691 metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap);
1692 metrics->hasTypographicMetrics = TRUE;
1694 else {
1695 metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent);
1696 /* Some fonts have usWinDescent value stored as signed short, which could be wrongly
1697 interpreted as large unsigned value. */
1698 metrics->descent = abs((SHORT)GET_BE_WORD(tt_os2->usWinDescent));
1700 if (tt_hhea) {
1701 SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender);
1702 INT32 linegap;
1704 linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) -
1705 metrics->ascent - metrics->descent;
1706 metrics->lineGap = linegap > 0 ? linegap : 0;
1710 metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition);
1711 metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize);
1713 metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset);
1714 metrics->subscriptPositionY = -GET_BE_WORD(tt_os2->ySubscriptYOffset);
1715 metrics->subscriptSizeX = GET_BE_WORD(tt_os2->ySubscriptXSize);
1716 metrics->subscriptSizeY = GET_BE_WORD(tt_os2->ySubscriptYSize);
1717 metrics->superscriptPositionX = GET_BE_WORD(tt_os2->ySuperscriptXOffset);
1718 metrics->superscriptPositionY = GET_BE_WORD(tt_os2->ySuperscriptYOffset);
1719 metrics->superscriptSizeX = GET_BE_WORD(tt_os2->ySuperscriptXSize);
1720 metrics->superscriptSizeY = GET_BE_WORD(tt_os2->ySuperscriptYSize);
1723 if (tt_post) {
1724 metrics->underlinePosition = GET_BE_WORD(tt_post->underlinePosition);
1725 metrics->underlineThickness = GET_BE_WORD(tt_post->underlineThickness);
1728 if (metrics->strikethroughThickness || metrics->underlineThickness) {
1729 if (!metrics->strikethroughThickness)
1730 metrics->strikethroughThickness = metrics->underlineThickness;
1731 if (!metrics->underlineThickness)
1732 metrics->underlineThickness = metrics->strikethroughThickness;
1734 else {
1735 metrics->strikethroughThickness = metrics->designUnitsPerEm / 14;
1736 metrics->underlineThickness = metrics->designUnitsPerEm / 14;
1739 if (tt_os2)
1740 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
1741 if (tt_head)
1742 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
1743 if (tt_hhea)
1744 IDWriteFontFace_ReleaseFontTable(fontface, hhea_context);
1745 if (tt_post)
1746 IDWriteFontFace_ReleaseFontTable(fontface, post_context);
1749 static void check_font_metrics(const WCHAR *nameW, BOOL has_metrics1, const DWRITE_FONT_METRICS *got,
1750 const DWRITE_FONT_METRICS1 *expected)
1752 ok(got->designUnitsPerEm == expected->designUnitsPerEm, "font %s: designUnitsPerEm %u, expected %u\n",
1753 wine_dbgstr_w(nameW), got->designUnitsPerEm, expected->designUnitsPerEm);
1754 ok(got->ascent == expected->ascent, "font %s: ascent %u, expected %u\n", wine_dbgstr_w(nameW), got->ascent,
1755 expected->ascent);
1756 ok(got->descent == expected->descent, "font %s: descent %u, expected %u\n", wine_dbgstr_w(nameW), got->descent,
1757 expected->descent);
1758 ok(got->lineGap == expected->lineGap, "font %s: lineGap %d, expected %d\n", wine_dbgstr_w(nameW), got->lineGap,
1759 expected->lineGap);
1760 ok(got->underlinePosition == expected->underlinePosition, "font %s: underlinePosition %d, expected %d\n",
1761 wine_dbgstr_w(nameW), got->underlinePosition, expected->underlinePosition);
1762 ok(got->underlineThickness == expected->underlineThickness, "font %s: underlineThickness %u, "
1763 "expected %u\n", wine_dbgstr_w(nameW), got->underlineThickness, expected->underlineThickness);
1764 ok(got->strikethroughPosition == expected->strikethroughPosition, "font %s: strikethroughPosition %d, expected %d\n",
1765 wine_dbgstr_w(nameW), got->strikethroughPosition, expected->strikethroughPosition);
1766 ok(got->strikethroughThickness == expected->strikethroughThickness, "font %s: strikethroughThickness %u, "
1767 "expected %u\n", wine_dbgstr_w(nameW), got->strikethroughThickness, expected->strikethroughThickness);
1769 if (has_metrics1) {
1770 const DWRITE_FONT_METRICS1 *m1 = (const DWRITE_FONT_METRICS1*)got;
1771 ok(m1->hasTypographicMetrics == expected->hasTypographicMetrics, "font %s: hasTypographicMetrics %d, "
1772 "expected %d\n", wine_dbgstr_w(nameW), m1->hasTypographicMetrics, expected->hasTypographicMetrics);
1773 ok(m1->glyphBoxLeft == expected->glyphBoxLeft, "font %s: glyphBoxLeft %d, expected %d\n", wine_dbgstr_w(nameW),
1774 m1->glyphBoxLeft, expected->glyphBoxLeft);
1775 ok(m1->glyphBoxTop == expected->glyphBoxTop, "font %s: glyphBoxTop %d, expected %d\n", wine_dbgstr_w(nameW),
1776 m1->glyphBoxTop, expected->glyphBoxTop);
1777 ok(m1->glyphBoxRight == expected->glyphBoxRight, "font %s: glyphBoxRight %d, expected %d\n", wine_dbgstr_w(nameW),
1778 m1->glyphBoxRight, expected->glyphBoxRight);
1779 ok(m1->glyphBoxBottom == expected->glyphBoxBottom, "font %s: glyphBoxBottom %d, expected %d\n", wine_dbgstr_w(nameW),
1780 m1->glyphBoxBottom, expected->glyphBoxBottom);
1782 ok(m1->subscriptPositionX == expected->subscriptPositionX, "font %s: subscriptPositionX %d, expected %d\n",
1783 wine_dbgstr_w(nameW), m1->subscriptPositionX, expected->subscriptPositionX);
1784 ok(m1->subscriptPositionY == expected->subscriptPositionY, "font %s: subscriptPositionY %d, expected %d\n",
1785 wine_dbgstr_w(nameW), m1->subscriptPositionY, expected->subscriptPositionY);
1786 ok(m1->subscriptSizeX == expected->subscriptSizeX, "font %s: subscriptSizeX %d, expected %d\n",
1787 wine_dbgstr_w(nameW), m1->subscriptSizeX, expected->subscriptSizeX);
1788 ok(m1->subscriptSizeY == expected->subscriptSizeY, "font %s: subscriptSizeY %d, expected %d\n",
1789 wine_dbgstr_w(nameW), m1->subscriptSizeY, expected->subscriptSizeY);
1790 ok(m1->superscriptPositionX == expected->superscriptPositionX, "font %s: superscriptPositionX %d, expected %d\n",
1791 wine_dbgstr_w(nameW), m1->superscriptPositionX, expected->superscriptPositionX);
1792 ok(m1->superscriptPositionY == expected->superscriptPositionY, "font %s: superscriptPositionY %d, expected %d\n",
1793 wine_dbgstr_w(nameW), m1->superscriptPositionY, expected->superscriptPositionY);
1794 ok(m1->superscriptSizeX == expected->superscriptSizeX, "font %s: superscriptSizeX %d, expected %d\n",
1795 wine_dbgstr_w(nameW), m1->superscriptSizeX, expected->superscriptSizeX);
1796 ok(m1->superscriptSizeY == expected->superscriptSizeY, "font %s: superscriptSizeY %d, expected %d\n",
1797 wine_dbgstr_w(nameW), m1->superscriptSizeY, expected->superscriptSizeY);
1801 static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
1803 static const WCHAR enusW[] = {'e','n','-','u','s',0};
1804 BOOL exists = FALSE;
1805 UINT32 index;
1806 HRESULT hr;
1808 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
1809 ok(hr == S_OK, "got 0x%08x\n", hr);
1810 ok(exists, "got %d\n", exists);
1812 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
1813 ok(hr == S_OK, "got 0x%08x\n", hr);
1816 static void test_GetMetrics(void)
1818 DWRITE_FONT_METRICS metrics, metrics2;
1819 IDWriteFontCollection *syscollection;
1820 IDWriteGdiInterop *interop;
1821 IDWriteFontFace *fontface;
1822 IDWriteFactory *factory;
1823 OUTLINETEXTMETRICW otm;
1824 IDWriteFontFile *file;
1825 IDWriteFont1 *font1;
1826 IDWriteFont *font;
1827 LOGFONTW logfont;
1828 UINT32 count, i;
1829 HRESULT hr;
1830 HDC hdc;
1831 HFONT hfont;
1832 int ret;
1834 factory = create_factory();
1836 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1837 EXPECT_HR(hr, S_OK);
1839 memset(&logfont, 0, sizeof(logfont));
1840 logfont.lfHeight = 12;
1841 logfont.lfWidth = 12;
1842 logfont.lfWeight = FW_NORMAL;
1843 logfont.lfItalic = 1;
1844 lstrcpyW(logfont.lfFaceName, tahomaW);
1846 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1847 ok(hr == S_OK, "got 0x%08x\n", hr);
1849 hfont = CreateFontIndirectW(&logfont);
1850 hdc = CreateCompatibleDC(0);
1851 SelectObject(hdc, hfont);
1853 otm.otmSize = sizeof(otm);
1854 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
1855 ok(ret, "got %d\n", ret);
1856 DeleteDC(hdc);
1857 DeleteObject(hfont);
1859 if (0) /* crashes on native */
1860 IDWriteFont_GetMetrics(font, NULL);
1862 memset(&metrics, 0, sizeof(metrics));
1863 IDWriteFont_GetMetrics(font, &metrics);
1865 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
1866 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
1867 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
1868 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
1869 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
1870 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
1871 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
1872 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
1873 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
1874 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
1876 hr = IDWriteFont_CreateFontFace(font, &fontface);
1877 ok(hr == S_OK, "got 0x%08x\n", hr);
1879 memset(&metrics, 0, sizeof(metrics));
1880 IDWriteFontFace_GetMetrics(fontface, &metrics);
1882 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
1883 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
1884 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
1885 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
1886 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
1887 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
1888 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
1889 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
1890 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
1891 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
1893 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
1894 if (hr == S_OK) {
1895 DWRITE_FONT_METRICS1 metrics1;
1896 IDWriteFontFace1 *fontface1;
1898 memset(&metrics1, 0, sizeof(metrics1));
1899 IDWriteFont1_GetMetrics(font1, &metrics1);
1901 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
1902 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
1903 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
1904 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
1905 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
1906 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
1907 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
1908 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
1909 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
1910 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
1911 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
1912 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
1913 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
1914 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
1915 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
1916 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
1917 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
1918 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
1919 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
1920 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
1921 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
1923 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
1924 ok(hr == S_OK, "got 0x%08x\n", hr);
1926 memset(&metrics1, 0, sizeof(metrics1));
1927 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
1929 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
1930 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
1931 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
1932 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
1933 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
1934 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
1935 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
1936 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
1937 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
1938 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
1939 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
1940 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
1941 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
1942 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
1943 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
1944 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
1945 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
1946 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
1947 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
1948 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
1949 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
1951 IDWriteFontFace1_Release(fontface1);
1952 IDWriteFont1_Release(font1);
1954 else
1955 win_skip("DWRITE_FONT_METRICS1 is not supported.\n");
1957 IDWriteFontFace_Release(fontface);
1958 IDWriteFont_Release(font);
1959 IDWriteGdiInterop_Release(interop);
1961 /* bold simulation affects returned font metrics */
1962 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
1964 /* create regulat Tahoma with bold simulation */
1965 hr = IDWriteFont_CreateFontFace(font, &fontface);
1966 ok(hr == S_OK, "got 0x%08x\n", hr);
1968 count = 1;
1969 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
1970 ok(hr == S_OK, "got 0x%08x\n", hr);
1972 IDWriteFontFace_GetMetrics(fontface, &metrics);
1973 ok(IDWriteFontFace_GetSimulations(fontface) == 0, "wrong simulations flags\n");
1974 IDWriteFontFace_Release(fontface);
1976 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
1977 0, DWRITE_FONT_SIMULATIONS_BOLD, &fontface);
1978 ok(hr == S_OK, "got 0x%08x\n", hr);
1979 IDWriteFontFace_GetMetrics(fontface, &metrics2);
1980 ok(IDWriteFontFace_GetSimulations(fontface) == DWRITE_FONT_SIMULATIONS_BOLD, "wrong simulations flags\n");
1982 ok(metrics.ascent == metrics2.ascent, "got %u, %u\n", metrics2.ascent, metrics.ascent);
1983 ok(metrics.descent == metrics2.descent, "got %u, %u\n", metrics2.descent, metrics.descent);
1984 ok(metrics.lineGap == metrics2.lineGap, "got %d, %d\n", metrics2.lineGap, metrics.lineGap);
1985 ok(metrics.capHeight == metrics2.capHeight, "got %u, %u\n", metrics2.capHeight, metrics.capHeight);
1986 ok(metrics.xHeight == metrics2.xHeight, "got %u, %u\n", metrics2.xHeight, metrics.xHeight);
1987 ok(metrics.underlinePosition == metrics2.underlinePosition, "got %d, %d\n", metrics2.underlinePosition,
1988 metrics.underlinePosition);
1989 ok(metrics.underlineThickness == metrics2.underlineThickness, "got %u, %u\n", metrics2.underlineThickness,
1990 metrics.underlineThickness);
1991 ok(metrics.strikethroughPosition == metrics2.strikethroughPosition, "got %d, %d\n", metrics2.strikethroughPosition,
1992 metrics.strikethroughPosition);
1993 ok(metrics.strikethroughThickness == metrics2.strikethroughThickness, "got %u, %u\n", metrics2.strikethroughThickness,
1994 metrics.strikethroughThickness);
1996 IDWriteFontFile_Release(file);
1997 IDWriteFont_Release(font);
1999 /* test metrics for whole system collection */
2000 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
2001 ok(hr == S_OK, "got 0x%08x\n", hr);
2002 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
2004 for (i = 0; i < count; i++) {
2005 DWRITE_FONT_METRICS1 expected_metrics, metrics1;
2006 IDWriteLocalizedStrings *names;
2007 IDWriteFontFace1 *fontface1;
2008 IDWriteFontFamily *family;
2009 IDWriteFont *font;
2010 WCHAR nameW[256];
2012 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
2013 ok(hr == S_OK, "got 0x%08x\n", hr);
2015 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
2016 DWRITE_FONT_STYLE_NORMAL, &font);
2017 ok(hr == S_OK, "got 0x%08x\n", hr);
2019 hr = IDWriteFont_CreateFontFace(font, &fontface);
2020 ok(hr == S_OK, "got 0x%08x\n", hr);
2022 fontface1 = NULL;
2023 IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2025 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2026 ok(hr == S_OK, "got 0x%08x\n", hr);
2028 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
2030 IDWriteLocalizedStrings_Release(names);
2031 IDWriteFont_Release(font);
2033 get_expected_font_metrics(fontface, &expected_metrics);
2034 if (fontface1) {
2035 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
2036 check_font_metrics(nameW, TRUE, (const DWRITE_FONT_METRICS*)&metrics1, &expected_metrics);
2038 else {
2039 IDWriteFontFace_GetMetrics(fontface, &metrics);
2040 check_font_metrics(nameW, FALSE, &metrics, &expected_metrics);
2043 if (fontface1)
2044 IDWriteFontFace1_Release(fontface1);
2045 IDWriteFontFace_Release(fontface);
2046 IDWriteFontFamily_Release(family);
2048 IDWriteFontCollection_Release(syscollection);
2049 IDWriteFactory_Release(factory);
2052 static void test_system_fontcollection(void)
2054 IDWriteFontCollection *collection, *coll2;
2055 IDWriteLocalFontFileLoader *localloader;
2056 IDWriteFontCollection1 *collection1;
2057 IDWriteFactory *factory, *factory2;
2058 IDWriteFontFileLoader *loader;
2059 IDWriteFontFamily *family;
2060 IDWriteFontFace *fontface;
2061 IDWriteFontFile *file;
2062 IDWriteFont *font;
2063 HRESULT hr;
2064 UINT32 i;
2065 BOOL ret;
2067 factory = create_factory();
2069 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2070 ok(hr == S_OK, "got 0x%08x\n", hr);
2072 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, FALSE);
2073 ok(hr == S_OK, "got 0x%08x\n", hr);
2074 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2075 IDWriteFontCollection_Release(coll2);
2077 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, TRUE);
2078 ok(hr == S_OK, "got 0x%08x\n", hr);
2079 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
2080 IDWriteFontCollection_Release(coll2);
2082 factory2 = create_factory();
2083 hr = IDWriteFactory_GetSystemFontCollection(factory2, &coll2, FALSE);
2084 ok(hr == S_OK, "got 0x%08x\n", hr);
2085 ok(coll2 != collection, "got %p, was %p\n", coll2, collection);
2086 IDWriteFontCollection_Release(coll2);
2087 IDWriteFactory_Release(factory2);
2089 i = IDWriteFontCollection_GetFontFamilyCount(collection);
2090 ok(i, "got %u\n", i);
2092 /* invalid index */
2093 family = (void*)0xdeadbeef;
2094 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2095 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2096 ok(family == NULL, "got %p\n", family);
2098 ret = FALSE;
2099 i = (UINT32)-1;
2100 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaW, &i, &ret);
2101 ok(hr == S_OK, "got 0x%08x\n", hr);
2102 ok(ret, "got %d\n", ret);
2103 ok(i != (UINT32)-1, "got %u\n", i);
2105 ret = FALSE;
2106 i = (UINT32)-1;
2107 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaUppercaseW, &i, &ret);
2108 ok(hr == S_OK, "got 0x%08x\n", hr);
2109 ok(ret, "got %d\n", ret);
2110 ok(i != (UINT32)-1, "got %u\n", i);
2112 ret = FALSE;
2113 i = (UINT32)-1;
2114 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaStrangecaseW, &i, &ret);
2115 ok(hr == S_OK, "got 0x%08x\n", hr);
2116 ok(ret, "got %d\n", ret);
2117 ok(i != (UINT32)-1, "got %u\n", i);
2119 /* get back local file loader */
2120 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2121 ok(hr == S_OK, "got 0x%08x\n", hr);
2123 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2124 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2125 ok(hr == S_OK, "got 0x%08x\n", hr);
2126 IDWriteFontFamily_Release(family);
2128 hr = IDWriteFont_CreateFontFace(font, &fontface);
2129 ok(hr == S_OK, "got 0x%08x\n", hr);
2130 IDWriteFont_Release(font);
2132 i = 1;
2133 file = NULL;
2134 hr = IDWriteFontFace_GetFiles(fontface, &i, &file);
2135 ok(hr == S_OK, "got 0x%08x\n", hr);
2136 ok(file != NULL, "got %p\n", file);
2138 hr = IDWriteFontFile_GetLoader(file, &loader);
2139 ok(hr == S_OK, "got 0x%08x\n", hr);
2140 IDWriteFontFile_Release(file);
2142 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2143 ok(hr == S_OK, "got 0x%08x\n", hr);
2144 IDWriteLocalFontFileLoader_Release(localloader);
2146 /* local loader is not registered by default */
2147 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
2148 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2149 hr = IDWriteFactory_UnregisterFontFileLoader(factory, loader);
2150 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2152 /* try with a different factory */
2153 factory2 = create_factory();
2154 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2155 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
2156 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
2157 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2158 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2159 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
2160 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
2161 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2162 IDWriteFactory_Release(factory2);
2164 IDWriteFontFileLoader_Release(loader);
2166 ret = TRUE;
2167 i = 0;
2168 hr = IDWriteFontCollection_FindFamilyName(collection, blahW, &i, &ret);
2169 ok(hr == S_OK, "got 0x%08x\n", hr);
2170 ok(!ret, "got %d\n", ret);
2171 ok(i == (UINT32)-1, "got %u\n", i);
2173 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection1, (void**)&collection1);
2174 if (hr == S_OK) {
2175 IDWriteFontFamily1 *family1;
2177 hr = IDWriteFontCollection1_QueryInterface(collection1, &IID_IDWriteFontCollection, (void**)&coll2);
2178 ok(hr == S_OK, "got 0x%08x\n", hr);
2179 ok(coll2 == collection, "got %p, %p\n", collection, coll2);
2180 IDWriteFontCollection_Release(coll2);
2182 family1 = (void*)0xdeadbeef;
2183 hr = IDWriteFontCollection1_GetFontFamily(collection1, ~0u, &family1);
2184 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2185 ok(family1 == NULL, "got %p\n", family1);
2187 hr = IDWriteFontCollection1_GetFontFamily(collection1, 0, &family1);
2188 ok(hr == S_OK, "got 0x%08x\n", hr);
2189 IDWriteFontFamily1_Release(family1);
2190 IDWriteFontCollection1_Release(collection1);
2192 else
2193 win_skip("IDWriteFontCollection1 is not supported.\n");
2195 IDWriteFontCollection_Release(collection);
2196 IDWriteFactory_Release(factory);
2199 static void get_logfont_from_font(IDWriteFont *font, LOGFONTW *logfont)
2201 void *os2_context, *head_context;
2202 IDWriteLocalizedStrings *names;
2203 DWRITE_FONT_SIMULATIONS sim;
2204 IDWriteFontFace *fontface;
2205 const TT_OS2_V2 *tt_os2;
2206 DWRITE_FONT_STYLE style;
2207 const TT_HEAD *tt_head;
2208 LONG weight;
2209 UINT32 size;
2210 BOOL exists;
2211 HRESULT hr;
2213 /* These are rendering time properties. */
2214 logfont->lfHeight = 0;
2215 logfont->lfWidth = 0;
2216 logfont->lfEscapement = 0;
2217 logfont->lfOrientation = 0;
2218 logfont->lfUnderline = 0;
2219 logfont->lfStrikeOut = 0;
2221 logfont->lfWeight = 0;
2222 logfont->lfItalic = 0;
2224 hr = IDWriteFont_CreateFontFace(font, &fontface);
2225 ok(hr == S_OK, "Failed to create font face, %#x\n", hr);
2227 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void **)&tt_os2, &size,
2228 &os2_context, &exists);
2229 ok(hr == S_OK, "Failed to get OS/2 table, %#x\n", hr);
2231 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_HEAD_TAG, (const void **)&tt_head, &size,
2232 &head_context, &exists);
2233 ok(hr == S_OK, "Failed to get head table, %#x\n", hr);
2235 sim = IDWriteFont_GetSimulations(font);
2237 /* lfWeight */
2238 weight = FW_REGULAR;
2239 if (tt_os2) {
2240 USHORT usWeightClass = GET_BE_WORD(tt_os2->usWeightClass);
2242 if (usWeightClass >= 1 && usWeightClass <= 9)
2243 usWeightClass *= 100;
2245 if (usWeightClass > DWRITE_FONT_WEIGHT_ULTRA_BLACK)
2246 weight = DWRITE_FONT_WEIGHT_ULTRA_BLACK;
2247 else if (usWeightClass > 0)
2248 weight = usWeightClass;
2250 else if (tt_head) {
2251 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2252 if (macStyle & TT_HEAD_MACSTYLE_BOLD)
2253 weight = DWRITE_FONT_WEIGHT_BOLD;
2255 if (sim & DWRITE_FONT_SIMULATIONS_BOLD)
2256 weight += (FW_BOLD - FW_REGULAR) / 2 + 1;
2257 logfont->lfWeight = weight;
2259 /* lfItalic */
2260 if (IDWriteFont_GetSimulations(font) & DWRITE_FONT_SIMULATIONS_OBLIQUE)
2261 logfont->lfItalic = 1;
2263 style = IDWriteFont_GetStyle(font);
2264 if (!logfont->lfItalic && ((style == DWRITE_FONT_STYLE_ITALIC) || (style == DWRITE_FONT_STYLE_OBLIQUE))) {
2265 if (tt_os2) {
2266 USHORT fsSelection = GET_BE_WORD(tt_os2->fsSelection);
2267 logfont->lfItalic = !!(fsSelection & OS2_FSSELECTION_ITALIC);
2269 else if (tt_head) {
2270 USHORT macStyle = GET_BE_WORD(tt_head->macStyle);
2271 logfont->lfItalic = !!(macStyle & TT_HEAD_MACSTYLE_ITALIC);
2275 /* lfFaceName */
2276 exists = FALSE;
2277 logfont->lfFaceName[0] = 0;
2278 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &exists);
2279 if (SUCCEEDED(hr)) {
2280 if (exists) {
2281 static const WCHAR enusW[] = {'e','n','-','u','s',0};
2282 WCHAR localeW[LOCALE_NAME_MAX_LENGTH];
2283 UINT32 index;
2285 /* Fallback to en-us if there's no string for user locale. */
2286 exists = FALSE;
2287 if (GetSystemDefaultLocaleName(localeW, sizeof(localeW)/sizeof(WCHAR)))
2288 IDWriteLocalizedStrings_FindLocaleName(names, localeW, &index, &exists);
2290 if (!exists)
2291 IDWriteLocalizedStrings_FindLocaleName(names, enusW, &index, &exists);
2293 if (exists)
2294 IDWriteLocalizedStrings_GetString(names, index, logfont->lfFaceName, sizeof(logfont->lfFaceName)/sizeof(WCHAR));
2297 IDWriteLocalizedStrings_Release(names);
2300 if (tt_os2)
2301 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
2302 if (tt_head)
2303 IDWriteFontFace_ReleaseFontTable(fontface, head_context);
2304 IDWriteFontFace_Release(fontface);
2307 static void test_ConvertFontFaceToLOGFONT(void)
2309 IDWriteGdiInterop *interop;
2310 IDWriteFontFace *fontface;
2311 IDWriteFactory *factory;
2312 LOGFONTW logfont;
2313 UINT32 count, i;
2314 HRESULT hr;
2315 IDWriteFontCollection *collection;
2317 factory = create_factory();
2319 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2320 ok(hr == S_OK, "got 0x%08x\n", hr);
2322 if (0) /* crashes on native */
2324 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, NULL);
2325 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, NULL);
2327 memset(&logfont, 0xcc, sizeof(logfont));
2328 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, &logfont);
2329 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2330 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2332 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2333 ok(hr == S_OK, "got 0x%08x\n", hr);
2335 count = IDWriteFontCollection_GetFontFamilyCount(collection);
2336 for (i = 0; i < count; i++) {
2337 WCHAR nameW[128], familynameW[64], facenameW[64];
2338 IDWriteLocalizedStrings *names;
2339 DWRITE_FONT_SIMULATIONS sim;
2340 IDWriteFontFamily *family;
2341 UINT32 font_count, j;
2342 IDWriteFont *font;
2343 LOGFONTW lf;
2345 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
2346 ok(hr == S_OK, "got 0x%08x\n", hr);
2348 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
2349 ok(hr == S_OK, "got 0x%08x\n", hr);
2351 get_enus_string(names, familynameW, sizeof(familynameW)/sizeof(familynameW[0]));
2352 IDWriteLocalizedStrings_Release(names);
2354 font_count = IDWriteFontFamily_GetFontCount(family);
2356 for (j = 0; j < font_count; j++) {
2357 static const WCHAR spaceW[] = {' ', 0};
2358 IDWriteFontFace *fontface;
2360 hr = IDWriteFontFamily_GetFont(family, j, &font);
2361 ok(hr == S_OK, "got 0x%08x\n", hr);
2363 hr = IDWriteFont_GetFaceNames(font, &names);
2364 ok(hr == S_OK, "got 0x%08x\n", hr);
2366 get_enus_string(names, facenameW, sizeof(facenameW)/sizeof(facenameW[0]));
2367 IDWriteLocalizedStrings_Release(names);
2369 lstrcpyW(nameW, familynameW);
2370 lstrcatW(nameW, spaceW);
2371 lstrcatW(nameW, facenameW);
2373 hr = IDWriteFont_CreateFontFace(font, &fontface);
2374 ok(hr == S_OK, "got 0x%08x\n", hr);
2376 memset(&logfont, 0xcc, sizeof(logfont));
2377 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, &logfont);
2378 ok(hr == S_OK, "got 0x%08x\n", hr);
2380 sim = IDWriteFontFace_GetSimulations(fontface);
2382 get_logfont_from_font(font, &lf);
2383 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
2384 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
2385 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
2386 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
2387 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
2388 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
2389 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
2391 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
2392 logfont.lfOutPrecision);
2393 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
2394 logfont.lfClipPrecision);
2395 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
2396 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
2397 logfont.lfPitchAndFamily);
2399 IDWriteFontFace_Release(fontface);
2400 IDWriteFont_Release(font);
2403 IDWriteFontFamily_Release(family);
2406 IDWriteFontCollection_Release(collection);
2407 IDWriteGdiInterop_Release(interop);
2408 IDWriteFactory_Release(factory);
2411 static HRESULT WINAPI fontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
2413 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
2415 *obj = iface;
2416 IDWriteFontFileEnumerator_AddRef(iface);
2417 return S_OK;
2419 return E_NOINTERFACE;
2422 static ULONG WINAPI fontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
2424 return 2;
2427 static ULONG WINAPI fontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
2429 return 1;
2432 static HRESULT WINAPI fontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
2434 *file = NULL;
2435 return E_FAIL;
2438 static HRESULT WINAPI fontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
2440 *current = FALSE;
2441 return S_OK;
2444 static const struct IDWriteFontFileEnumeratorVtbl dwritefontfileenumeratorvtbl =
2446 fontfileenumerator_QueryInterface,
2447 fontfileenumerator_AddRef,
2448 fontfileenumerator_Release,
2449 fontfileenumerator_MoveNext,
2450 fontfileenumerator_GetCurrentFontFile,
2453 static HRESULT WINAPI fontcollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
2455 *obj = iface;
2456 return S_OK;
2459 static ULONG WINAPI fontcollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
2461 return 2;
2464 static ULONG WINAPI fontcollectionloader_Release(IDWriteFontCollectionLoader *iface)
2466 return 1;
2469 static HRESULT WINAPI fontcollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory, const void *key,
2470 UINT32 key_size, IDWriteFontFileEnumerator **ret)
2472 static IDWriteFontFileEnumerator enumerator = { &dwritefontfileenumeratorvtbl };
2473 *ret = &enumerator;
2474 return S_OK;
2477 static const struct IDWriteFontCollectionLoaderVtbl dwritefontcollectionloadervtbl = {
2478 fontcollectionloader_QueryInterface,
2479 fontcollectionloader_AddRef,
2480 fontcollectionloader_Release,
2481 fontcollectionloader_CreateEnumeratorFromKey
2484 static void test_CustomFontCollection(void)
2486 static const WCHAR fontnameW[] = {'w','i','n','e','_','t','e','s','t',0};
2487 IDWriteFontCollectionLoader collection = { &dwritefontcollectionloadervtbl };
2488 IDWriteFontCollectionLoader collection2 = { &dwritefontcollectionloadervtbl };
2489 IDWriteFontCollectionLoader collection3 = { &dwritefontcollectionloadervtbl };
2490 IDWriteFontCollection *font_collection = NULL;
2491 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
2492 struct test_fontcollectionloader resource_collection = { { &resourcecollectionloadervtbl }, &rloader };
2493 IDWriteFontFamily *family, *family2, *family3;
2494 IDWriteFontFace *idfontface, *idfontface2;
2495 IDWriteFontFile *fontfile, *fontfile2;
2496 IDWriteLocalizedStrings *string;
2497 IDWriteFont *idfont, *idfont2;
2498 IDWriteFactory *factory;
2499 UINT32 index, count;
2500 BOOL exists;
2501 HRESULT hr;
2502 HRSRC font;
2504 factory = create_factory();
2506 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, NULL);
2507 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2509 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, NULL);
2510 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2512 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &collection);
2513 ok(hr == S_OK, "got 0x%08x\n", hr);
2514 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &collection2);
2515 ok(hr == S_OK, "got 0x%08x\n", hr);
2516 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &collection);
2517 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2519 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
2520 ok(hr == S_OK, "got 0x%08x\n", hr);
2521 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
2522 ok(hr == S_OK, "got 0x%08x\n", hr);
2524 font_collection = (void*)0xdeadbeef;
2525 hr = IDWriteFactory_CreateCustomFontCollection(factory, &collection3, "Billy", 6, &font_collection);
2526 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2527 ok(font_collection == NULL, "got %p\n", font_collection);
2529 hr = IDWriteFactory_CreateCustomFontCollection(factory, &collection, "Billy", 6, &font_collection);
2530 ok(hr == S_OK, "got 0x%08x\n", hr);
2531 IDWriteFontCollection_Release(font_collection);
2533 hr = IDWriteFactory_CreateCustomFontCollection(factory, &collection2, "Billy", 6, &font_collection);
2534 ok(hr == S_OK, "got 0x%08x\n", hr);
2535 IDWriteFontCollection_Release(font_collection);
2537 font_collection = (void*)0xdeadbeef;
2538 hr = IDWriteFactory_CreateCustomFontCollection(factory, (IDWriteFontCollectionLoader*)0xdeadbeef, "Billy", 6, &font_collection);
2539 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2540 ok(font_collection == NULL, "got %p\n", font_collection);
2542 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
2543 ok(font != NULL, "Failed to find font resource\n");
2545 hr = IDWriteFactory_CreateCustomFontCollection(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface,
2546 &font, sizeof(HRSRC), &font_collection);
2547 ok(hr == S_OK, "got 0x%08x\n",hr);
2549 index = 1;
2550 exists = FALSE;
2551 hr = IDWriteFontCollection_FindFamilyName(font_collection, fontnameW, &index, &exists);
2552 ok(hr == S_OK, "got 0x%08x\n", hr);
2553 ok(index == 0, "got index %i\n", index);
2554 ok(exists, "got exists %i\n", exists);
2556 count = IDWriteFontCollection_GetFontFamilyCount(font_collection);
2557 ok(count == 1, "got %u\n", count);
2559 family = NULL;
2560 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family);
2561 ok(hr == S_OK, "got 0x%08x\n", hr);
2562 EXPECT_REF(family, 1);
2564 family2 = NULL;
2565 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family2);
2566 ok(hr == S_OK, "got 0x%08x\n", hr);
2567 EXPECT_REF(family2, 1);
2568 ok(family != family2, "got %p, %p\n", family, family2);
2570 hr = IDWriteFontFamily_GetFont(family, 0, &idfont);
2571 ok(hr == S_OK, "got 0x%08x\n", hr);
2572 EXPECT_REF(idfont, 1);
2573 EXPECT_REF(family, 2);
2574 hr = IDWriteFontFamily_GetFont(family, 0, &idfont2);
2575 ok(hr == S_OK, "got 0x%08x\n", hr);
2576 EXPECT_REF(idfont2, 1);
2577 EXPECT_REF(family, 3);
2578 ok(idfont != idfont2, "got %p, %p\n", idfont, idfont2);
2579 IDWriteFont_Release(idfont2);
2581 hr = IDWriteFont_GetInformationalStrings(idfont, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &string, &exists);
2582 ok(hr == S_OK, "got 0x%08x\n", hr);
2583 ok(exists, "got %d\n", exists);
2584 EXPECT_REF(string, 1);
2585 IDWriteLocalizedStrings_Release(string);
2587 family3 = NULL;
2588 hr = IDWriteFont_GetFontFamily(idfont, &family3);
2589 ok(hr == S_OK, "got 0x%08x\n", hr);
2590 EXPECT_REF(family, 3);
2591 ok(family == family3, "got %p, %p\n", family, family3);
2592 IDWriteFontFamily_Release(family3);
2594 idfontface = NULL;
2595 hr = IDWriteFont_CreateFontFace(idfont, &idfontface);
2596 ok(hr == S_OK, "got 0x%08x\n", hr);
2597 EXPECT_REF(idfont, 1);
2599 idfont2 = NULL;
2600 hr = IDWriteFontFamily_GetFont(family2, 0, &idfont2);
2601 ok(hr == S_OK, "got 0x%08x\n", hr);
2602 EXPECT_REF(idfont2, 1);
2603 EXPECT_REF(idfont, 1);
2604 ok(idfont2 != idfont, "Font instances should not match\n");
2606 idfontface2 = NULL;
2607 hr = IDWriteFont_CreateFontFace(idfont2, &idfontface2);
2608 ok(hr == S_OK, "got 0x%08x\n", hr);
2609 ok(idfontface2 == idfontface, "fontfaces should match\n");
2611 index = 1;
2612 fontfile = NULL;
2613 hr = IDWriteFontFace_GetFiles(idfontface, &index, &fontfile);
2614 ok(hr == S_OK, "got 0x%08x\n", hr);
2616 index = 1;
2617 fontfile2 = NULL;
2618 hr = IDWriteFontFace_GetFiles(idfontface2, &index, &fontfile2);
2619 ok(hr == S_OK, "got 0x%08x\n", hr);
2620 ok(fontfile == fontfile2, "fontfiles should match\n");
2622 IDWriteFont_Release(idfont);
2623 IDWriteFont_Release(idfont2);
2624 IDWriteFontFile_Release(fontfile);
2625 IDWriteFontFile_Release(fontfile2);
2626 IDWriteFontFace_Release(idfontface);
2627 IDWriteFontFace_Release(idfontface2);
2628 IDWriteFontFamily_Release(family2);
2629 IDWriteFontFamily_Release(family);
2630 IDWriteFontCollection_Release(font_collection);
2632 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &collection);
2633 ok(hr == S_OK, "got 0x%08x\n", hr);
2634 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &collection);
2635 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2636 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &collection2);
2637 ok(hr == S_OK, "got 0x%08x\n", hr);
2638 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
2639 ok(hr == S_OK, "got 0x%08x\n", hr);
2640 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
2641 ok(hr == S_OK, "got 0x%08x\n", hr);
2643 IDWriteFactory_Release(factory);
2646 static HRESULT WINAPI fontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
2648 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
2650 *obj = iface;
2651 IDWriteFontFileLoader_AddRef(iface);
2652 return S_OK;
2655 *obj = NULL;
2656 return E_NOINTERFACE;
2659 static ULONG WINAPI fontfileloader_AddRef(IDWriteFontFileLoader *iface)
2661 return 2;
2664 static ULONG WINAPI fontfileloader_Release(IDWriteFontFileLoader *iface)
2666 return 1;
2669 static HRESULT WINAPI fontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *ref_key, UINT32 key_size,
2670 IDWriteFontFileStream **stream)
2672 return 0x8faecafe;
2675 static const struct IDWriteFontFileLoaderVtbl dwritefontfileloadervtbl = {
2676 fontfileloader_QueryInterface,
2677 fontfileloader_AddRef,
2678 fontfileloader_Release,
2679 fontfileloader_CreateStreamFromKey
2682 static void test_CreateCustomFontFileReference(void)
2684 IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl };
2685 IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl };
2686 IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl };
2687 IDWriteFactory *factory, *factory2;
2688 IDWriteFontFileLoader *loader;
2689 IDWriteFontFile *file, *file2;
2690 BOOL support;
2691 DWRITE_FONT_FILE_TYPE file_type;
2692 DWRITE_FONT_FACE_TYPE face_type;
2693 UINT32 count;
2694 IDWriteFontFace *face, *face2;
2695 HRESULT hr;
2696 HRSRC fontrsrc;
2697 UINT32 codePoints[1] = {0xa8};
2698 UINT16 indices[2];
2699 const void *key;
2700 UINT32 key_size;
2701 WCHAR *path;
2703 path = create_testfontfile(test_fontfile);
2705 factory = create_factory();
2706 factory2 = create_factory();
2708 if (0) { /* crashes on win10 */
2709 hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
2710 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2712 /* local loader is accepted too */
2713 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
2714 ok(hr == S_OK, "got 0x%08x\n", hr);
2716 hr = IDWriteFontFile_GetLoader(file, &loader);
2717 ok(hr == S_OK, "got 0x%08x\n", hr);
2719 hr = IDWriteFontFile_GetReferenceKey(file, &key, &key_size);
2720 ok(hr == S_OK, "got 0x%08x\n", hr);
2722 hr = IDWriteFactory_CreateCustomFontFileReference(factory, key, key_size, loader, &file2);
2723 ok(hr == S_OK, "got 0x%08x\n", hr);
2725 IDWriteFontFile_Release(file2);
2726 IDWriteFontFile_Release(file);
2727 IDWriteFontFileLoader_Release(loader);
2729 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
2730 ok(hr == S_OK, "got 0x%08x\n", hr);
2731 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader2);
2732 ok(hr == S_OK, "got 0x%08x\n", hr);
2733 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
2734 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
2735 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
2736 ok(hr == S_OK, "got 0x%08x\n", hr);
2738 file = NULL;
2739 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
2740 ok(hr == S_OK, "got 0x%08x\n", hr);
2741 IDWriteFontFile_Release(file);
2743 file = (void*)0xdeadbeef;
2744 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader3, &file);
2745 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2746 ok(file == NULL, "got %p\n", file);
2748 file = (void*)0xdeadbeef;
2749 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, NULL, &file);
2750 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2751 ok(file == NULL, "got %p\n", file);
2753 file = NULL;
2754 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
2755 ok(hr == S_OK, "got 0x%08x\n", hr);
2757 file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
2758 face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
2759 support = TRUE;
2760 count = 1;
2761 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
2762 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
2763 ok(support == FALSE, "got %i\n", support);
2764 ok(file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN, "got %i\n", file_type);
2765 ok(face_type == DWRITE_FONT_FACE_TYPE_UNKNOWN, "got %i\n", face_type);
2766 ok(count == 0, "got %i\n", count);
2768 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0, &face);
2769 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
2770 IDWriteFontFile_Release(file);
2772 fontrsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
2773 ok(fontrsrc != NULL, "Failed to find font resource\n");
2775 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file);
2776 ok(hr == S_OK, "got 0x%08x\n", hr);
2778 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
2779 face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
2780 support = FALSE;
2781 count = 0;
2782 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
2783 ok(hr == S_OK, "got 0x%08x\n", hr);
2784 ok(support == TRUE, "got %i\n", support);
2785 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
2786 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
2787 ok(count == 1, "got %i\n", count);
2789 /* invalid index */
2790 face = (void*)0xdeadbeef;
2791 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 1, DWRITE_FONT_SIMULATIONS_NONE, &face);
2792 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2793 ok(face == NULL, "got %p\n", face);
2795 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
2796 ok(hr == S_OK, "got 0x%08x\n", hr);
2798 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
2799 ok(hr == S_OK, "got 0x%08x\n", hr);
2800 /* fontface instances are reused starting with win7 */
2801 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
2802 IDWriteFontFace_Release(face2);
2804 /* file was created with different factory */
2805 face2 = NULL;
2806 hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
2807 todo_wine
2808 ok(hr == S_OK, "got 0x%08x\n", hr);
2809 if (face2) {
2810 IDWriteFontFace_Release(face2);
2812 file2 = NULL;
2813 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2);
2814 ok(hr == S_OK, "got 0x%08x\n", hr);
2815 ok(file != file2, "got %p, %p\n", file, file2);
2817 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
2818 ok(hr == S_OK, "got 0x%08x\n", hr);
2819 /* fontface instances are reused starting with win7 */
2820 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
2821 IDWriteFontFace_Release(face2);
2822 IDWriteFontFile_Release(file2);
2824 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, NULL);
2825 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
2827 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, NULL);
2828 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
2830 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, indices);
2831 ok(hr == S_OK, "got 0x%08x\n", hr);
2833 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, indices);
2834 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
2836 indices[0] = indices[1] = 11;
2837 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, indices);
2838 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2839 ok(indices[0] == 0, "got index %i\n", indices[0]);
2840 ok(indices[1] == 11, "got index %i\n", indices[1]);
2842 if (0) /* crashes on native */
2843 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, NULL);
2845 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 1, indices);
2846 ok(hr == S_OK, "got 0x%08x\n", hr);
2847 ok(indices[0] == 6, "got index %i\n", indices[0]);
2848 IDWriteFontFace_Release(face);
2849 IDWriteFontFile_Release(file);
2851 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
2852 ok(hr == S_OK, "got 0x%08x\n", hr);
2853 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
2854 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2855 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader2);
2856 ok(hr == S_OK, "got 0x%08x\n", hr);
2857 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
2858 ok(hr == S_OK, "got 0x%08x\n", hr);
2860 IDWriteFactory_Release(factory2);
2861 IDWriteFactory_Release(factory);
2862 DELETE_FONTFILE(path);
2865 static void test_CreateFontFileReference(void)
2867 HRESULT hr;
2868 IDWriteFontFile *ffile = NULL;
2869 BOOL support;
2870 DWRITE_FONT_FILE_TYPE type;
2871 DWRITE_FONT_FACE_TYPE face;
2872 UINT32 count;
2873 IDWriteFontFace *fface = NULL;
2874 IDWriteFactory *factory;
2875 WCHAR *path;
2877 path = create_testfontfile(test_fontfile);
2878 factory = create_factory();
2880 ffile = (void*)0xdeadbeef;
2881 hr = IDWriteFactory_CreateFontFileReference(factory, NULL, NULL, &ffile);
2882 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
2883 ok(ffile == NULL, "got %p\n", ffile);
2885 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &ffile);
2886 ok(hr == S_OK, "got 0x%08x\n",hr);
2888 support = FALSE;
2889 type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
2890 face = DWRITE_FONT_FACE_TYPE_CFF;
2891 count = 0;
2892 hr = IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count);
2893 ok(hr == S_OK, "got 0x%08x\n", hr);
2894 ok(support == TRUE, "got %i\n", support);
2895 ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type);
2896 ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face);
2897 ok(count == 1, "got %i\n", count);
2899 hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface);
2900 ok(hr == S_OK, "got 0x%08x\n", hr);
2902 IDWriteFontFace_Release(fface);
2903 IDWriteFontFile_Release(ffile);
2904 IDWriteFactory_Release(factory);
2906 DELETE_FONTFILE(path);
2909 static void test_shared_isolated(void)
2911 IDWriteFactory *isolated, *isolated2;
2912 IDWriteFactory *shared, *shared2;
2913 HRESULT hr;
2915 /* invalid type */
2916 shared = NULL;
2917 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&shared);
2918 ok(hr == S_OK, "got 0x%08x\n", hr);
2919 ok(shared != NULL, "got %p\n", shared);
2920 IDWriteFactory_Release(shared);
2922 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared);
2923 ok(hr == S_OK, "got 0x%08x\n", hr);
2925 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
2926 ok(hr == S_OK, "got 0x%08x\n", hr);
2927 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
2928 IDWriteFactory_Release(shared2);
2930 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IUnknown, (IUnknown**)&shared2);
2931 ok(hr == S_OK, "got 0x%08x\n", hr);
2932 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
2934 IDWriteFactory_Release(shared);
2935 IDWriteFactory_Release(shared2);
2937 /* we got 2 references, released 2 - still same pointer is returned */
2938 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
2939 ok(hr == S_OK, "got 0x%08x\n", hr);
2940 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
2941 IDWriteFactory_Release(shared2);
2943 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated);
2944 ok(hr == S_OK, "got 0x%08x\n", hr);
2946 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated2);
2947 ok(hr == S_OK, "got 0x%08x\n", hr);
2948 ok(isolated != isolated2, "got %p, and %p\n", isolated, isolated2);
2949 IDWriteFactory_Release(isolated2);
2951 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IUnknown, (IUnknown**)&isolated2);
2952 ok(hr == S_OK, "got 0x%08x\n", hr);
2953 IDWriteFactory_Release(isolated2);
2955 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&isolated2);
2956 ok(hr == S_OK, "got 0x%08x\n", hr);
2957 ok(shared != isolated2, "got %p, and %p\n", shared, isolated2);
2959 IDWriteFactory_Release(isolated);
2960 IDWriteFactory_Release(isolated2);
2963 static void test_GetUnicodeRanges(void)
2965 DWRITE_UNICODE_RANGE *ranges, r;
2966 IDWriteFontFile *ffile = NULL;
2967 IDWriteFontFace1 *fontface1;
2968 IDWriteFontFace *fontface;
2969 IDWriteFactory *factory;
2970 UINT32 count;
2971 HRESULT hr;
2972 HRSRC font;
2974 factory = create_factory();
2976 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
2977 ok(hr == S_OK, "got 0x%08x\n", hr);
2979 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
2980 ok(font != NULL, "Failed to find font resource\n");
2982 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile);
2983 ok(hr == S_OK, "got 0x%08x\n", hr);
2985 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2986 ok(hr == S_OK, "got 0x%08x\n", hr);
2987 IDWriteFontFile_Release(ffile);
2989 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2990 IDWriteFontFace_Release(fontface);
2991 if (hr != S_OK) {
2992 win_skip("GetUnicodeRanges() is not supported.\n");
2993 IDWriteFactory_Release(factory);
2994 return;
2997 count = 0;
2998 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
2999 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3000 ok(count > 0, "got %u\n", count);
3002 count = 1;
3003 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count);
3004 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3005 ok(count == 0, "got %u\n", count);
3007 count = 0;
3008 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count);
3009 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3010 ok(count > 1, "got %u\n", count);
3012 ranges = heap_alloc(count*sizeof(DWRITE_UNICODE_RANGE));
3013 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
3014 ok(hr == S_OK, "got 0x%08x\n", hr);
3016 ranges[0].first = ranges[0].last = 0;
3017 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count);
3018 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3019 ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last);
3021 heap_free(ranges);
3023 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
3024 ok(hr == S_OK, "got 0x%08x\n", hr);
3026 IDWriteFontFace1_Release(fontface1);
3027 IDWriteFactory_Release(factory);
3030 static void test_GetFontFromFontFace(void)
3032 IDWriteFontFace *fontface, *fontface2;
3033 IDWriteFontCollection *collection;
3034 IDWriteFont *font, *font2, *font3;
3035 IDWriteFontFamily *family;
3036 IDWriteFactory *factory;
3037 IDWriteFontFile *file;
3038 WCHAR *path;
3039 HRESULT hr;
3041 factory = create_factory();
3043 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3044 ok(hr == S_OK, "got 0x%08x\n", hr);
3046 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3047 ok(hr == S_OK, "got 0x%08x\n", hr);
3049 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3050 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3051 ok(hr == S_OK, "got 0x%08x\n", hr);
3053 hr = IDWriteFont_CreateFontFace(font, &fontface);
3054 ok(hr == S_OK, "got 0x%08x\n", hr);
3056 font2 = NULL;
3057 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
3058 ok(hr == S_OK, "got 0x%08x\n", hr);
3059 ok(font2 != font, "got %p, %p\n", font2, font);
3061 font3 = NULL;
3062 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3063 ok(hr == S_OK, "got 0x%08x\n", hr);
3064 ok(font3 != font && font3 != font2, "got %p, %p, %p\n", font3, font2, font);
3066 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
3067 ok(hr == S_OK, "got 0x%08x\n", hr);
3068 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3069 IDWriteFontFace_Release(fontface2);
3071 hr = IDWriteFont_CreateFontFace(font3, &fontface2);
3072 ok(hr == S_OK, "got 0x%08x\n", hr);
3073 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
3074 IDWriteFontFace_Release(fontface2);
3075 IDWriteFontFace_Release(fontface);
3076 IDWriteFont_Release(font3);
3077 IDWriteFactory_Release(factory);
3079 /* fontface that wasn't created from this collection */
3080 factory = create_factory();
3081 path = create_testfontfile(test_fontfile);
3083 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3084 ok(hr == S_OK, "got 0x%08x\n",hr);
3086 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3087 ok(hr == S_OK, "got 0x%08x\n", hr);
3088 IDWriteFontFile_Release(file);
3090 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
3091 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
3092 ok(font3 == NULL, "got %p\n", font3);
3093 IDWriteFontFace_Release(fontface);
3095 IDWriteFont_Release(font);
3096 IDWriteFont_Release(font2);
3097 IDWriteFontFamily_Release(family);
3098 IDWriteFontCollection_Release(collection);
3099 IDWriteFactory_Release(factory);
3100 DELETE_FONTFILE(path);
3103 static void test_GetFirstMatchingFont(void)
3105 DWRITE_FONT_SIMULATIONS simulations;
3106 IDWriteFontCollection *collection;
3107 IDWriteFontFamily *family;
3108 IDWriteFont *font, *font2;
3109 IDWriteFactory *factory;
3110 HRESULT hr;
3112 factory = create_factory();
3114 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3115 ok(hr == S_OK, "got 0x%08x\n", hr);
3117 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3118 ok(hr == S_OK, "got 0x%08x\n", hr);
3120 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3121 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3122 ok(hr == S_OK, "got 0x%08x\n", hr);
3124 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3125 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
3126 ok(hr == S_OK, "got 0x%08x\n", hr);
3127 ok(font != font2, "got %p, %p\n", font, font2);
3128 IDWriteFont_Release(font);
3129 IDWriteFont_Release(font2);
3131 /* out-of-range font props are allowed */
3132 hr = IDWriteFontFamily_GetFirstMatchingFont(family, 1000, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3133 ok(hr == S_OK, "got 0x%08x\n", hr);
3134 IDWriteFont_Release(font);
3136 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, 10, DWRITE_FONT_STYLE_NORMAL, &font);
3137 ok(hr == S_OK, "got 0x%08x\n", hr);
3138 IDWriteFont_Release(font);
3140 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3141 10, &font);
3142 ok(hr == S_OK, "got 0x%08x\n", hr);
3143 IDWriteFont_Release(font);
3145 IDWriteFontFamily_Release(family);
3147 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
3148 simulations = IDWriteFont_GetSimulations(font);
3149 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "%d\n", simulations);
3150 IDWriteFont_Release(font);
3152 IDWriteFontCollection_Release(collection);
3153 IDWriteFactory_Release(factory);
3156 static void test_GetMatchingFonts(void)
3158 IDWriteFontCollection *collection;
3159 IDWriteFontFamily *family;
3160 IDWriteFactory *factory;
3161 IDWriteFontList *fontlist, *fontlist2;
3162 IDWriteFontList1 *fontlist1;
3163 HRESULT hr;
3165 factory = create_factory();
3167 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3168 ok(hr == S_OK, "got 0x%08x\n", hr);
3170 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3171 ok(hr == S_OK, "got 0x%08x\n", hr);
3173 /* out-of-range font props are allowed */
3174 hr = IDWriteFontFamily_GetMatchingFonts(family, 1000, DWRITE_FONT_STRETCH_NORMAL,
3175 DWRITE_FONT_STYLE_NORMAL, &fontlist);
3176 ok(hr == S_OK, "got 0x%08x\n", hr);
3177 IDWriteFontList_Release(fontlist);
3179 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, 10,
3180 DWRITE_FONT_STYLE_NORMAL, &fontlist);
3181 ok(hr == S_OK, "got 0x%08x\n", hr);
3182 IDWriteFontList_Release(fontlist);
3184 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3185 10, &fontlist);
3186 ok(hr == S_OK, "got 0x%08x\n", hr);
3187 IDWriteFontList_Release(fontlist);
3189 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
3190 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist);
3191 ok(hr == S_OK, "got 0x%08x\n", hr);
3193 hr = IDWriteFontFamily_GetMatchingFonts(family, DWRITE_FONT_WEIGHT_NORMAL,
3194 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &fontlist2);
3195 ok(hr == S_OK, "got 0x%08x\n", hr);
3196 ok(fontlist != fontlist2, "got %p, %p\n", fontlist, fontlist2);
3197 IDWriteFontList_Release(fontlist2);
3199 hr = IDWriteFontList_QueryInterface(fontlist, &IID_IDWriteFontList1, (void**)&fontlist1);
3200 if (hr == S_OK) {
3201 IDWriteFontFaceReference *ref, *ref1;
3202 IDWriteFont3 *font;
3203 UINT32 count;
3205 count = IDWriteFontList1_GetFontCount(fontlist1);
3206 ok(count > 0, "got %u\n", count);
3208 font = (void*)0xdeadbeef;
3209 hr = IDWriteFontList1_GetFont(fontlist1, ~0u, &font);
3210 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3211 ok(font == NULL, "got %p\n", font);
3213 font = (void*)0xdeadbeef;
3214 hr = IDWriteFontList1_GetFont(fontlist1, count, &font);
3215 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3216 ok(font == NULL, "got %p\n", font);
3218 hr = IDWriteFontList1_GetFont(fontlist1, 0, &font);
3219 ok(hr == S_OK, "got 0x%08x\n", hr);
3220 IDWriteFont3_Release(font);
3222 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref);
3223 ok(hr == S_OK, "got 0x%08x\n", hr);
3225 hr = IDWriteFontList1_GetFontFaceReference(fontlist1, 0, &ref1);
3226 ok(hr == S_OK, "got 0x%08x\n", hr);
3227 ok(ref != ref1, "got %p, %p\n", ref, ref1);
3229 IDWriteFontFaceReference_Release(ref1);
3230 IDWriteFontFaceReference_Release(ref);
3231 IDWriteFontList1_Release(fontlist1);
3233 else
3234 win_skip("IDWriteFontList1 is not supported.\n");
3236 IDWriteFontList_Release(fontlist);
3237 IDWriteFontFamily_Release(family);
3239 IDWriteFontCollection_Release(collection);
3240 IDWriteFactory_Release(factory);
3243 static void test_GetInformationalStrings(void)
3245 IDWriteLocalizedStrings *strings, *strings2;
3246 IDWriteFontCollection *collection;
3247 IDWriteFontFamily *family;
3248 IDWriteFactory *factory;
3249 IDWriteFont *font;
3250 BOOL exists;
3251 HRESULT hr;
3253 factory = create_factory();
3255 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3256 ok(hr == S_OK, "got 0x%08x\n", hr);
3258 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3259 ok(hr == S_OK, "got 0x%08x\n", hr);
3261 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3262 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3263 ok(hr == S_OK, "got 0x%08x\n", hr);
3265 exists = TRUE;
3266 strings = (void*)0xdeadbeef;
3267 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1, &strings, &exists);
3268 ok(hr == S_OK, "got 0x%08x\n", hr);
3269 ok(exists == FALSE, "got %d\n", exists);
3270 ok(strings == NULL, "got %p\n", strings);
3272 exists = TRUE;
3273 strings = NULL;
3274 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists);
3275 ok(hr == S_OK, "got 0x%08x\n", hr);
3276 ok(exists == FALSE, "got %d\n", exists);
3278 exists = FALSE;
3279 strings = NULL;
3280 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
3281 ok(hr == S_OK, "got 0x%08x\n", hr);
3282 ok(exists == TRUE, "got %d\n", exists);
3284 /* strings instance is not reused */
3285 strings2 = NULL;
3286 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings2, &exists);
3287 ok(hr == S_OK, "got 0x%08x\n", hr);
3288 ok(strings2 != strings, "got %p, %p\n", strings2, strings);
3290 IDWriteLocalizedStrings_Release(strings);
3291 IDWriteLocalizedStrings_Release(strings2);
3292 IDWriteFont_Release(font);
3293 IDWriteFontFamily_Release(family);
3294 IDWriteFontCollection_Release(collection);
3295 IDWriteFactory_Release(factory);
3298 static void test_GetGdiInterop(void)
3300 IDWriteGdiInterop *interop, *interop2;
3301 IDWriteFactory *factory, *factory2;
3302 IDWriteFont *font;
3303 LOGFONTW logfont;
3304 HRESULT hr;
3306 factory = create_factory();
3308 interop = NULL;
3309 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3310 ok(hr == S_OK, "got 0x%08x\n", hr);
3312 interop2 = NULL;
3313 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
3314 ok(hr == S_OK, "got 0x%08x\n", hr);
3315 ok(interop == interop2, "got %p, %p\n", interop, interop2);
3316 IDWriteGdiInterop_Release(interop2);
3318 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory2);
3319 ok(hr == S_OK, "got 0x%08x\n", hr);
3321 /* each factory gets its own interop */
3322 interop2 = NULL;
3323 hr = IDWriteFactory_GetGdiInterop(factory2, &interop2);
3324 ok(hr == S_OK, "got 0x%08x\n", hr);
3325 ok(interop != interop2, "got %p, %p\n", interop, interop2);
3327 /* release factory - interop still works */
3328 IDWriteFactory_Release(factory2);
3330 memset(&logfont, 0, sizeof(logfont));
3331 logfont.lfHeight = 12;
3332 logfont.lfWidth = 12;
3333 logfont.lfWeight = FW_NORMAL;
3334 logfont.lfItalic = 1;
3335 lstrcpyW(logfont.lfFaceName, tahomaW);
3337 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop2, &logfont, &font);
3338 ok(hr == S_OK, "got 0x%08x\n", hr);
3339 IDWriteFont_Release(font);
3341 IDWriteGdiInterop_Release(interop2);
3342 IDWriteGdiInterop_Release(interop);
3343 IDWriteFactory_Release(factory);
3346 static void test_CreateFontFaceFromHdc(void)
3348 IDWriteGdiInterop *interop;
3349 IDWriteFontFace *fontface;
3350 IDWriteFactory *factory;
3351 HFONT hfont, oldhfont;
3352 LOGFONTW logfont;
3353 HRESULT hr;
3354 HDC hdc;
3356 factory = create_factory();
3358 interop = NULL;
3359 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3360 ok(hr == S_OK, "got 0x%08x\n", hr);
3362 fontface = (void*)0xdeadbeef;
3363 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, NULL, &fontface);
3364 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3365 ok(fontface == NULL, "got %p\n", fontface);
3367 memset(&logfont, 0, sizeof(logfont));
3368 logfont.lfHeight = 12;
3369 logfont.lfWidth = 12;
3370 logfont.lfWeight = FW_NORMAL;
3371 logfont.lfItalic = 1;
3372 lstrcpyW(logfont.lfFaceName, tahomaW);
3374 hfont = CreateFontIndirectW(&logfont);
3375 hdc = CreateCompatibleDC(0);
3376 oldhfont = SelectObject(hdc, hfont);
3378 fontface = NULL;
3379 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
3380 ok(hr == S_OK, "got 0x%08x\n", hr);
3381 IDWriteFontFace_Release(fontface);
3382 DeleteObject(SelectObject(hdc, oldhfont));
3383 DeleteDC(hdc);
3385 IDWriteGdiInterop_Release(interop);
3386 IDWriteFactory_Release(factory);
3389 static void test_GetSimulations(void)
3391 DWRITE_FONT_SIMULATIONS simulations;
3392 IDWriteGdiInterop *interop;
3393 IDWriteFontFace *fontface;
3394 IDWriteFactory *factory;
3395 IDWriteFont *font;
3396 LOGFONTW logfont;
3397 HRESULT hr;
3399 factory = create_factory();
3401 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3402 ok(hr == S_OK, "got 0x%08x\n", hr);
3404 memset(&logfont, 0, sizeof(logfont));
3405 logfont.lfHeight = 12;
3406 logfont.lfWidth = 12;
3407 logfont.lfWeight = FW_NORMAL;
3408 logfont.lfItalic = 1;
3409 lstrcpyW(logfont.lfFaceName, tahomaW);
3411 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3412 ok(hr == S_OK, "got 0x%08x\n", hr);
3414 simulations = IDWriteFont_GetSimulations(font);
3415 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
3416 hr = IDWriteFont_CreateFontFace(font, &fontface);
3417 ok(hr == S_OK, "got 0x%08x\n", hr);
3418 simulations = IDWriteFontFace_GetSimulations(fontface);
3419 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
3420 IDWriteFontFace_Release(fontface);
3421 IDWriteFont_Release(font);
3423 memset(&logfont, 0, sizeof(logfont));
3424 logfont.lfHeight = 12;
3425 logfont.lfWidth = 12;
3426 logfont.lfWeight = FW_NORMAL;
3427 logfont.lfItalic = 0;
3428 lstrcpyW(logfont.lfFaceName, tahomaW);
3430 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3431 ok(hr == S_OK, "got 0x%08x\n", hr);
3433 simulations = IDWriteFont_GetSimulations(font);
3434 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
3435 hr = IDWriteFont_CreateFontFace(font, &fontface);
3436 ok(hr == S_OK, "got 0x%08x\n", hr);
3437 simulations = IDWriteFontFace_GetSimulations(fontface);
3438 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
3439 IDWriteFontFace_Release(fontface);
3440 IDWriteFont_Release(font);
3442 IDWriteGdiInterop_Release(interop);
3443 IDWriteFactory_Release(factory);
3446 static void test_GetFaceNames(void)
3448 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
3449 static const WCHAR enus2W[] = {'e','n','-','U','s',0};
3450 static const WCHAR enusW[] = {'e','n','-','u','s',0};
3451 IDWriteLocalizedStrings *strings, *strings2;
3452 IDWriteGdiInterop *interop;
3453 IDWriteFactory *factory;
3454 UINT32 count, index;
3455 IDWriteFont *font;
3456 LOGFONTW logfont;
3457 WCHAR buffW[255];
3458 BOOL exists;
3459 HRESULT hr;
3461 factory = create_factory();
3463 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3464 ok(hr == S_OK, "got 0x%08x\n", hr);
3466 memset(&logfont, 0, sizeof(logfont));
3467 logfont.lfHeight = 12;
3468 logfont.lfWidth = 12;
3469 logfont.lfWeight = FW_NORMAL;
3470 logfont.lfItalic = 1;
3471 lstrcpyW(logfont.lfFaceName, tahomaW);
3473 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
3474 ok(hr == S_OK, "got 0x%08x\n", hr);
3476 hr = IDWriteFont_GetFaceNames(font, &strings);
3477 ok(hr == S_OK, "got 0x%08x\n", hr);
3479 hr = IDWriteFont_GetFaceNames(font, &strings2);
3480 ok(hr == S_OK, "got 0x%08x\n", hr);
3481 ok(strings != strings2, "got %p, %p\n", strings2, strings);
3482 IDWriteLocalizedStrings_Release(strings2);
3484 count = IDWriteLocalizedStrings_GetCount(strings);
3485 ok(count == 1, "got %d\n", count);
3487 index = 1;
3488 exists = FALSE;
3489 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enus2W, &index, &exists);
3490 ok(hr == S_OK, "got 0x%08x\n", hr);
3491 ok(index == 0 && exists, "got %d, %d\n", index, exists);
3493 count = 0;
3494 hr = IDWriteLocalizedStrings_GetLocaleNameLength(strings, 1, &count);
3495 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3496 ok(count == ~0, "got %d\n", count);
3498 /* for simulated faces names are also simulated */
3499 buffW[0] = 0;
3500 hr = IDWriteLocalizedStrings_GetLocaleName(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
3501 ok(hr == S_OK, "got 0x%08x\n", hr);
3502 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
3504 buffW[0] = 0;
3505 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
3506 ok(hr == S_OK, "got 0x%08x\n", hr);
3507 ok(!lstrcmpW(buffW, obliqueW), "got %s\n", wine_dbgstr_w(buffW));
3508 IDWriteLocalizedStrings_Release(strings);
3510 IDWriteFont_Release(font);
3511 IDWriteGdiInterop_Release(interop);
3512 IDWriteFactory_Release(factory);
3515 struct local_refkey
3517 FILETIME writetime;
3518 WCHAR name[1];
3521 static void test_TryGetFontTable(void)
3523 IDWriteLocalFontFileLoader *localloader;
3524 WIN32_FILE_ATTRIBUTE_DATA info;
3525 const struct local_refkey *key;
3526 IDWriteFontFileLoader *loader;
3527 const void *table, *table2;
3528 IDWriteFontFace *fontface;
3529 void *context, *context2;
3530 IDWriteFactory *factory;
3531 IDWriteFontFile *file;
3532 WCHAR buffW[MAX_PATH];
3533 BOOL exists, ret;
3534 UINT32 size, len;
3535 WCHAR *path;
3536 HRESULT hr;
3538 path = create_testfontfile(test_fontfile);
3540 factory = create_factory();
3542 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3543 ok(hr == S_OK, "got 0x%08x\n",hr);
3545 key = NULL;
3546 size = 0;
3547 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
3548 ok(hr == S_OK, "got 0x%08x\n", hr);
3549 ok(size != 0, "got %u\n", size);
3551 ret = GetFileAttributesExW(path, GetFileExInfoStandard, &info);
3552 ok(ret, "got %d\n", ret);
3553 ok(!memcmp(&info.ftLastWriteTime, &key->writetime, sizeof(key->writetime)), "got wrong write time\n");
3555 hr = IDWriteFontFile_GetLoader(file, &loader);
3556 ok(hr == S_OK, "got 0x%08x\n", hr);
3557 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
3558 IDWriteFontFileLoader_Release(loader);
3560 hr = IDWriteLocalFontFileLoader_GetFilePathLengthFromKey(localloader, key, size, &len);
3561 ok(hr == S_OK, "got 0x%08x\n", hr);
3562 ok(lstrlenW(key->name) == len, "path length %d\n", len);
3564 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, size, buffW, sizeof(buffW)/sizeof(WCHAR));
3565 ok(hr == S_OK, "got 0x%08x\n", hr);
3566 ok(!lstrcmpW(buffW, key->name), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(key->name));
3567 IDWriteLocalFontFileLoader_Release(localloader);
3569 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, 0, &fontface);
3570 ok(hr == S_OK, "got 0x%08x\n",hr);
3572 exists = FALSE;
3573 context = (void*)0xdeadbeef;
3574 table = NULL;
3575 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table, &size, &context, &exists);
3576 ok(hr == S_OK, "got 0x%08x\n",hr);
3577 ok(exists == TRUE, "got %d\n", exists);
3578 ok(context == NULL && table != NULL, "cmap: context %p, table %p\n", context, table);
3580 exists = FALSE;
3581 context2 = (void*)0xdeadbeef;
3582 table2 = NULL;
3583 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table2, &size, &context2, &exists);
3584 ok(hr == S_OK, "got 0x%08x\n",hr);
3585 ok(exists == TRUE, "got %d\n", exists);
3586 ok(context2 == context && table2 == table, "cmap: context2 %p, table2 %p\n", context2, table2);
3588 IDWriteFontFace_ReleaseFontTable(fontface, context2);
3589 IDWriteFontFace_ReleaseFontTable(fontface, context);
3591 /* table does not exist */
3592 exists = TRUE;
3593 context = (void*)0xdeadbeef;
3594 table = (void*)0xdeadbeef;
3595 hr = IDWriteFontFace_TryGetFontTable(fontface, 0xabababab, &table, &size, &context, &exists);
3596 ok(hr == S_OK, "got 0x%08x\n", hr);
3597 ok(exists == FALSE, "got %d\n", exists);
3598 ok(context == NULL && table == NULL, "got context %p, table pointer %p\n", context, table);
3600 IDWriteFontFace_Release(fontface);
3601 IDWriteFontFile_Release(file);
3602 IDWriteFactory_Release(factory);
3603 DELETE_FONTFILE(path);
3606 static void test_ConvertFontToLOGFONT(void)
3608 IDWriteFactory *factory, *factory2;
3609 IDWriteFontCollection *collection;
3610 IDWriteGdiInterop *interop;
3611 IDWriteFontFamily *family;
3612 IDWriteFont *font;
3613 LOGFONTW logfont;
3614 UINT32 i, count;
3615 BOOL system;
3616 HRESULT hr;
3618 factory = create_factory();
3619 factory2 = create_factory();
3621 interop = NULL;
3622 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
3623 ok(hr == S_OK, "got 0x%08x\n", hr);
3625 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection, FALSE);
3626 ok(hr == S_OK, "got 0x%08x\n", hr);
3628 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
3629 ok(hr == S_OK, "got 0x%08x\n", hr);
3631 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3632 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3633 ok(hr == S_OK, "got 0x%08x\n", hr);
3635 if (0) { /* crashes on native */
3636 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, NULL, NULL);
3637 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, NULL);
3638 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, NULL, &system);
3641 memset(&logfont, 0xcc, sizeof(logfont));
3642 system = TRUE;
3643 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, &system);
3644 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3645 ok(!system, "got %d\n", system);
3646 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
3648 count = IDWriteFontCollection_GetFontFamilyCount(collection);
3649 for (i = 0; i < count; i++) {
3650 WCHAR nameW[128], familynameW[64], facenameW[64];
3651 IDWriteLocalizedStrings *names;
3652 DWRITE_FONT_SIMULATIONS sim;
3653 IDWriteFontFamily *family;
3654 UINT32 font_count, j;
3655 IDWriteFont *font;
3656 LOGFONTW lf;
3658 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
3659 ok(hr == S_OK, "got 0x%08x\n", hr);
3661 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
3662 ok(hr == S_OK, "got 0x%08x\n", hr);
3664 get_enus_string(names, familynameW, sizeof(familynameW)/sizeof(familynameW[0]));
3665 IDWriteLocalizedStrings_Release(names);
3667 font_count = IDWriteFontFamily_GetFontCount(family);
3669 for (j = 0; j < font_count; j++) {
3670 static const WCHAR spaceW[] = {' ', 0};
3672 hr = IDWriteFontFamily_GetFont(family, j, &font);
3673 ok(hr == S_OK, "got 0x%08x\n", hr);
3675 hr = IDWriteFont_GetFaceNames(font, &names);
3676 ok(hr == S_OK, "got 0x%08x\n", hr);
3678 get_enus_string(names, facenameW, sizeof(facenameW)/sizeof(facenameW[0]));
3679 IDWriteLocalizedStrings_Release(names);
3681 lstrcpyW(nameW, familynameW);
3682 lstrcatW(nameW, spaceW);
3683 lstrcatW(nameW, facenameW);
3685 system = FALSE;
3686 memset(&logfont, 0xcc, sizeof(logfont));
3687 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, &logfont, &system);
3688 ok(hr == S_OK, "got 0x%08x\n", hr);
3689 ok(system, "got %d\n", system);
3691 sim = IDWriteFont_GetSimulations(font);
3693 get_logfont_from_font(font, &lf);
3694 ok(logfont.lfWeight == lf.lfWeight, "%s: unexpected lfWeight %d, expected lfWeight %d, font weight %d, "
3695 "bold simulation %s\n", wine_dbgstr_w(nameW), logfont.lfWeight, lf.lfWeight, IDWriteFont_GetWeight(font),
3696 sim & DWRITE_FONT_SIMULATIONS_BOLD ? "yes" : "no");
3697 ok(logfont.lfItalic == lf.lfItalic, "%s: unexpected italic flag %d, oblique simulation %s\n",
3698 wine_dbgstr_w(nameW), logfont.lfItalic, sim & DWRITE_FONT_SIMULATIONS_OBLIQUE ? "yes" : "no");
3699 ok(!lstrcmpW(logfont.lfFaceName, lf.lfFaceName), "%s: unexpected facename %s, expected %s\n",
3700 wine_dbgstr_w(nameW), wine_dbgstr_w(logfont.lfFaceName), wine_dbgstr_w(lf.lfFaceName));
3702 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "%s: unexpected output precision %d\n", wine_dbgstr_w(nameW),
3703 logfont.lfOutPrecision);
3704 ok(logfont.lfClipPrecision == CLIP_DEFAULT_PRECIS, "%s: unexpected clipping precision %d\n", wine_dbgstr_w(nameW),
3705 logfont.lfClipPrecision);
3706 ok(logfont.lfQuality == DEFAULT_QUALITY, "%s: unexpected quality %d\n", wine_dbgstr_w(nameW), logfont.lfQuality);
3707 ok(logfont.lfPitchAndFamily == DEFAULT_PITCH, "%s: unexpected pitch %d\n", wine_dbgstr_w(nameW),
3708 logfont.lfPitchAndFamily);
3710 IDWriteFont_Release(font);
3713 IDWriteFontFamily_Release(family);
3716 IDWriteFactory_Release(factory2);
3718 IDWriteFontCollection_Release(collection);
3719 IDWriteFontFamily_Release(family);
3720 IDWriteFont_Release(font);
3721 IDWriteGdiInterop_Release(interop);
3722 IDWriteFactory_Release(factory);
3725 static void test_CreateStreamFromKey(void)
3727 IDWriteLocalFontFileLoader *localloader;
3728 IDWriteFontFileStream *stream, *stream2;
3729 IDWriteFontFileLoader *loader;
3730 IDWriteFactory *factory;
3731 IDWriteFontFile *file;
3732 UINT64 writetime;
3733 WCHAR *path;
3734 void *key;
3735 UINT32 size;
3736 HRESULT hr;
3738 factory = create_factory();
3740 path = create_testfontfile(test_fontfile);
3742 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3743 ok(hr == S_OK, "got 0x%08x\n",hr);
3745 key = NULL;
3746 size = 0;
3747 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
3748 ok(hr == S_OK, "got 0x%08x\n", hr);
3749 ok(size != 0, "got %u\n", size);
3751 hr = IDWriteFontFile_GetLoader(file, &loader);
3752 ok(hr == S_OK, "got 0x%08x\n", hr);
3753 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
3754 IDWriteFontFileLoader_Release(loader);
3756 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
3757 ok(hr == S_OK, "got 0x%08x\n", hr);
3758 EXPECT_REF(stream, 1);
3760 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2);
3761 ok(hr == S_OK, "got 0x%08x\n", hr);
3762 ok(stream == stream2 || broken(stream != stream2) /* Win7 SP0 */, "got %p, %p\n", stream, stream2);
3763 if (stream == stream2)
3764 EXPECT_REF(stream, 2);
3765 IDWriteFontFileStream_Release(stream);
3766 IDWriteFontFileStream_Release(stream2);
3768 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
3769 ok(hr == S_OK, "got 0x%08x\n", hr);
3770 EXPECT_REF(stream, 1);
3772 writetime = 0;
3773 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
3774 ok(hr == S_OK, "got 0x%08x\n", hr);
3775 ok(writetime != 0, "got %08x%08x\n", (UINT)(writetime >> 32), (UINT)writetime);
3777 IDWriteFontFileStream_Release(stream);
3778 IDWriteFontFile_Release(file);
3780 IDWriteLocalFontFileLoader_Release(localloader);
3781 IDWriteFactory_Release(factory);
3782 DELETE_FONTFILE(path);
3785 static void test_ReadFileFragment(void)
3787 IDWriteLocalFontFileLoader *localloader;
3788 IDWriteFontFileStream *stream;
3789 IDWriteFontFileLoader *loader;
3790 IDWriteFactory *factory;
3791 IDWriteFontFile *file;
3792 const void *fragment, *fragment2;
3793 void *key, *context, *context2;
3794 UINT64 filesize;
3795 UINT32 size;
3796 WCHAR *path;
3797 HRESULT hr;
3799 factory = create_factory();
3801 path = create_testfontfile(test_fontfile);
3803 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3804 ok(hr == S_OK, "got 0x%08x\n",hr);
3806 key = NULL;
3807 size = 0;
3808 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
3809 ok(hr == S_OK, "got 0x%08x\n", hr);
3810 ok(size != 0, "got %u\n", size);
3812 hr = IDWriteFontFile_GetLoader(file, &loader);
3813 ok(hr == S_OK, "got 0x%08x\n", hr);
3814 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
3815 IDWriteFontFileLoader_Release(loader);
3817 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
3818 ok(hr == S_OK, "got 0x%08x\n", hr);
3820 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
3821 ok(hr == S_OK, "got 0x%08x\n", hr);
3823 /* reading past the end of the stream */
3824 fragment = (void*)0xdeadbeef;
3825 context = (void*)0xdeadbeef;
3826 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize+1, &context);
3827 ok(hr == E_FAIL, "got 0x%08x\n", hr);
3828 ok(context == NULL, "got %p\n", context);
3829 ok(fragment == NULL, "got %p\n", fragment);
3831 fragment = (void*)0xdeadbeef;
3832 context = (void*)0xdeadbeef;
3833 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
3834 ok(hr == S_OK, "got 0x%08x\n", hr);
3835 ok(context == NULL, "got %p\n", context);
3836 ok(fragment != NULL, "got %p\n", fragment);
3838 fragment2 = (void*)0xdeadbeef;
3839 context2 = (void*)0xdeadbeef;
3840 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment2, 0, filesize, &context2);
3841 ok(hr == S_OK, "got 0x%08x\n", hr);
3842 ok(context2 == NULL, "got %p\n", context2);
3843 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
3845 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
3846 IDWriteFontFileStream_ReleaseFileFragment(stream, context2);
3848 /* fragment is released, try again */
3849 fragment = (void*)0xdeadbeef;
3850 context = (void*)0xdeadbeef;
3851 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
3852 ok(hr == S_OK, "got 0x%08x\n", hr);
3853 ok(context == NULL, "got %p\n", context);
3854 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
3855 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
3857 IDWriteFontFile_Release(file);
3858 IDWriteFontFileStream_Release(stream);
3859 IDWriteLocalFontFileLoader_Release(localloader);
3860 IDWriteFactory_Release(factory);
3861 DELETE_FONTFILE(path);
3864 static void test_GetDesignGlyphMetrics(void)
3866 DWRITE_GLYPH_METRICS metrics[2];
3867 IDWriteFontFace *fontface;
3868 IDWriteFactory *factory;
3869 IDWriteFontFile *file;
3870 UINT16 indices[2];
3871 UINT32 codepoint;
3872 WCHAR *path;
3873 HRESULT hr;
3875 factory = create_factory();
3877 path = create_testfontfile(test_fontfile);
3879 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3880 ok(hr == S_OK, "got 0x%08x\n",hr);
3882 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
3883 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3884 ok(hr == S_OK, "got 0x%08x\n",hr);
3885 IDWriteFontFile_Release(file);
3887 codepoint = 'A';
3888 indices[0] = 0;
3889 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &indices[0]);
3890 ok(hr == S_OK, "got 0x%08x\n", hr);
3891 ok(indices[0] > 0, "got %u\n", indices[0]);
3893 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 0, metrics, FALSE);
3894 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
3896 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 1, metrics, FALSE);
3897 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
3899 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 0, metrics, FALSE);
3900 ok(hr == S_OK, "got 0x%08x\n",hr);
3902 /* missing glyphs are ignored */
3903 indices[1] = 1;
3904 memset(metrics, 0xcc, sizeof(metrics));
3905 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 2, metrics, FALSE);
3906 ok(hr == S_OK, "got 0x%08x\n",hr);
3907 ok(metrics[0].advanceWidth == 1000, "got %d\n", metrics[0].advanceWidth);
3908 ok(metrics[1].advanceWidth == 0, "got %d\n", metrics[1].advanceWidth);
3910 IDWriteFontFace_Release(fontface);
3911 IDWriteFactory_Release(factory);
3912 DELETE_FONTFILE(path);
3915 static void test_IsMonospacedFont(void)
3917 static const WCHAR courierW[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
3918 IDWriteFontCollection *collection;
3919 IDWriteFactory *factory;
3920 UINT32 index;
3921 BOOL exists;
3922 HRESULT hr;
3924 factory = create_factory();
3925 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3926 ok(hr == S_OK, "got 0x%08x\n", hr);
3928 exists = FALSE;
3929 hr = IDWriteFontCollection_FindFamilyName(collection, courierW, &index, &exists);
3930 ok(hr == S_OK, "got 0x%08x\n", hr);
3931 if (exists) {
3932 IDWriteFontFamily *family;
3933 IDWriteFont1 *font1;
3934 IDWriteFont *font;
3936 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
3937 ok(hr == S_OK, "got 0x%08x\n", hr);
3939 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3940 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3941 ok(hr == S_OK, "got 0x%08x\n", hr);
3942 IDWriteFontFamily_Release(family);
3944 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
3945 if (hr == S_OK) {
3946 IDWriteFontFace1 *fontface1;
3947 IDWriteFontFace *fontface;
3948 BOOL is_monospaced;
3950 is_monospaced = IDWriteFont1_IsMonospacedFont(font1);
3951 ok(is_monospaced, "got %d\n", is_monospaced);
3953 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
3954 ok(hr == S_OK, "got 0x%08x\n", hr);
3955 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3956 ok(hr == S_OK, "got 0x%08x\n", hr);
3957 is_monospaced = IDWriteFontFace1_IsMonospacedFont(fontface1);
3958 ok(is_monospaced, "got %d\n", is_monospaced);
3959 IDWriteFontFace1_Release(fontface1);
3961 IDWriteFontFace_Release(fontface);
3962 IDWriteFont1_Release(font1);
3964 else
3965 win_skip("IsMonospacedFont() is not supported.\n");
3967 else
3968 skip("Courier New font not found.\n");
3970 IDWriteFontCollection_Release(collection);
3973 static void test_GetDesignGlyphAdvances(void)
3975 IDWriteFontFace1 *fontface1;
3976 IDWriteFontFace *fontface;
3977 IDWriteFactory *factory;
3978 IDWriteFontFile *file;
3979 WCHAR *path;
3980 HRESULT hr;
3982 factory = create_factory();
3984 path = create_testfontfile(test_fontfile);
3986 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3987 ok(hr == S_OK, "got 0x%08x\n", hr);
3989 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
3990 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3991 ok(hr == S_OK, "got 0x%08x\n", hr);
3992 IDWriteFontFile_Release(file);
3994 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3995 if (hr == S_OK) {
3996 UINT32 codepoint;
3997 UINT16 index;
3998 INT32 advance;
4000 codepoint = 'A';
4001 index = 0;
4002 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &index);
4003 ok(hr == S_OK, "got 0x%08x\n", hr);
4004 ok(index > 0, "got %u\n", index);
4006 advance = 0;
4007 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, FALSE);
4008 ok(hr == S_OK, "got 0x%08x\n", hr);
4009 ok(advance == 1000, "got %i\n", advance);
4011 advance = 0;
4012 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, TRUE);
4013 ok(hr == S_OK, "got 0x%08x\n", hr);
4014 todo_wine
4015 ok(advance == 2048, "got %i\n", advance);
4017 IDWriteFontFace1_Release(fontface1);
4019 else
4020 win_skip("GetDesignGlyphAdvances() is not supported.\n");
4022 IDWriteFontFace_Release(fontface);
4023 IDWriteFactory_Release(factory);
4024 DELETE_FONTFILE(path);
4027 static void test_GetGlyphRunOutline(void)
4029 DWRITE_GLYPH_OFFSET offsets[2];
4030 IDWriteFactory *factory;
4031 IDWriteFontFile *file;
4032 IDWriteFontFace *face;
4033 UINT32 codepoint;
4034 FLOAT advances[2];
4035 UINT16 glyphs[2];
4036 WCHAR *path;
4037 HRESULT hr;
4039 path = create_testfontfile(test_fontfile);
4040 factory = create_factory();
4042 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4043 ok(hr == S_OK, "got 0x%08x\n",hr);
4045 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
4046 ok(hr == S_OK, "got 0x%08x\n", hr);
4047 IDWriteFontFile_Release(file);
4049 codepoint = 'A';
4050 glyphs[0] = 0;
4051 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4052 ok(hr == S_OK, "got 0x%08x\n", hr);
4053 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4054 glyphs[1] = glyphs[0];
4056 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, glyphs, advances, offsets, 1, FALSE, FALSE, NULL);
4057 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4059 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, NULL, NULL, offsets, 1, FALSE, FALSE, &test_geomsink);
4060 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4062 advances[0] = 1.0;
4063 advances[1] = 0.0;
4065 offsets[0].advanceOffset = 1.0;
4066 offsets[0].ascenderOffset = 1.0;
4067 offsets[1].advanceOffset = 0.0;
4068 offsets[1].ascenderOffset = 0.0;
4070 /* default advances, no offsets */
4071 memset(g_startpoints, 0, sizeof(g_startpoints));
4072 g_startpoint_count = 0;
4073 SET_EXPECT(setfillmode);
4074 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, FALSE, &test_geomsink);
4075 ok(hr == S_OK, "got 0x%08x\n", hr);
4076 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4077 if (g_startpoint_count == 2) {
4078 /* glyph advance of 500 is applied */
4079 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);
4080 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);
4082 CHECK_CALLED(setfillmode);
4084 /* default advances, no offsets, RTL */
4085 memset(g_startpoints, 0, sizeof(g_startpoints));
4086 g_startpoint_count = 0;
4087 SET_EXPECT(setfillmode);
4088 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, TRUE, &test_geomsink);
4089 ok(hr == S_OK, "got 0x%08x\n", hr);
4090 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4091 if (g_startpoint_count == 2) {
4092 /* advance is -500 now */
4093 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);
4094 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);
4096 CHECK_CALLED(setfillmode);
4098 /* default advances, additional offsets */
4099 memset(g_startpoints, 0, sizeof(g_startpoints));
4100 g_startpoint_count = 0;
4101 SET_EXPECT(setfillmode);
4102 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, FALSE, &test_geomsink);
4103 ok(hr == S_OK, "got 0x%08x\n", hr);
4104 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4105 if (g_startpoint_count == 2) {
4106 /* offsets applied to first contour */
4107 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);
4108 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);
4110 CHECK_CALLED(setfillmode);
4112 /* default advances, additional offsets, RTL */
4113 memset(g_startpoints, 0, sizeof(g_startpoints));
4114 g_startpoint_count = 0;
4115 SET_EXPECT(setfillmode);
4116 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, TRUE, &test_geomsink);
4117 ok(hr == S_OK, "got 0x%08x\n", hr);
4118 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4119 if (g_startpoint_count == 2) {
4120 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);
4121 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);
4123 CHECK_CALLED(setfillmode);
4125 /* custom advances and offsets, offset turns total advance value to zero */
4126 memset(g_startpoints, 0, sizeof(g_startpoints));
4127 g_startpoint_count = 0;
4128 SET_EXPECT(setfillmode);
4129 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, advances, offsets, 2, FALSE, FALSE, &test_geomsink);
4130 ok(hr == S_OK, "got 0x%08x\n", hr);
4131 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
4132 if (g_startpoint_count == 2) {
4133 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);
4134 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);
4136 CHECK_CALLED(setfillmode);
4138 /* 0 glyph count */
4139 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 0, FALSE, FALSE, &test_geomsink2);
4140 ok(hr == S_OK, "got 0x%08x\n", hr);
4142 IDWriteFactory_Release(factory);
4143 IDWriteFontFace_Release(face);
4144 DELETE_FONTFILE(path);
4146 /* space glyph */
4147 factory = create_factory();
4148 face = create_fontface(factory);
4150 codepoint = ' ';
4151 glyphs[0] = 0;
4152 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
4153 ok(hr == S_OK, "got 0x%08x\n", hr);
4154 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
4156 SET_EXPECT(setfillmode);
4157 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
4158 ok(hr == S_OK, "got 0x%08x\n", hr);
4159 CHECK_CALLED(setfillmode);
4161 IDWriteFactory_Release(factory);
4162 IDWriteFontFace_Release(face);
4165 static void test_GetEudcFontCollection(void)
4167 IDWriteFontCollection *coll, *coll2;
4168 IDWriteFactory1 *factory1;
4169 IDWriteFactory *factory;
4170 HRESULT hr;
4172 factory = create_factory();
4174 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory1, (void**)&factory1);
4175 IDWriteFactory_Release(factory);
4176 if (hr != S_OK) {
4177 win_skip("GetEudcFontCollection() is not supported.\n");
4178 return;
4181 hr = IDWriteFactory1_GetEudcFontCollection(factory1, &coll, FALSE);
4182 ok(hr == S_OK, "got 0x%08x\n", hr);
4183 hr = IDWriteFactory1_GetEudcFontCollection(factory1, &coll2, FALSE);
4184 ok(hr == S_OK, "got 0x%08x\n", hr);
4185 ok(coll == coll2, "got %p, %p\n", coll, coll2);
4186 IDWriteFontCollection_Release(coll);
4187 IDWriteFontCollection_Release(coll2);
4189 IDWriteFactory1_Release(factory1);
4192 static void test_GetCaretMetrics(void)
4194 DWRITE_FONT_METRICS1 metrics;
4195 IDWriteFontFace1 *fontface1;
4196 DWRITE_CARET_METRICS caret;
4197 IDWriteFontFace *fontface;
4198 IDWriteFactory *factory;
4199 IDWriteFontFile *file;
4200 IDWriteFont *font;
4201 WCHAR *path;
4202 HRESULT hr;
4204 path = create_testfontfile(test_fontfile);
4205 factory = create_factory();
4207 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4208 ok(hr == S_OK, "got 0x%08x\n", hr);
4210 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4211 ok(hr == S_OK, "got 0x%08x\n", hr);
4212 IDWriteFontFile_Release(file);
4214 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4215 IDWriteFontFace_Release(fontface);
4216 if (hr != S_OK) {
4217 win_skip("GetCaretMetrics() is not supported.\n");
4218 IDWriteFactory_Release(factory);
4219 DELETE_FONTFILE(path);
4220 return;
4223 memset(&caret, 0xcc, sizeof(caret));
4224 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4225 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
4226 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
4227 ok(caret.offset == 0, "got %d\n", caret.offset);
4228 IDWriteFontFace1_Release(fontface1);
4229 IDWriteFactory_Release(factory);
4231 /* now with Tahoma Normal */
4232 factory = create_factory();
4233 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
4234 hr = IDWriteFont_CreateFontFace(font, &fontface);
4235 ok(hr == S_OK, "got 0x%08x\n", hr);
4236 IDWriteFont_Release(font);
4237 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4238 ok(hr == S_OK, "got 0x%08x\n", hr);
4239 IDWriteFontFace_Release(fontface);
4241 memset(&caret, 0xcc, sizeof(caret));
4242 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4243 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
4244 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
4245 ok(caret.offset == 0, "got %d\n", caret.offset);
4246 IDWriteFontFace1_Release(fontface1);
4248 /* simulated italic */
4249 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
4250 hr = IDWriteFont_CreateFontFace(font, &fontface);
4251 ok(hr == S_OK, "got 0x%08x\n", hr);
4252 IDWriteFont_Release(font);
4253 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4254 ok(hr == S_OK, "got 0x%08x\n", hr);
4255 IDWriteFontFace_Release(fontface);
4257 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
4259 memset(&caret, 0xcc, sizeof(caret));
4260 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
4261 ok(caret.slopeRise == metrics.designUnitsPerEm, "got %d\n", caret.slopeRise);
4262 ok(caret.slopeRun > 0, "got %d\n", caret.slopeRun);
4263 ok(caret.offset == 0, "got %d\n", caret.offset);
4264 IDWriteFontFace1_Release(fontface1);
4266 IDWriteFactory_Release(factory);
4267 DELETE_FONTFILE(path);
4270 static void test_GetGlyphCount(void)
4272 IDWriteFontFace *fontface;
4273 IDWriteFactory *factory;
4274 IDWriteFontFile *file;
4275 UINT16 count;
4276 WCHAR *path;
4277 HRESULT hr;
4279 path = create_testfontfile(test_fontfile);
4280 factory = create_factory();
4282 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4283 ok(hr == S_OK, "got 0x%08x\n", hr);
4285 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4286 ok(hr == S_OK, "got 0x%08x\n", hr);
4287 IDWriteFontFile_Release(file);
4289 count = IDWriteFontFace_GetGlyphCount(fontface);
4290 ok(count == 7, "got %u\n", count);
4292 IDWriteFontFace_Release(fontface);
4293 IDWriteFactory_Release(factory);
4294 DELETE_FONTFILE(path);
4297 static void test_GetKerningPairAdjustments(void)
4299 IDWriteFontFace1 *fontface1;
4300 IDWriteFontFace *fontface;
4301 IDWriteFactory *factory;
4302 IDWriteFontFile *file;
4303 WCHAR *path;
4304 HRESULT hr;
4306 path = create_testfontfile(test_fontfile);
4307 factory = create_factory();
4309 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
4310 ok(hr == S_OK, "got 0x%08x\n", hr);
4312 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
4313 ok(hr == S_OK, "got 0x%08x\n", hr);
4314 IDWriteFontFile_Release(file);
4316 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4317 if (hr == S_OK) {
4318 INT32 adjustments[1];
4320 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 0, NULL, NULL);
4321 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
4323 if (0) /* crashes on native */
4324 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, NULL);
4326 adjustments[0] = 1;
4327 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, adjustments);
4328 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4329 ok(adjustments[0] == 0, "got %d\n", adjustments[0]);
4331 IDWriteFontFace1_Release(fontface1);
4333 else
4334 win_skip("GetKerningPairAdjustments() is not supported.\n");
4336 IDWriteFontFace_Release(fontface);
4337 IDWriteFactory_Release(factory);
4338 DELETE_FONTFILE(path);
4341 static void test_CreateRenderingParams(void)
4343 IDWriteRenderingParams2 *params2;
4344 IDWriteRenderingParams1 *params1;
4345 IDWriteRenderingParams *params;
4346 DWRITE_RENDERING_MODE mode;
4347 IDWriteFactory3 *factory3;
4348 IDWriteFactory *factory;
4349 HRESULT hr;
4351 factory = create_factory();
4353 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
4354 DWRITE_RENDERING_MODE_DEFAULT, &params);
4355 ok(hr == S_OK, "got 0x%08x\n", hr);
4357 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams1, (void**)&params1);
4358 if (hr == S_OK) {
4359 FLOAT enhcontrast;
4361 /* test what enhanced contrast setting set by default to */
4362 enhcontrast = IDWriteRenderingParams1_GetGrayscaleEnhancedContrast(params1);
4363 ok(enhcontrast == 1.0, "got %.2f\n", enhcontrast);
4364 IDWriteRenderingParams1_Release(params1);
4366 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
4367 if (hr == S_OK) {
4368 DWRITE_GRID_FIT_MODE gridfit;
4370 /* default gridfit mode */
4371 gridfit = IDWriteRenderingParams2_GetGridFitMode(params2);
4372 ok(gridfit == DWRITE_GRID_FIT_MODE_DEFAULT, "got %d\n", gridfit);
4374 IDWriteRenderingParams2_Release(params2);
4376 else
4377 win_skip("IDWriteRenderingParams2 not supported.\n");
4379 else
4380 win_skip("IDWriteRenderingParams1 not supported.\n");
4382 IDWriteRenderingParams_Release(params);
4384 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
4385 ok(hr == S_OK, "got 0x%08x\n", hr);
4387 mode = IDWriteRenderingParams_GetRenderingMode(params);
4388 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
4389 IDWriteRenderingParams_Release(params);
4391 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
4392 if (hr == S_OK) {
4393 IDWriteRenderingParams3 *params3;
4395 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 1.0f, DWRITE_PIXEL_GEOMETRY_FLAT,
4396 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_DEFAULT, &params3);
4397 ok(hr == S_OK, "got 0x%08x\n", hr);
4399 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
4400 ok(hr == S_OK, "got 0x%08x\n", hr);
4402 mode = IDWriteRenderingParams_GetRenderingMode(params);
4403 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
4405 IDWriteRenderingParams_Release(params);
4406 IDWriteRenderingParams3_Release(params3);
4407 IDWriteFactory3_Release(factory3);
4409 else
4410 win_skip("IDWriteRenderingParams3 not supported.\n");
4412 IDWriteFactory_Release(factory);
4415 static void test_CreateGlyphRunAnalysis(void)
4417 static const DWRITE_RENDERING_MODE rendermodes[] = {
4418 DWRITE_RENDERING_MODE_ALIASED,
4419 DWRITE_RENDERING_MODE_GDI_CLASSIC,
4420 DWRITE_RENDERING_MODE_GDI_NATURAL,
4421 DWRITE_RENDERING_MODE_NATURAL,
4422 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
4425 IDWriteGlyphRunAnalysis *analysis, *analysis2;
4426 IDWriteFactory *factory;
4427 DWRITE_GLYPH_RUN run;
4428 IDWriteFontFace *face;
4429 UINT16 glyph, glyphs[10];
4430 FLOAT advances[2];
4431 HRESULT hr;
4432 UINT32 ch;
4433 RECT rect, rect2;
4434 DWRITE_GLYPH_OFFSET offsets[2];
4435 DWRITE_GLYPH_METRICS metrics;
4436 DWRITE_FONT_METRICS fm;
4437 DWRITE_MATRIX m;
4438 int i;
4440 factory = create_factory();
4441 face = create_fontface(factory);
4443 ch = 'A';
4444 glyph = 0;
4445 hr = IDWriteFontFace_GetGlyphIndices(face, &ch, 1, &glyph);
4446 ok(hr == S_OK, "got 0x%08x\n", hr);
4447 ok(glyph > 0, "got %u\n", glyph);
4449 hr = IDWriteFontFace_GetDesignGlyphMetrics(face, &glyph, 1, &metrics, FALSE);
4450 ok(hr == S_OK, "got 0x%08x\n", hr);
4451 advances[0] = metrics.advanceWidth;
4453 offsets[0].advanceOffset = 0.0;
4454 offsets[0].ascenderOffset = 0.0;
4456 run.fontFace = face;
4457 run.fontEmSize = 24.0;
4458 run.glyphCount = 1;
4459 run.glyphIndices = &glyph;
4460 run.glyphAdvances = advances;
4461 run.glyphOffsets = offsets;
4462 run.isSideways = FALSE;
4463 run.bidiLevel = 0;
4465 /* zero ppdip */
4466 analysis = (void*)0xdeadbeef;
4467 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 0.0, NULL,
4468 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4469 0.0, 0.0, &analysis);
4470 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4471 ok(analysis == NULL, "got %p\n", analysis);
4473 /* negative ppdip */
4474 analysis = (void*)0xdeadbeef;
4475 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, -1.0, NULL,
4476 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4477 0.0, 0.0, &analysis);
4478 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4479 ok(analysis == NULL, "got %p\n", analysis);
4481 /* default mode is not allowed */
4482 analysis = (void*)0xdeadbeef;
4483 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4484 DWRITE_RENDERING_MODE_DEFAULT, DWRITE_MEASURING_MODE_NATURAL,
4485 0.0, 0.0, &analysis);
4486 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4487 ok(analysis == NULL, "got %p\n", analysis);
4489 /* outline too */
4490 analysis = (void*)0xdeadbeef;
4491 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4492 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_MEASURING_MODE_NATURAL,
4493 0.0, 0.0, &analysis);
4494 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4495 ok(analysis == NULL, "got %p\n", analysis);
4497 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4498 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4499 0.0, 0.0, &analysis);
4500 ok(hr == S_OK, "got 0x%08x\n", hr);
4502 /* invalid texture type */
4503 memset(&rect, 0xcc, sizeof(rect));
4504 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &rect);
4505 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4506 ok(rect.left == 0 && rect.right == 0 &&
4507 rect.top == 0 && rect.bottom == 0, "unexpected rect\n");
4509 /* check how origin affects bounds */
4510 SetRectEmpty(&rect);
4511 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4512 ok(hr == S_OK, "got 0x%08x\n", hr);
4513 ok(!IsRectEmpty(&rect), "got empty rect\n");
4514 IDWriteGlyphRunAnalysis_Release(analysis);
4516 /* doubled ppdip */
4517 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
4518 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4519 0.0, 0.0, &analysis);
4520 ok(hr == S_OK, "got 0x%08x\n", hr);
4521 SetRectEmpty(&rect2);
4522 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4523 ok(hr == S_OK, "got 0x%08x\n", hr);
4524 ok(rect.right - rect.left < rect2.right - rect2.left, "expected wider rect\n");
4525 ok(rect.bottom - rect.top < rect2.bottom - rect2.top, "expected taller rect\n");
4526 IDWriteGlyphRunAnalysis_Release(analysis);
4528 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4529 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4530 10.0, -5.0, &analysis);
4531 ok(hr == S_OK, "got 0x%08x\n", hr);
4533 SetRectEmpty(&rect2);
4534 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4535 ok(hr == S_OK, "got 0x%08x\n", hr);
4536 ok(!IsRectEmpty(&rect2), "got empty rect\n");
4537 IDWriteGlyphRunAnalysis_Release(analysis);
4539 ok(!EqualRect(&rect, &rect2), "got equal bounds\n");
4540 OffsetRect(&rect, 10, -5);
4541 ok(EqualRect(&rect, &rect2), "got different bounds\n");
4543 for (i = 0; i < sizeof(rendermodes)/sizeof(rendermodes[0]); i++) {
4544 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4545 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
4546 0.0, 0.0, &analysis);
4547 ok(hr == S_OK, "got 0x%08x\n", hr);
4549 if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
4550 SetRectEmpty(&rect);
4551 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4552 ok(hr == S_OK, "got 0x%08x\n", hr);
4553 ok(!IsRectEmpty(&rect), "got empty rect\n");
4555 SetRect(&rect, 0, 0, 1, 1);
4556 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
4557 ok(hr == S_OK, "got 0x%08x\n", hr);
4558 ok(IsRectEmpty(&rect), "unexpected empty rect\n");
4560 else {
4561 SetRect(&rect, 0, 0, 1, 1);
4562 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4563 ok(hr == S_OK, "got 0x%08x\n", hr);
4564 ok(IsRectEmpty(&rect), "got empty rect\n");
4566 SetRectEmpty(&rect);
4567 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
4568 ok(hr == S_OK, "got 0x%08x\n", hr);
4569 ok(!IsRectEmpty(&rect), "got empty rect\n");
4572 IDWriteGlyphRunAnalysis_Release(analysis);
4575 IDWriteFontFace_GetMetrics(run.fontFace, &fm);
4577 /* check bbox for a single glyph run */
4578 for (run.fontEmSize = 1.0; run.fontEmSize <= 100.0; run.fontEmSize += 1.0) {
4579 DWRITE_GLYPH_METRICS gm;
4580 LONG bboxX, bboxY;
4582 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4583 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
4584 0.0, 0.0, &analysis);
4585 ok(hr == S_OK, "got 0x%08x\n", hr);
4587 SetRectEmpty(&rect);
4588 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4589 ok(hr == S_OK, "got 0x%08x\n", hr);
4591 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
4592 DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
4593 ok(hr == S_OK, "got 0x%08x\n", hr);
4595 /* metrics are in design units */
4596 bboxX = (int)floorf((gm.advanceWidth - gm.leftSideBearing - gm.rightSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
4597 bboxY = (int)floorf((gm.advanceHeight - gm.topSideBearing - gm.bottomSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
4599 rect.right -= rect.left;
4600 rect.bottom -= rect.top;
4601 ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %d, from metrics %d\n", run.fontEmSize, rect.right, bboxX);
4602 ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %d, from metrics %d\n", run.fontEmSize, rect.bottom, bboxY);
4604 IDWriteGlyphRunAnalysis_Release(analysis);
4607 /* without offsets */
4608 run.fontFace = face;
4609 run.fontEmSize = 24.0;
4610 run.glyphCount = 1;
4611 run.glyphIndices = &glyph;
4612 run.glyphAdvances = advances;
4613 run.glyphOffsets = NULL;
4614 run.isSideways = FALSE;
4615 run.bidiLevel = 0;
4617 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4618 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4619 0.0, 0.0, &analysis);
4620 ok(hr == S_OK, "got 0x%08x\n", hr);
4622 SetRectEmpty(&rect);
4623 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4624 ok(hr == S_OK, "got 0x%08x\n", hr);
4625 ok(!IsRectEmpty(&rect), "got empty bounds\n");
4627 IDWriteGlyphRunAnalysis_Release(analysis);
4629 /* without explicit advances */
4630 run.fontFace = face;
4631 run.fontEmSize = 24.0;
4632 run.glyphCount = 1;
4633 run.glyphIndices = &glyph;
4634 run.glyphAdvances = NULL;
4635 run.glyphOffsets = NULL;
4636 run.isSideways = FALSE;
4637 run.bidiLevel = 0;
4639 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4640 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4641 0.0, 0.0, &analysis);
4642 ok(hr == S_OK, "got 0x%08x\n", hr);
4644 SetRectEmpty(&rect);
4645 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4646 ok(hr == S_OK, "got 0x%08x\n", hr);
4647 ok(!IsRectEmpty(&rect), "got empty bounds\n");
4649 IDWriteGlyphRunAnalysis_Release(analysis);
4651 /* test that advances are scaled according to ppdip too */
4652 glyphs[0] = glyphs[1] = glyph;
4653 advances[0] = advances[1] = 100.0f;
4654 run.fontFace = face;
4655 run.fontEmSize = 24.0;
4656 run.glyphCount = 2;
4657 run.glyphIndices = glyphs;
4658 run.glyphAdvances = advances;
4659 run.glyphOffsets = NULL;
4660 run.isSideways = FALSE;
4661 run.bidiLevel = 0;
4663 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4664 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4665 0.0, 0.0, &analysis);
4666 ok(hr == S_OK, "got 0x%08x\n", hr);
4668 SetRectEmpty(&rect2);
4669 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4670 ok(hr == S_OK, "got 0x%08x\n", hr);
4671 ok(!IsRectEmpty(&rect2), "got empty bounds\n");
4672 ok(!EqualRect(&rect, &rect2), "got wrong rect2\n");
4673 ok((rect2.right - rect.left) > advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
4674 IDWriteGlyphRunAnalysis_Release(analysis);
4676 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
4677 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4678 0.0, 0.0, &analysis);
4679 ok(hr == S_OK, "got 0x%08x\n", hr);
4681 SetRectEmpty(&rect);
4682 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4683 ok(hr == S_OK, "got 0x%08x\n", hr);
4684 ok((rect.right - rect.left) > 2 * advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
4685 IDWriteGlyphRunAnalysis_Release(analysis);
4687 /* with scaling transform */
4688 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4689 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4690 0.0, 0.0, &analysis);
4691 ok(hr == S_OK, "got 0x%08x\n", hr);
4693 SetRectEmpty(&rect);
4694 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
4695 ok(hr == S_OK, "got 0x%08x\n", hr);
4696 ok(!IsRectEmpty(&rect), "got rect width %d\n", rect.right - rect.left);
4697 IDWriteGlyphRunAnalysis_Release(analysis);
4699 memset(&m, 0, sizeof(m));
4700 m.m11 = 2.0;
4701 m.m22 = 1.0;
4702 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
4703 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4704 0.0, 0.0, &analysis);
4705 ok(hr == S_OK, "got 0x%08x\n", hr);
4707 SetRectEmpty(&rect2);
4708 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
4709 ok(hr == S_OK, "got 0x%08x\n", hr);
4710 ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %d\n", rect2.right - rect2.left);
4712 /* instances are not reused for same runs */
4713 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
4714 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
4715 0.0, 0.0, &analysis2);
4716 ok(hr == S_OK, "got 0x%08x\n", hr);
4717 ok(analysis2 != analysis, "got %p, previous instance %p\n", analysis2, analysis);
4718 IDWriteGlyphRunAnalysis_Release(analysis2);
4720 IDWriteGlyphRunAnalysis_Release(analysis);
4722 IDWriteFontFace_Release(face);
4723 IDWriteFactory_Release(factory);
4726 #define round(x) ((int)floor((x) + 0.5))
4728 struct VDMX_Header
4730 WORD version;
4731 WORD numRecs;
4732 WORD numRatios;
4735 struct VDMX_Ratio
4737 BYTE bCharSet;
4738 BYTE xRatio;
4739 BYTE yStartRatio;
4740 BYTE yEndRatio;
4743 struct VDMX_group
4745 WORD recs;
4746 BYTE startsz;
4747 BYTE endsz;
4750 struct VDMX_vTable
4752 WORD yPelHeight;
4753 SHORT yMax;
4754 SHORT yMin;
4757 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
4759 WORD num_ratios, i, group_offset = 0;
4760 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
4761 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
4763 num_ratios = GET_BE_WORD(hdr->numRatios);
4765 for (i = 0; i < num_ratios; i++)
4767 if (!ratios[i].bCharSet) continue;
4769 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
4770 ratios[i].yEndRatio == 0) ||
4771 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
4772 ratios[i].yEndRatio >= dev_y_ratio))
4774 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
4775 break;
4778 if (group_offset)
4779 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
4780 return NULL;
4783 static BOOL get_vdmx_size(const struct VDMX_group *group, int emsize, int *a, int *d)
4785 WORD recs, i;
4786 const struct VDMX_vTable *tables;
4788 if (!group) return FALSE;
4790 recs = GET_BE_WORD(group->recs);
4791 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
4793 tables = (const struct VDMX_vTable *)(group + 1);
4794 for (i = 0; i < recs; i++)
4796 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
4797 if (ppem > emsize)
4799 /* FIXME: Supposed to interpolate */
4800 trace("FIXME interpolate %d\n", emsize);
4801 return FALSE;
4804 if (ppem == emsize)
4806 *a = (SHORT)GET_BE_WORD(tables[i].yMax);
4807 *d = -(SHORT)GET_BE_WORD(tables[i].yMin);
4808 return TRUE;
4811 return FALSE;
4814 static void test_metrics_cmp(FLOAT emsize, const DWRITE_FONT_METRICS *metrics, const DWRITE_FONT_METRICS1 *expected)
4816 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
4817 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
4818 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
4819 emsize, metrics->ascent, expected->ascent);
4820 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
4821 emsize, metrics->descent, expected->descent);
4822 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
4823 emsize, metrics->lineGap, expected->lineGap);
4824 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
4825 emsize, metrics->capHeight, expected->capHeight);
4826 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
4827 emsize, metrics->xHeight, expected->xHeight);
4828 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
4829 emsize, metrics->underlinePosition, expected->underlinePosition);
4830 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
4831 emsize, metrics->underlineThickness, expected->underlineThickness);
4832 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
4833 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
4834 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
4835 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
4838 static void test_metrics1_cmp(FLOAT emsize, const DWRITE_FONT_METRICS1 *metrics, const DWRITE_FONT_METRICS1 *expected)
4840 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
4841 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
4842 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
4843 emsize, metrics->ascent, expected->ascent);
4844 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
4845 emsize, metrics->descent, expected->descent);
4846 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
4847 emsize, metrics->lineGap, expected->lineGap);
4848 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
4849 emsize, metrics->capHeight, expected->capHeight);
4850 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
4851 emsize, metrics->xHeight, expected->xHeight);
4852 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
4853 emsize, metrics->underlinePosition, expected->underlinePosition);
4854 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
4855 emsize, metrics->underlineThickness, expected->underlineThickness);
4856 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
4857 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
4858 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
4859 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
4860 ok(metrics->glyphBoxLeft == expected->glyphBoxLeft, "%.2f box left: got %d expect %d\n",
4861 emsize, metrics->glyphBoxLeft, expected->glyphBoxLeft);
4862 if (0) { /* this is not consistent */
4863 ok(metrics->glyphBoxTop == expected->glyphBoxTop, "%.2f box top: got %d expect %d\n",
4864 emsize, metrics->glyphBoxTop, expected->glyphBoxTop);
4865 ok(metrics->glyphBoxRight == expected->glyphBoxRight, "%.2f box right: got %d expect %d\n",
4866 emsize, metrics->glyphBoxRight, expected->glyphBoxRight);
4868 ok(metrics->glyphBoxBottom == expected->glyphBoxBottom, "%.2f box bottom: got %d expect %d\n",
4869 emsize, metrics->glyphBoxBottom, expected->glyphBoxBottom);
4870 ok(metrics->subscriptPositionX == expected->subscriptPositionX, "%.2f subX: got %d expect %d\n",
4871 emsize, metrics->subscriptPositionX, expected->subscriptPositionX);
4872 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subY: got %d expect %d\n",
4873 emsize, metrics->subscriptPositionY, expected->subscriptPositionY);
4874 ok(metrics->subscriptSizeX == expected->subscriptSizeX, "%.2f subsizeX: got %d expect %d\n",
4875 emsize, metrics->subscriptSizeX, expected->subscriptSizeX);
4876 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subsizeY: got %d expect %d\n",
4877 emsize, metrics->subscriptSizeY, expected->subscriptSizeY);
4878 ok(metrics->superscriptPositionX == expected->superscriptPositionX, "%.2f supX: got %d expect %d\n",
4879 emsize, metrics->superscriptPositionX, expected->superscriptPositionX);
4880 if (0)
4881 ok(metrics->superscriptPositionY == expected->superscriptPositionY, "%.2f supY: got %d expect %d\n",
4882 emsize, metrics->superscriptPositionY, expected->superscriptPositionY);
4883 ok(metrics->superscriptSizeX == expected->superscriptSizeX, "%.2f supsizeX: got %d expect %d\n",
4884 emsize, metrics->superscriptSizeX, expected->superscriptSizeX);
4885 ok(metrics->superscriptSizeY == expected->superscriptSizeY, "%.2f supsizeY: got %d expect %d\n",
4886 emsize, metrics->superscriptSizeY, expected->superscriptSizeY);
4887 ok(metrics->hasTypographicMetrics == expected->hasTypographicMetrics, "%.2f hastypo: got %d expect %d\n",
4888 emsize, metrics->hasTypographicMetrics, expected->hasTypographicMetrics);
4891 struct compatmetrics_test {
4892 DWRITE_MATRIX m;
4893 FLOAT ppdip;
4894 FLOAT emsize;
4897 static struct compatmetrics_test compatmetrics_tests[] = {
4898 { { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0, 5.0 },
4899 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 1.0, 5.0 },
4900 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 2.0, 5.0 },
4901 { { 0.0, 0.0, 0.0, 3.0, 0.0, 0.0 }, 2.0, 5.0 },
4902 { { 0.0, 0.0, 0.0, -3.0, 0.0, 0.0 }, 2.0, 5.0 },
4903 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 2.0, 5.0 },
4904 { { 1.0, 0.0, 0.0, 1.0, 5.0, 0.0 }, 2.0, 5.0 },
4905 { { 1.0, 0.0, 0.0, 1.0, 0.0, 5.0 }, 2.0, 5.0 },
4908 static void get_expected_metrics(IDWriteFontFace *fontface, struct compatmetrics_test *ptr,
4909 DWRITE_FONT_METRICS *expected)
4911 HRESULT hr;
4913 memset(expected, 0, sizeof(*expected));
4914 hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, ptr->ppdip * fabsf(ptr->m.m22) * ptr->emsize, 1.0, NULL, expected);
4915 ok(hr == S_OK, "got %08x\n", hr);
4918 static void test_GetGdiCompatibleMetrics_face(IDWriteFontFace *face)
4920 IDWriteFontFace1 *fontface1 = NULL;
4921 HRESULT hr;
4922 DWRITE_FONT_METRICS design_metrics, comp_metrics;
4923 DWRITE_FONT_METRICS1 design_metrics1, expected;
4924 FLOAT emsize, scale;
4925 int ascent, descent;
4926 const struct VDMX_Header *vdmx;
4927 UINT32 vdmx_len;
4928 void *vdmx_ctx;
4929 BOOL exists;
4930 const struct VDMX_group *vdmx_group = NULL;
4931 int i;
4933 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace1, (void**)&fontface1);
4934 if (hr != S_OK)
4935 win_skip("gdi compatible DWRITE_FONT_METRICS1 are not supported.\n");
4937 if (fontface1) {
4938 IDWriteFontFace1_GetMetrics(fontface1, &design_metrics1);
4939 memcpy(&design_metrics, &design_metrics1, sizeof(design_metrics));
4941 else
4942 IDWriteFontFace_GetMetrics(face, &design_metrics);
4944 hr = IDWriteFontFace_TryGetFontTable(face, MS_VDMX_TAG, (const void **)&vdmx,
4945 &vdmx_len, &vdmx_ctx, &exists);
4946 if (hr != S_OK || !exists)
4947 vdmx = NULL;
4948 else
4949 vdmx_group = find_vdmx_group(vdmx);
4951 /* negative emsize */
4952 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4953 memset(&expected, 0, sizeof(expected));
4954 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, -10.0, 1.0, NULL, &comp_metrics);
4955 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4956 test_metrics_cmp(0.0, &comp_metrics, &expected);
4958 /* zero emsize */
4959 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4960 memset(&expected, 0, sizeof(expected));
4961 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 0.0, 1.0, NULL, &comp_metrics);
4962 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4963 test_metrics_cmp(0.0, &comp_metrics, &expected);
4965 /* zero pixels per dip */
4966 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4967 memset(&expected, 0, sizeof(expected));
4968 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, 0.0, NULL, &comp_metrics);
4969 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4970 test_metrics_cmp(5.0, &comp_metrics, &expected);
4972 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4973 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, -1.0, NULL, &comp_metrics);
4974 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4975 test_metrics_cmp(5.0, &comp_metrics, &expected);
4977 for (i = 0; i < sizeof(compatmetrics_tests)/sizeof(compatmetrics_tests[0]); i++) {
4978 struct compatmetrics_test *ptr = &compatmetrics_tests[i];
4980 get_expected_metrics(face, ptr, (DWRITE_FONT_METRICS*)&expected);
4981 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, ptr->emsize, ptr->ppdip, &ptr->m, &comp_metrics);
4982 ok(hr == S_OK, "got %08x\n", hr);
4983 test_metrics_cmp(ptr->emsize, &comp_metrics, &expected);
4986 for (emsize = 5; emsize <= design_metrics.designUnitsPerEm; emsize++)
4988 DWRITE_FONT_METRICS1 comp_metrics1, expected;
4990 if (fontface1) {
4991 hr = IDWriteFontFace1_GetGdiCompatibleMetrics(fontface1, emsize, 1.0, NULL, &comp_metrics1);
4992 ok(hr == S_OK, "got %08x\n", hr);
4994 else {
4995 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, emsize, 1.0, NULL, &comp_metrics);
4996 ok(hr == S_OK, "got %08x\n", hr);
4999 scale = emsize / design_metrics.designUnitsPerEm;
5000 if (!get_vdmx_size(vdmx_group, emsize, &ascent, &descent))
5002 ascent = round(design_metrics.ascent * scale);
5003 descent = round(design_metrics.descent * scale);
5006 expected.designUnitsPerEm = design_metrics.designUnitsPerEm;
5007 expected.ascent = round(ascent / scale );
5008 expected.descent = round(descent / scale );
5009 expected.lineGap = round(round(design_metrics.lineGap * scale) / scale);
5010 expected.capHeight = round(round(design_metrics.capHeight * scale) / scale);
5011 expected.xHeight = round(round(design_metrics.xHeight * scale) / scale);
5012 expected.underlinePosition = round(round(design_metrics.underlinePosition * scale) / scale);
5013 expected.underlineThickness = round(round(design_metrics.underlineThickness * scale) / scale);
5014 expected.strikethroughPosition = round(round(design_metrics.strikethroughPosition * scale) / scale);
5015 expected.strikethroughThickness = round(round(design_metrics.strikethroughThickness * scale) / scale);
5017 if (fontface1) {
5018 expected.glyphBoxLeft = round(round(design_metrics1.glyphBoxLeft * scale) / scale);
5020 if (0) { /* those two fail on Tahoma and Win7 */
5021 expected.glyphBoxTop = round(round(design_metrics1.glyphBoxTop * scale) / scale);
5022 expected.glyphBoxRight = round(round(design_metrics1.glyphBoxRight * scale) / scale);
5024 expected.glyphBoxBottom = round(round(design_metrics1.glyphBoxBottom * scale) / scale);
5025 expected.subscriptPositionX = round(round(design_metrics1.subscriptPositionX * scale) / scale);
5026 expected.subscriptPositionY = round(round(design_metrics1.subscriptPositionY * scale) / scale);
5027 expected.subscriptSizeX = round(round(design_metrics1.subscriptSizeX * scale) / scale);
5028 expected.subscriptSizeY = round(round(design_metrics1.subscriptSizeY * scale) / scale);
5029 expected.superscriptPositionX = round(round(design_metrics1.superscriptPositionX * scale) / scale);
5030 if (0) /* this fails for 3 emsizes, Tahoma from [5, 2048] range */ {
5031 expected.superscriptPositionY = round(round(design_metrics1.superscriptPositionY * scale) / scale);
5033 expected.superscriptSizeX = round(round(design_metrics1.superscriptSizeX * scale) / scale);
5034 expected.superscriptSizeY = round(round(design_metrics1.superscriptSizeY * scale) / scale);
5035 expected.hasTypographicMetrics = design_metrics1.hasTypographicMetrics;
5037 test_metrics1_cmp(emsize, &comp_metrics1, &expected);
5039 else
5040 test_metrics_cmp(emsize, &comp_metrics, &expected);
5044 if (fontface1)
5045 IDWriteFontFace1_Release(fontface1);
5046 if (vdmx) IDWriteFontFace_ReleaseFontTable(face, vdmx_ctx);
5049 static void test_GetGdiCompatibleMetrics(void)
5051 IDWriteFactory *factory;
5052 IDWriteFont *font;
5053 IDWriteFontFace *fontface;
5054 HRESULT hr;
5056 factory = create_factory();
5058 font = get_font(factory, tahomaW, DWRITE_FONT_STYLE_NORMAL);
5059 hr = IDWriteFont_CreateFontFace(font, &fontface);
5060 ok(hr == S_OK, "got 0x%08x\n", hr);
5061 IDWriteFont_Release(font);
5062 test_GetGdiCompatibleMetrics_face(fontface);
5063 IDWriteFontFace_Release(fontface);
5065 font = get_font(factory, arialW, DWRITE_FONT_STYLE_NORMAL);
5066 if (!font)
5067 skip("Skipping tests with Arial\n");
5068 else
5070 hr = IDWriteFont_CreateFontFace(font, &fontface);
5071 ok(hr == S_OK, "got 0x%08x\n", hr);
5072 IDWriteFont_Release(font);
5074 test_GetGdiCompatibleMetrics_face(fontface);
5075 IDWriteFontFace_Release(fontface);
5078 IDWriteFactory_Release(factory);
5081 static void test_GetPanose(void)
5083 IDWriteFactory *factory;
5084 IDWriteFont1 *font1;
5085 IDWriteFont *font;
5086 HRESULT hr;
5088 factory = create_factory();
5089 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5091 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
5092 IDWriteFont_Release(font);
5093 if (hr == S_OK) {
5094 IDWriteFontFace3 *fontface3;
5095 IDWriteFontFace *fontface;
5096 DWRITE_PANOSE panose;
5098 if (0) /* crashes on native */
5099 IDWriteFont1_GetPanose(font1, NULL);
5101 memset(&panose, 0, sizeof(panose));
5102 IDWriteFont1_GetPanose(font1, &panose);
5103 ok(panose.familyKind == DWRITE_PANOSE_FAMILY_TEXT_DISPLAY,
5104 "got %u\n", panose.familyKind);
5105 ok(panose.text.serifStyle == DWRITE_PANOSE_SERIF_STYLE_NORMAL_SANS,
5106 "got %u\n", panose.text.serifStyle);
5107 ok(panose.text.weight == DWRITE_PANOSE_WEIGHT_MEDIUM,
5108 "got %u\n", panose.text.weight);
5109 ok(panose.text.proportion == DWRITE_PANOSE_PROPORTION_EVEN_WIDTH,
5110 "got %u\n", panose.text.proportion);
5111 ok(panose.text.contrast == DWRITE_PANOSE_CONTRAST_VERY_LOW,
5112 "got %u\n", panose.text.contrast);
5113 ok(panose.text.strokeVariation == DWRITE_PANOSE_STROKE_VARIATION_GRADUAL_VERTICAL,
5114 "got %u\n", panose.text.strokeVariation);
5115 ok(panose.text.armStyle == DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_VERTICAL,
5116 "got %u\n", panose.text.armStyle);
5117 ok(panose.text.letterform == DWRITE_PANOSE_LETTERFORM_NORMAL_BOXED,
5118 "got %u\n", panose.text.letterform);
5119 ok(panose.text.midline == DWRITE_PANOSE_MIDLINE_STANDARD_TRIMMED,
5120 "got %u\n", panose.text.midline);
5121 ok(panose.text.xHeight == DWRITE_PANOSE_XHEIGHT_CONSTANT_LARGE,
5122 "got %u\n", panose.text.xHeight);
5124 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
5125 ok(hr == S_OK, "got 0x%08x\n", hr);
5127 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
5128 IDWriteFontFace_Release(fontface);
5129 if (hr == S_OK) {
5130 DWRITE_PANOSE panose2;
5132 IDWriteFontFace3_GetPanose(fontface3, &panose2);
5133 ok(!memcmp(&panose, &panose2, sizeof(panose)), "wrong panose data\n");
5135 IDWriteFontFace3_Release(fontface3);
5138 IDWriteFont1_Release(font1);
5140 else
5141 win_skip("GetPanose() is not supported.\n");
5143 IDWriteFactory_Release(factory);
5146 static INT32 get_gdi_font_advance(HDC hdc, FLOAT emsize)
5148 LOGFONTW logfont;
5149 HFONT hfont;
5150 BOOL ret;
5151 ABC abc;
5153 memset(&logfont, 0, sizeof(logfont));
5154 logfont.lfHeight = (LONG)-emsize;
5155 logfont.lfWeight = FW_NORMAL;
5156 logfont.lfQuality = CLEARTYPE_QUALITY;
5157 lstrcpyW(logfont.lfFaceName, tahomaW);
5159 hfont = CreateFontIndirectW(&logfont);
5160 SelectObject(hdc, hfont);
5162 ret = GetCharABCWidthsW(hdc, 'A', 'A', &abc);
5163 ok(ret, "got %d\n", ret);
5165 DeleteObject(hfont);
5167 return abc.abcA + abc.abcB + abc.abcC;
5170 static void test_GetGdiCompatibleGlyphAdvances(void)
5172 IDWriteFontFace1 *fontface1;
5173 IDWriteFontFace *fontface;
5174 IDWriteFactory *factory;
5175 IDWriteFont *font;
5176 HRESULT hr;
5177 HDC hdc;
5178 UINT32 codepoint;
5179 UINT16 glyph;
5180 FLOAT emsize;
5181 DWRITE_FONT_METRICS1 fm;
5182 INT32 advance;
5184 factory = create_factory();
5185 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
5187 hr = IDWriteFont_CreateFontFace(font, &fontface);
5188 ok(hr == S_OK, "got 0x%08x\n", hr);
5189 IDWriteFont_Release(font);
5191 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5192 IDWriteFontFace_Release(fontface);
5194 if (hr != S_OK) {
5195 IDWriteFactory_Release(factory);
5196 win_skip("GetGdiCompatibleGlyphAdvances() is not supported\n");
5197 return;
5200 codepoint = 'A';
5201 glyph = 0;
5202 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &glyph);
5203 ok(hr == S_OK, "got 0x%08x\n", hr);
5204 ok(glyph > 0, "got %u\n", glyph);
5206 /* zero emsize */
5207 advance = 1;
5208 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 0.0,
5209 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5210 ok(hr == S_OK, "got 0x%08x\n", hr);
5211 ok(advance == 0, "got %d\n", advance);
5213 /* negative emsize */
5214 advance = 1;
5215 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, -1.0,
5216 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5217 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5218 ok(advance == 0, "got %d\n", advance);
5220 /* zero ppdip */
5221 advance = 1;
5222 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
5223 0.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5224 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5225 ok(advance == 0, "got %d\n", advance);
5227 /* negative ppdip */
5228 advance = 1;
5229 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
5230 -1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5231 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5232 ok(advance == 0, "got %d\n", advance);
5234 IDWriteFontFace1_GetMetrics(fontface1, &fm);
5236 hdc = CreateCompatibleDC(0);
5238 for (emsize = 1.0; emsize <= fm.designUnitsPerEm; emsize += 1.0) {
5239 INT32 gdi_advance;
5241 gdi_advance = get_gdi_font_advance(hdc, emsize);
5242 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emsize,
5243 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
5244 ok(hr == S_OK, "got 0x%08x\n", hr);
5246 /* advance is in design units */
5247 advance = (int)floorf(emsize * advance / fm.designUnitsPerEm + 0.5f);
5248 ok((advance - gdi_advance) <= 2, "%.0f: got advance %d, expected %d\n", emsize, advance, gdi_advance);
5251 DeleteObject(hdc);
5253 IDWriteFactory_Release(factory);
5256 static WORD get_gasp_flags(IDWriteFontFace *fontface, FLOAT emsize, FLOAT ppdip)
5258 WORD num_recs, version;
5259 const WORD *ptr;
5260 WORD flags = 0;
5261 UINT32 size;
5262 BOOL exists;
5263 void *ctxt;
5264 HRESULT hr;
5266 emsize *= ppdip;
5268 exists = FALSE;
5269 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GASP_TAG,
5270 (const void**)&ptr, &size, &ctxt, &exists);
5271 ok(hr == S_OK, "got 0x%08x\n", hr);
5273 if (!exists)
5274 goto done;
5276 version = GET_BE_WORD( *ptr++ );
5277 num_recs = GET_BE_WORD( *ptr++ );
5278 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
5279 ok(0, "unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
5280 goto done;
5283 while (num_recs--)
5285 flags = GET_BE_WORD( *(ptr + 1) );
5286 if (emsize <= GET_BE_WORD( *ptr )) break;
5287 ptr += 2;
5290 done:
5291 IDWriteFontFace_ReleaseFontTable(fontface, ctxt);
5292 return flags;
5295 #define GASP_GRIDFIT 0x0001
5296 #define GASP_DOGRAY 0x0002
5297 #define GASP_SYMMETRIC_GRIDFIT 0x0004
5298 #define GASP_SYMMETRIC_SMOOTHING 0x0008
5300 static BOOL g_is_vista;
5301 static DWRITE_RENDERING_MODE get_expected_rendering_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
5302 DWRITE_OUTLINE_THRESHOLD threshold)
5304 static const FLOAT aa_threshold = 100.0f;
5305 static const FLOAT a_threshold = 350.0f;
5306 static const FLOAT naturalemsize = 20.0f;
5307 FLOAT v;
5309 /* outline threshold */
5310 if (g_is_vista)
5311 v = mode == DWRITE_MEASURING_MODE_NATURAL ? aa_threshold : a_threshold;
5312 else
5313 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
5315 if (emsize >= v)
5316 return DWRITE_RENDERING_MODE_OUTLINE;
5318 switch (mode)
5320 case DWRITE_MEASURING_MODE_NATURAL:
5321 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (emsize <= naturalemsize))
5322 return DWRITE_RENDERING_MODE_NATURAL;
5323 else
5324 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
5325 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
5326 return DWRITE_RENDERING_MODE_GDI_CLASSIC;
5327 case DWRITE_MEASURING_MODE_GDI_NATURAL:
5328 return DWRITE_RENDERING_MODE_GDI_NATURAL;
5329 default:
5333 /* should be unreachable */
5334 return DWRITE_RENDERING_MODE_DEFAULT;
5337 static DWRITE_GRID_FIT_MODE get_expected_gridfit_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
5338 DWRITE_OUTLINE_THRESHOLD threshold)
5340 static const FLOAT aa_threshold = 100.0f;
5341 static const FLOAT a_threshold = 350.0f;
5342 FLOAT v;
5344 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
5345 if (emsize >= v)
5346 return DWRITE_GRID_FIT_MODE_DISABLED;
5348 if (mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
5349 return DWRITE_GRID_FIT_MODE_ENABLED;
5351 return (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
5354 struct recommendedmode_test
5356 DWRITE_MEASURING_MODE measuring;
5357 DWRITE_OUTLINE_THRESHOLD threshold;
5360 static const struct recommendedmode_test recmode_tests[] = {
5361 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5362 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5363 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5366 static const struct recommendedmode_test recmode_tests1[] = {
5367 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5368 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5369 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
5370 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5371 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5372 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
5375 static void test_GetRecommendedRenderingMode(void)
5377 IDWriteRenderingParams *params;
5378 IDWriteFontFace3 *fontface3;
5379 IDWriteFontFace2 *fontface2;
5380 IDWriteFontFace1 *fontface1;
5381 IDWriteFontFace *fontface;
5382 DWRITE_RENDERING_MODE mode;
5383 IDWriteFactory *factory;
5384 FLOAT emsize;
5385 HRESULT hr;
5387 factory = create_factory();
5388 fontface = create_fontface(factory);
5390 fontface1 = NULL;
5391 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
5392 if (hr != S_OK)
5393 win_skip("IDWriteFontFace1::GetRecommendedRenderingMode() is not supported.\n");
5395 fontface2 = NULL;
5396 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
5397 if (hr != S_OK)
5398 win_skip("IDWriteFontFace2::GetRecommendedRenderingMode() is not supported.\n");
5400 fontface3 = NULL;
5401 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
5402 if (hr != S_OK)
5403 win_skip("IDWriteFontFace3::GetRecommendedRenderingMode() is not supported.\n");
5405 if (0) /* crashes on native */
5406 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
5407 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, NULL);
5409 mode = 10;
5410 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
5411 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode);
5412 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5413 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
5415 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
5416 ok(hr == S_OK, "got 0x%08x\n", hr);
5418 /* detect old dwrite version, that is using higher threshold value */
5419 g_is_vista = fontface1 == NULL;
5421 for (emsize = 1.0; emsize < 500.0; emsize += 1.0) {
5422 DWRITE_RENDERING_MODE expected;
5423 FLOAT ppdip;
5424 WORD gasp;
5425 int i;
5427 for (i = 0; i < sizeof(recmode_tests)/sizeof(recmode_tests[0]); i++) {
5428 ppdip = 1.0f;
5429 mode = 10;
5430 gasp = get_gasp_flags(fontface, emsize, ppdip);
5431 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
5432 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
5433 ok(hr == S_OK, "got 0x%08x\n", hr);
5434 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
5436 /* some ppdip variants */
5437 ppdip = 0.5f;
5438 mode = 10;
5439 gasp = get_gasp_flags(fontface, emsize, ppdip);
5440 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
5441 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
5442 ok(hr == S_OK, "got 0x%08x\n", hr);
5443 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
5445 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
5446 Win8 and Win10 handle this as expected. */
5447 if (emsize > 20.0f) {
5448 ppdip = 1.5f;
5449 mode = 10;
5450 gasp = get_gasp_flags(fontface, emsize, ppdip);
5451 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
5452 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
5453 ok(hr == S_OK, "got 0x%08x\n", hr);
5454 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
5456 ppdip = 2.0f;
5457 mode = 10;
5458 gasp = get_gasp_flags(fontface, emsize, ppdip);
5459 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
5460 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
5461 ok(hr == S_OK, "got 0x%08x\n", hr);
5462 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
5466 /* IDWriteFontFace1 offers another variant of this method */
5467 if (fontface1) {
5468 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
5469 FLOAT dpi;
5471 ppdip = 1.0f;
5472 dpi = 96.0f * ppdip;
5473 mode = 10;
5474 gasp = get_gasp_flags(fontface, emsize, ppdip);
5475 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5476 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
5477 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
5478 ok(hr == S_OK, "got 0x%08x\n", hr);
5479 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
5481 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
5482 Win8 and Win10 handle this as expected. */
5483 if (emsize > 20.0f) {
5484 ppdip = 2.0f;
5485 dpi = 96.0f * ppdip;
5486 mode = 10;
5487 gasp = get_gasp_flags(fontface, emsize, ppdip);
5488 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5489 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
5490 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
5491 ok(hr == S_OK, "got 0x%08x\n", hr);
5492 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
5494 ppdip = 0.5f;
5495 dpi = 96.0f * ppdip;
5496 mode = 10;
5497 gasp = get_gasp_flags(fontface, emsize, ppdip);
5498 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5499 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
5500 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
5501 ok(hr == S_OK, "got 0x%08x\n", hr);
5502 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
5504 /* try different dpis for X and Y direction */
5505 ppdip = 1.0f;
5506 dpi = 96.0f * ppdip;
5507 mode = 10;
5508 gasp = get_gasp_flags(fontface, emsize, ppdip);
5509 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5510 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
5511 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
5512 ok(hr == S_OK, "got 0x%08x\n", hr);
5513 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
5515 ppdip = 1.0f;
5516 dpi = 96.0f * ppdip;
5517 mode = 10;
5518 gasp = get_gasp_flags(fontface, emsize, ppdip);
5519 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5520 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
5521 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
5522 ok(hr == S_OK, "got 0x%08x\n", hr);
5523 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
5525 ppdip = 2.0f;
5526 dpi = 96.0f * ppdip;
5527 mode = 10;
5528 gasp = get_gasp_flags(fontface, emsize, ppdip);
5529 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5530 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
5531 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
5532 ok(hr == S_OK, "got 0x%08x\n", hr);
5533 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
5535 ppdip = 2.0f;
5536 dpi = 96.0f * ppdip;
5537 mode = 10;
5538 gasp = get_gasp_flags(fontface, emsize, ppdip);
5539 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5540 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
5541 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
5542 ok(hr == S_OK, "got 0x%08x\n", hr);
5543 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
5548 /* IDWriteFontFace2 - another one */
5549 if (fontface2) {
5550 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
5552 gasp = get_gasp_flags(fontface, emsize, 1.0f);
5553 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
5554 mode = 10;
5555 expected = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5556 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5557 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, emsize, 96.0f, 96.0f,
5558 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode, &gridfit);
5559 ok(hr == S_OK, "got 0x%08x\n", hr);
5560 ok(mode == expected, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode, gasp, expected);
5561 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
5562 gasp, expected_gridfit);
5566 /* IDWriteFontFace3 - and another one */
5567 if (fontface3) {
5568 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
5569 DWRITE_RENDERING_MODE1 mode1, expected1;
5571 gasp = get_gasp_flags(fontface, emsize, 1.0f);
5572 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
5573 mode1 = 10;
5574 expected1 = get_expected_rendering_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5575 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
5576 hr = IDWriteFontFace3_GetRecommendedRenderingMode(fontface3, emsize, 96.0f, 96.0f,
5577 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, params, &mode1, &gridfit);
5578 ok(hr == S_OK, "got 0x%08x\n", hr);
5579 ok(mode1 == expected1, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode1, gasp, expected1);
5580 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
5581 gasp, expected_gridfit);
5586 IDWriteRenderingParams_Release(params);
5588 /* test how parameters override returned modes */
5589 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
5590 DWRITE_RENDERING_MODE_GDI_CLASSIC, &params);
5591 ok(hr == S_OK, "got 0x%08x\n", hr);
5593 mode = 10;
5594 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode);
5595 ok(hr == S_OK, "got 0x%08x\n", hr);
5596 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
5598 IDWriteRenderingParams_Release(params);
5600 if (fontface2) {
5601 IDWriteRenderingParams2 *params2;
5602 IDWriteFactory2 *factory2;
5603 DWRITE_GRID_FIT_MODE gridfit;
5605 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
5606 ok(hr == S_OK, "got 0x%08x\n", hr);
5608 hr = IDWriteFactory2_CreateCustomRenderingParams(factory2, 1.0, 0.0, 0.0, 0.5, DWRITE_PIXEL_GEOMETRY_FLAT,
5609 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_GRID_FIT_MODE_ENABLED, &params2);
5610 ok(hr == S_OK, "got 0x%08x\n", hr);
5612 mode = 10;
5613 gridfit = 10;
5614 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
5615 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5616 NULL, &mode, &gridfit);
5617 ok(hr == S_OK, "got 0x%08x\n", hr);
5618 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
5619 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
5621 mode = 10;
5622 gridfit = 10;
5623 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
5624 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5625 (IDWriteRenderingParams*)params2, &mode, &gridfit);
5626 ok(hr == S_OK, "got 0x%08x\n", hr);
5627 ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode);
5628 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
5630 IDWriteRenderingParams2_Release(params2);
5631 IDWriteFactory2_Release(factory2);
5634 if (fontface3) {
5635 IDWriteRenderingParams3 *params3;
5636 IDWriteRenderingParams2 *params2;
5637 IDWriteRenderingParams *params;
5638 IDWriteFactory3 *factory3;
5639 DWRITE_GRID_FIT_MODE gridfit;
5640 DWRITE_RENDERING_MODE1 mode1;
5642 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
5643 ok(hr == S_OK, "got 0x%08x\n", hr);
5645 hr = IDWriteFactory3_CreateCustomRenderingParams(factory3, 1.0f, 0.0f, 0.0f, 0.5f, DWRITE_PIXEL_GEOMETRY_FLAT,
5646 DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, DWRITE_GRID_FIT_MODE_ENABLED, &params3);
5647 ok(hr == S_OK, "got 0x%08x\n", hr);
5649 mode1 = IDWriteRenderingParams3_GetRenderingMode1(params3);
5650 ok(mode1 == DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC_DOWNSAMPLED, "got %d\n", mode1);
5652 mode1 = IDWriteRenderingParams3_GetRenderingMode(params3);
5653 ok(mode1 == DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC, "got %d\n", mode1);
5655 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams, (void**)&params);
5656 ok(hr == S_OK, "got 0x%08x\n", hr);
5657 ok(params == (IDWriteRenderingParams*)params3, "got %p, %p\n", params3, params);
5658 mode = IDWriteRenderingParams_GetRenderingMode(params);
5659 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
5660 IDWriteRenderingParams_Release(params);
5662 hr = IDWriteRenderingParams3_QueryInterface(params3, &IID_IDWriteRenderingParams2, (void**)&params2);
5663 ok(hr == S_OK, "got 0x%08x\n", hr);
5664 ok(params2 == (IDWriteRenderingParams2*)params3, "got %p, %p\n", params3, params2);
5665 mode = IDWriteRenderingParams2_GetRenderingMode(params2);
5666 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
5667 IDWriteRenderingParams2_Release(params2);
5669 mode = 10;
5670 gridfit = 10;
5671 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
5672 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5673 NULL, &mode, &gridfit);
5674 ok(hr == S_OK, "got 0x%08x\n", hr);
5675 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
5676 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
5678 mode = 10;
5679 gridfit = 10;
5680 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0f, 96.0f, 96.0f,
5681 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5682 (IDWriteRenderingParams*)params3, &mode, &gridfit);
5683 ok(hr == S_OK, "got 0x%08x\n", hr);
5684 ok(mode == DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC, "got %d\n", mode);
5685 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
5687 IDWriteRenderingParams3_Release(params3);
5688 IDWriteFactory3_Release(factory3);
5691 if (fontface3)
5692 IDWriteFontFace3_Release(fontface3);
5693 if (fontface2)
5694 IDWriteFontFace2_Release(fontface2);
5695 if (fontface1)
5696 IDWriteFontFace1_Release(fontface1);
5697 IDWriteFontFace_Release(fontface);
5698 IDWriteFactory_Release(factory);
5701 static inline BOOL float_eq(FLOAT left, FLOAT right)
5703 int x = *(int *)&left;
5704 int y = *(int *)&right;
5706 if (x < 0)
5707 x = INT_MIN - x;
5708 if (y < 0)
5709 y = INT_MIN - y;
5711 return abs(x - y) <= 8;
5714 static void test_GetAlphaBlendParams(void)
5716 static const DWRITE_RENDERING_MODE rendermodes[] = {
5717 DWRITE_RENDERING_MODE_ALIASED,
5718 DWRITE_RENDERING_MODE_GDI_CLASSIC,
5719 DWRITE_RENDERING_MODE_GDI_NATURAL,
5720 DWRITE_RENDERING_MODE_NATURAL,
5721 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
5724 IDWriteGlyphRunAnalysis *analysis;
5725 FLOAT gamma, contrast, ctlevel;
5726 IDWriteRenderingParams *params;
5727 DWRITE_GLYPH_METRICS metrics;
5728 DWRITE_GLYPH_OFFSET offset;
5729 IDWriteFontFace *fontface;
5730 IDWriteFactory *factory;
5731 DWRITE_GLYPH_RUN run;
5732 FLOAT advance, expected_gdi_gamma;
5733 UINT value = 0;
5734 UINT16 glyph;
5735 UINT32 ch, i;
5736 HRESULT hr;
5737 BOOL ret;
5739 factory = create_factory();
5740 fontface = create_fontface(factory);
5742 ch = 'A';
5743 glyph = 0;
5744 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
5745 ok(hr == S_OK, "got 0x%08x\n", hr);
5746 ok(glyph > 0, "got %u\n", glyph);
5748 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
5749 ok(hr == S_OK, "got 0x%08x\n", hr);
5750 advance = metrics.advanceWidth;
5752 offset.advanceOffset = 0.0;
5753 offset.ascenderOffset = 0.0;
5755 run.fontFace = fontface;
5756 run.fontEmSize = 24.0;
5757 run.glyphCount = 1;
5758 run.glyphIndices = &glyph;
5759 run.glyphAdvances = &advance;
5760 run.glyphOffsets = &offset;
5761 run.isSideways = FALSE;
5762 run.bidiLevel = 0;
5764 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.9, 0.3, 0.1, DWRITE_PIXEL_GEOMETRY_RGB,
5765 DWRITE_RENDERING_MODE_DEFAULT, &params);
5766 ok(hr == S_OK, "got 0x%08x\n", hr);
5768 value = 0;
5769 ret = SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
5770 ok(ret, "got %d\n", ret);
5771 expected_gdi_gamma = (FLOAT)(value / 1000.0);
5773 for (i = 0; i < sizeof(rendermodes)/sizeof(rendermodes[0]); i++) {
5774 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5775 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
5776 0.0, 0.0, &analysis);
5777 ok(hr == S_OK, "got 0x%08x\n", hr);
5779 gamma = contrast = ctlevel = -1.0;
5780 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, NULL, &gamma, &contrast, &ctlevel);
5781 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5782 ok(gamma == -1.0, "got %.2f\n", gamma);
5783 ok(contrast == -1.0, "got %.2f\n", contrast);
5784 ok(ctlevel == -1.0, "got %.2f\n", ctlevel);
5786 gamma = contrast = ctlevel = -1.0;
5787 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &ctlevel);
5788 ok(hr == S_OK, "got 0x%08x\n", hr);
5790 if (rendermodes[i] == DWRITE_RENDERING_MODE_GDI_CLASSIC || rendermodes[i] == DWRITE_RENDERING_MODE_GDI_NATURAL) {
5791 ok(float_eq(gamma, expected_gdi_gamma), "got %.2f, expected %.2f\n", gamma, expected_gdi_gamma);
5792 ok(contrast == 0.0f, "got %.2f\n", contrast);
5793 ok(ctlevel == 1.0f, "got %.2f\n", ctlevel);
5795 else {
5796 ok(gamma == 0.9f, "got %.2f\n", gamma);
5797 ok(contrast == 0.3f, "got %.2f\n", contrast);
5798 ok(ctlevel == 0.1f, "got %.2f\n", ctlevel);
5801 IDWriteGlyphRunAnalysis_Release(analysis);
5804 IDWriteRenderingParams_Release(params);
5805 IDWriteFontFace_Release(fontface);
5806 IDWriteFactory_Release(factory);
5809 static void test_CreateAlphaTexture(void)
5811 IDWriteGlyphRunAnalysis *analysis;
5812 DWRITE_GLYPH_METRICS metrics;
5813 DWRITE_GLYPH_OFFSET offset;
5814 IDWriteFontFace *fontface;
5815 IDWriteFactory *factory;
5816 DWRITE_GLYPH_RUN run;
5817 UINT32 ch, size;
5818 BYTE buff[1024];
5819 RECT bounds, r;
5820 FLOAT advance;
5821 UINT16 glyph;
5822 HRESULT hr;
5824 factory = create_factory();
5825 fontface = create_fontface(factory);
5827 ch = 'A';
5828 glyph = 0;
5829 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
5830 ok(hr == S_OK, "got 0x%08x\n", hr);
5831 ok(glyph > 0, "got %u\n", glyph);
5833 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
5834 ok(hr == S_OK, "got 0x%08x\n", hr);
5835 advance = metrics.advanceWidth;
5837 offset.advanceOffset = 0.0;
5838 offset.ascenderOffset = 0.0;
5840 run.fontFace = fontface;
5841 run.fontEmSize = 24.0;
5842 run.glyphCount = 1;
5843 run.glyphIndices = &glyph;
5844 run.glyphAdvances = &advance;
5845 run.glyphOffsets = &offset;
5846 run.isSideways = FALSE;
5847 run.bidiLevel = 0;
5849 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5850 DWRITE_RENDERING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
5851 0.0, 0.0, &analysis);
5852 ok(hr == S_OK, "got 0x%08x\n", hr);
5854 SetRectEmpty(&bounds);
5855 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
5856 ok(hr == S_OK, "got 0x%08x\n", hr);
5857 ok(!IsRectEmpty(&bounds), "got empty rect\n");
5858 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top)*3;
5859 ok(sizeof(buff) >= size, "required %u\n", size);
5861 /* invalid type value */
5862 memset(buff, 0xcf, sizeof(buff));
5863 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &bounds, buff, sizeof(buff));
5864 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5865 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
5867 memset(buff, 0xcf, sizeof(buff));
5868 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, 2);
5869 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
5870 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
5872 /* vista version allows texture type mismatch, mark it broken for now */
5873 memset(buff, 0xcf, sizeof(buff));
5874 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, sizeof(buff));
5875 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
5876 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
5878 memset(buff, 0xcf, sizeof(buff));
5879 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, size-1);
5880 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
5881 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
5883 IDWriteGlyphRunAnalysis_Release(analysis);
5885 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
5886 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
5887 0.0, 0.0, &analysis);
5888 ok(hr == S_OK, "got 0x%08x\n", hr);
5890 SetRectEmpty(&bounds);
5891 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
5892 ok(hr == S_OK, "got 0x%08x\n", hr);
5893 ok(!IsRectEmpty(&bounds), "got empty rect\n");
5894 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
5895 ok(sizeof(buff) >= size, "required %u\n", size);
5897 memset(buff, 0xcf, sizeof(buff));
5898 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, sizeof(buff));
5899 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5900 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
5902 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, NULL, sizeof(buff));
5903 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5905 memset(buff, 0xcf, sizeof(buff));
5906 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, 0);
5907 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5908 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
5910 /* buffer size is not enough */
5911 memset(buff, 0xcf, sizeof(buff));
5912 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, size-1);
5913 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
5914 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
5916 /* request texture for rectangle that doesn't intersect */
5917 memset(buff, 0xcf, sizeof(buff));
5918 r = bounds;
5919 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
5920 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
5921 ok(hr == S_OK, "got 0x%08x\n", hr);
5922 ok(buff[0] == 0, "got %1x\n", buff[0]);
5924 memset(buff, 0xcf, sizeof(buff));
5925 r = bounds;
5926 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
5927 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
5928 ok(hr == S_OK, "got 0x%08x\n", hr);
5929 ok(buff[0] == 0, "got %1x\n", buff[0]);
5931 /* request texture for rectangle that doesn't intersect, small buffer */
5932 memset(buff, 0xcf, sizeof(buff));
5933 r = bounds;
5934 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
5935 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, size-1);
5936 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
5937 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
5939 /* vista version allows texture type mismatch, mark it broken for now */
5940 memset(buff, 0xcf, sizeof(buff));
5941 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, sizeof(buff));
5942 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
5943 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
5945 IDWriteGlyphRunAnalysis_Release(analysis);
5946 IDWriteFontFace_Release(fontface);
5947 IDWriteFactory_Release(factory);
5950 static void test_IsSymbolFont(void)
5952 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
5953 IDWriteFontCollection *collection;
5954 IDWriteFontFace *fontface;
5955 IDWriteFactory *factory;
5956 IDWriteFont *font;
5957 HRESULT hr;
5958 BOOL ret;
5960 factory = create_factory();
5962 /* Tahoma */
5963 fontface = create_fontface(factory);
5964 ret = IDWriteFontFace_IsSymbolFont(fontface);
5965 ok(!ret, "got %d\n", ret);
5967 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
5968 ok(hr == S_OK, "got 0x%08x\n", hr);
5970 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font);
5971 ok(hr == S_OK, "got 0x%08x\n", hr);
5973 ret = IDWriteFont_IsSymbolFont(font);
5974 ok(!ret, "got %d\n", ret);
5976 IDWriteFontCollection_Release(collection);
5977 IDWriteFont_Release(font);
5978 IDWriteFontFace_Release(fontface);
5980 /* Symbol */
5981 font = get_font(factory, symbolW, DWRITE_FONT_STYLE_NORMAL);
5982 ret = IDWriteFont_IsSymbolFont(font);
5983 ok(ret, "got %d\n", ret);
5985 hr = IDWriteFont_CreateFontFace(font, &fontface);
5986 ok(hr == S_OK, "got 0x%08x\n", hr);
5987 ret = IDWriteFontFace_IsSymbolFont(fontface);
5988 ok(ret, "got %d\n", ret);
5989 IDWriteFont_Release(font);
5991 IDWriteFactory_Release(factory);
5994 struct CPAL_Header_0
5996 USHORT version;
5997 USHORT numPaletteEntries;
5998 USHORT numPalette;
5999 USHORT numColorRecords;
6000 ULONG offsetFirstColorRecord;
6001 USHORT colorRecordIndices[1];
6004 static void test_GetPaletteEntries(void)
6006 IDWriteFontFace2 *fontface2;
6007 IDWriteFontFace *fontface;
6008 IDWriteFactory *factory;
6009 IDWriteFont *font;
6010 DWRITE_COLOR_F color;
6011 UINT32 palettecount, entrycount, size, colorrecords;
6012 void *ctxt;
6013 const struct CPAL_Header_0 *cpal_header;
6014 HRESULT hr;
6015 BOOL exists;
6017 factory = create_factory();
6019 /* Tahoma, no color support */
6020 fontface = create_fontface(factory);
6021 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6022 IDWriteFontFace_Release(fontface);
6023 if (hr != S_OK) {
6024 IDWriteFactory_Release(factory);
6025 win_skip("GetPaletteEntries() is not supported.\n");
6026 return;
6029 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 1, &color);
6030 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6031 IDWriteFontFace2_Release(fontface2);
6033 /* Segoe UI Emoji, with color support */
6034 font = get_font(factory, emojiW, DWRITE_FONT_STYLE_NORMAL);
6035 if (!font) {
6036 IDWriteFactory_Release(factory);
6037 skip("Segoe UI Emoji font not found.\n");
6038 return;
6041 hr = IDWriteFont_CreateFontFace(font, &fontface);
6042 ok(hr == S_OK, "got 0x%08x\n", hr);
6043 IDWriteFont_Release(font);
6045 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6046 ok(hr == S_OK, "got 0x%08x\n", hr);
6047 IDWriteFontFace_Release(fontface);
6049 palettecount = IDWriteFontFace2_GetColorPaletteCount(fontface2);
6050 ok(palettecount >= 1, "got %u\n", palettecount);
6052 entrycount = IDWriteFontFace2_GetPaletteEntryCount(fontface2);
6053 ok(entrycount >= 1, "got %u\n", entrycount);
6055 exists = FALSE;
6056 hr = IDWriteFontFace2_TryGetFontTable(fontface2, MS_CPAL_TAG, (const void**)&cpal_header, &size, &ctxt, &exists);
6057 ok(hr == S_OK, "got 0x%08x\n", hr);
6058 ok(exists, "got %d\n", exists);
6059 colorrecords = GET_BE_WORD(cpal_header->numColorRecords);
6060 ok(colorrecords >= 1, "got %u\n", colorrecords);
6062 /* invalid palette index */
6063 color.r = color.g = color.b = color.a = 123.0;
6064 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, palettecount, 0, 1, &color);
6065 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6066 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6067 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6069 /* invalid entry index */
6070 color.r = color.g = color.b = color.a = 123.0;
6071 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount, 1, &color);
6072 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6073 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6074 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6076 color.r = color.g = color.b = color.a = 123.0;
6077 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount - 1, 1, &color);
6078 ok(hr == S_OK, "got 0x%08x\n", hr);
6079 ok(color.r != 123.0 && color.g != 123.0 && color.b != 123.0 && color.a != 123.0,
6080 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6082 /* zero return length */
6083 color.r = color.g = color.b = color.a = 123.0;
6084 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 0, &color);
6085 ok(hr == S_OK, "got 0x%08x\n", hr);
6086 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
6087 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
6089 IDWriteFontFace2_Release(fontface2);
6090 IDWriteFactory_Release(factory);
6093 static void test_TranslateColorGlyphRun(void)
6095 IDWriteColorGlyphRunEnumerator *layers;
6096 const DWRITE_COLOR_GLYPH_RUN *colorrun;
6097 IDWriteFontFace2 *fontface2;
6098 IDWriteFontFace *fontface;
6099 IDWriteFactory2 *factory2;
6100 IDWriteFactory *factory;
6101 DWRITE_GLYPH_RUN run;
6102 UINT32 codepoints[2];
6103 IDWriteFont *font;
6104 UINT16 glyphs[2];
6105 BOOL hasrun;
6106 HRESULT hr;
6108 factory = create_factory();
6110 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
6111 IDWriteFactory_Release(factory);
6112 if (hr != S_OK) {
6113 win_skip("TranslateColorGlyphRun() is not supported.\n");
6114 return;
6117 /* Tahoma, no color support */
6118 fontface = create_fontface((IDWriteFactory*)factory2);
6120 codepoints[0] = 'A';
6121 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6122 ok(hr == S_OK, "got 0x%08x\n", hr);
6124 run.fontFace = fontface;
6125 run.fontEmSize = 20.0f;
6126 run.glyphCount = 1;
6127 run.glyphIndices = glyphs;
6128 run.glyphAdvances = NULL;
6129 run.glyphOffsets = NULL;
6130 run.isSideways = FALSE;
6131 run.bidiLevel = 0;
6133 layers = (void*)0xdeadbeef;
6134 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
6135 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6136 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6137 ok(layers == NULL, "got %p\n", layers);
6138 IDWriteFontFace_Release(fontface);
6140 /* Segoe UI Emoji, with color support */
6141 font = get_font((IDWriteFactory*)factory2, emojiW, DWRITE_FONT_STYLE_NORMAL);
6142 if (!font) {
6143 IDWriteFactory2_Release(factory2);
6144 skip("Segoe UI Emoji font not found.\n");
6145 return;
6148 hr = IDWriteFont_CreateFontFace(font, &fontface);
6149 ok(hr == S_OK, "got 0x%08x\n", hr);
6150 IDWriteFont_Release(font);
6152 codepoints[0] = 0x26c4;
6153 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6154 ok(hr == S_OK, "got 0x%08x\n", hr);
6156 run.fontFace = fontface;
6158 layers = NULL;
6159 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
6160 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6161 ok(hr == S_OK, "got 0x%08x\n", hr);
6162 ok(layers != NULL, "got %p\n", layers);
6164 while (1) {
6165 hasrun = FALSE;
6166 hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &hasrun);
6167 ok(hr == S_OK, "got 0x%08x\n", hr);
6169 if (!hasrun)
6170 break;
6172 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
6173 ok(hr == S_OK, "got 0x%08x\n", hr);
6174 ok(colorrun->glyphRun.fontFace != NULL, "got fontface %p\n", colorrun->glyphRun.fontFace);
6175 ok(colorrun->glyphRun.fontEmSize == 20.0f, "got wrong font size %f\n", colorrun->glyphRun.fontEmSize);
6176 ok(colorrun->glyphRun.glyphCount > 0, "got wrong glyph count %u\n", colorrun->glyphRun.glyphCount);
6177 ok(colorrun->glyphRun.glyphIndices != NULL, "got null glyph indices %p\n", colorrun->glyphRun.glyphIndices);
6178 ok(colorrun->glyphRun.glyphAdvances != NULL, "got null glyph advances %p\n", colorrun->glyphRun.glyphAdvances);
6181 /* iterated all way through */
6182 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
6183 ok(hr == E_NOT_VALID_STATE, "got 0x%08x\n", hr);
6185 IDWriteColorGlyphRunEnumerator_Release(layers);
6187 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
6188 ok(hr == S_OK, "got 0x%08x\n", hr);
6190 /* invalid palette index */
6191 layers = (void*)0xdeadbeef;
6192 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0f, 0.0f, &run, NULL,
6193 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2),
6194 &layers);
6195 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6196 ok(layers == NULL, "got %p\n", layers);
6198 layers = NULL;
6199 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0f, 0.0f, &run, NULL,
6200 DWRITE_MEASURING_MODE_NATURAL, NULL, IDWriteFontFace2_GetColorPaletteCount(fontface2) - 1,
6201 &layers);
6202 ok(hr == S_OK, "got 0x%08x\n", hr);
6203 IDWriteColorGlyphRunEnumerator_Release(layers);
6205 /* color font, glyph without color info */
6206 codepoints[0] = 'A';
6207 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
6208 ok(hr == S_OK, "got 0x%08x\n", hr);
6210 layers = (void*)0xdeadbeef;
6211 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
6212 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6213 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
6214 ok(layers == NULL, "got %p\n", layers);
6216 /* one glyph with, one without */
6217 codepoints[0] = 'A';
6218 codepoints[1] = 0x26c4;
6220 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 2, glyphs);
6221 ok(hr == S_OK, "got 0x%08x\n", hr);
6223 run.glyphCount = 2;
6225 layers = NULL;
6226 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
6227 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
6228 ok(hr == S_OK, "got 0x%08x\n", hr);
6229 ok(layers != NULL, "got %p\n", layers);
6230 IDWriteColorGlyphRunEnumerator_Release(layers);
6232 IDWriteFontFace2_Release(fontface2);
6233 IDWriteFontFace_Release(fontface);
6234 IDWriteFactory2_Release(factory2);
6237 static void test_HasCharacter(void)
6239 IDWriteFactory3 *factory3;
6240 IDWriteFactory *factory;
6241 IDWriteFont3 *font3;
6242 IDWriteFont *font;
6243 HRESULT hr;
6244 BOOL ret;
6246 factory = create_factory();
6248 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
6249 ok(font != NULL, "failed to create font\n");
6251 /* Win8 is broken, QI claims to support IDWriteFont3, but in fact it does not */
6252 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
6253 if (hr == S_OK) {
6254 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
6255 ok(hr == S_OK, "got 0x%08x\n", hr);
6257 ret = IDWriteFont3_HasCharacter(font3, 'A');
6258 ok(ret, "got %d\n", ret);
6260 IDWriteFont3_Release(font3);
6261 IDWriteFactory3_Release(factory3);
6263 else
6264 win_skip("IDWriteFont3 is not supported.\n");
6266 IDWriteFont_Release(font);
6267 IDWriteFactory_Release(factory);
6270 static void test_CreateFontFaceReference(void)
6272 static const WCHAR dummyW[] = {'d','u','m','m','y',0};
6273 IDWriteFontFace3 *fontface, *fontface1;
6274 IDWriteFontFaceReference *ref, *ref1;
6275 IDWriteFontFile *file, *file1;
6276 IDWriteFactory3 *factory3;
6277 IDWriteFactory *factory;
6278 IDWriteFont3 *font3;
6279 IDWriteFont *font;
6280 UINT32 index;
6281 WCHAR *path;
6282 HRESULT hr;
6283 BOOL ret;
6285 factory = create_factory();
6287 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory3, (void**)&factory3);
6288 IDWriteFactory_Release(factory);
6289 if (FAILED(hr)) {
6290 win_skip("CreateFontFaceReference() is not supported.\n");
6291 return;
6294 path = create_testfontfile(test_fontfile);
6296 hr = IDWriteFactory3_CreateFontFaceReference(factory3, NULL, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6297 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6299 /* out of range simulation flags */
6300 hr = IDWriteFactory3_CreateFontFaceReference(factory3, path, NULL, 0, ~0u, &ref);
6301 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6303 /* test file is not a collection, but reference could still be created with non-zero face index */
6304 hr = IDWriteFactory3_CreateFontFaceReference(factory3, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6305 ok(hr == S_OK, "got 0x%08x\n", hr);
6307 index = IDWriteFontFaceReference_GetFontFaceIndex(ref);
6308 ok(index == 1, "got %u\n", index);
6310 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
6311 ok(hr == S_OK, "got 0x%08x\n", hr);
6312 IDWriteFontFile_Release(file);
6314 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
6315 todo_wine
6316 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
6318 IDWriteFontFaceReference_Release(ref);
6320 /* path however has to be valid */
6321 hr = IDWriteFactory3_CreateFontFaceReference(factory3, dummyW, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6322 todo_wine
6323 ok(hr == DWRITE_E_FILENOTFOUND, "got 0x%08x\n", hr);
6324 if (hr == S_OK)
6325 IDWriteFontFaceReference_Release(ref);
6327 EXPECT_REF(factory3, 1);
6328 hr = IDWriteFactory3_CreateFontFaceReference(factory3, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6329 ok(hr == S_OK, "got 0x%08x\n", hr);
6330 EXPECT_REF(factory3, 2);
6332 /* new file is returned */
6333 hr = IDWriteFontFaceReference_GetFontFile(ref, &file);
6334 ok(hr == S_OK, "got 0x%08x\n", hr);
6336 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
6337 ok(hr == S_OK, "got 0x%08x\n", hr);
6338 ok(file != file1, "got %p, previous file %p\n", file1, file);
6340 IDWriteFontFile_Release(file);
6341 IDWriteFontFile_Release(file1);
6343 /* references are not reused */
6344 hr = IDWriteFactory3_CreateFontFaceReference(factory3, path, NULL, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
6345 ok(hr == S_OK, "got 0x%08x\n", hr);
6346 ok(ref1 != ref, "got %p, previous ref %p\n", ref1, ref);
6348 /* created fontfaces are cached */
6349 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface);
6350 ok(hr == S_OK, "got 0x%08x\n", hr);
6352 hr = IDWriteFontFaceReference_CreateFontFace(ref1, &fontface1);
6353 ok(hr == S_OK, "got 0x%08x\n", hr);
6354 ok(fontface == fontface1, "got %p, expected %p\n", fontface1, fontface);
6355 IDWriteFontFace3_Release(fontface);
6356 IDWriteFontFace3_Release(fontface1);
6358 /* reference equality */
6359 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6360 ok(ret, "got %d\n", ret);
6361 IDWriteFontFaceReference_Release(ref1);
6363 hr = IDWriteFactory3_CreateFontFaceReference(factory3, path, NULL, 1, DWRITE_FONT_SIMULATIONS_NONE, &ref1);
6364 ok(hr == S_OK, "got 0x%08x\n", hr);
6365 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6366 ok(!ret, "got %d\n", ret);
6367 IDWriteFontFaceReference_Release(ref1);
6369 hr = IDWriteFactory3_CreateFontFaceReference(factory3, path, NULL, 0, DWRITE_FONT_SIMULATIONS_BOLD, &ref1);
6370 ok(hr == S_OK, "got 0x%08x\n", hr);
6371 ret = IDWriteFontFaceReference_Equals(ref, ref1);
6372 ok(!ret, "got %d\n", ret);
6373 IDWriteFontFaceReference_Release(ref1);
6375 IDWriteFontFaceReference_Release(ref);
6377 /* create reference from a file */
6378 hr = IDWriteFactory3_CreateFontFileReference(factory3, path, NULL, &file);
6379 ok(hr == S_OK, "got 0x%08x\n", hr);
6381 hr = IDWriteFactory3_CreateFontFaceReference_(factory3, file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ref);
6382 ok(hr == S_OK, "got 0x%08x\n", hr);
6384 hr = IDWriteFontFaceReference_GetFontFile(ref, &file1);
6385 ok(hr == S_OK, "got 0x%08x\n", hr);
6386 ok(file != file1, "got %p, previous file %p\n", file1, file);
6388 IDWriteFontFaceReference_Release(ref);
6389 IDWriteFontFile_Release(file);
6390 IDWriteFontFile_Release(file1);
6392 /* references returned from IDWriteFont3 */
6393 font = get_tahoma_instance((IDWriteFactory*)factory3, DWRITE_FONT_STYLE_NORMAL);
6394 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont3, (void**)&font3);
6395 ok(hr == S_OK, "got 0x%08x\n", hr);
6396 IDWriteFont_Release(font);
6398 hr = IDWriteFont3_GetFontFaceReference(font3, &ref);
6399 ok(hr == S_OK, "got 0x%08x\n", hr);
6401 hr = IDWriteFont3_GetFontFaceReference(font3, &ref1);
6402 ok(hr == S_OK, "got 0x%08x\n", hr);
6403 ok(ref != ref1, "got %p, %p\n", ref1, ref);
6405 IDWriteFontFaceReference_Release(ref);
6406 IDWriteFontFaceReference_Release(ref1);
6408 /* references returned from IDWriteFontFace3 */
6409 hr = IDWriteFont3_CreateFontFace(font3, &fontface);
6410 ok(hr == S_OK, "got 0x%08x\n", hr);
6412 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref);
6413 todo_wine
6414 ok(hr == S_OK, "got 0x%08x\n", hr);
6416 hr = IDWriteFontFace3_GetFontFaceReference(fontface, &ref1);
6417 todo_wine
6418 ok(hr == S_OK, "got 0x%08x\n", hr);
6419 if (hr == S_OK)
6420 ok(ref == ref1, "got %p, %p\n", ref1, ref);
6422 if (hr == S_OK) {
6423 hr = IDWriteFontFaceReference_CreateFontFace(ref, &fontface1);
6424 ok(hr == S_OK, "got 0x%08x\n", hr);
6425 ok(fontface1 == fontface, "got %p, %p\n", fontface1, fontface);
6426 IDWriteFontFace3_Release(fontface1);
6428 IDWriteFontFaceReference_Release(ref);
6429 IDWriteFontFaceReference_Release(ref1);
6431 IDWriteFontFace3_Release(fontface);
6432 IDWriteFont3_Release(font3);
6434 IDWriteFactory3_Release(factory3);
6435 DELETE_FONTFILE(path);
6438 static void get_expected_fontsig(IDWriteFont *font, FONTSIGNATURE *fontsig)
6440 void *os2_context;
6441 IDWriteFontFace *fontface;
6442 const TT_OS2_V2 *tt_os2;
6443 UINT32 size;
6444 BOOL exists;
6445 HRESULT hr;
6447 memset(fontsig, 0, sizeof(*fontsig));
6449 hr = IDWriteFont_CreateFontFace(font, &fontface);
6450 ok(hr == S_OK, "got 0x%08x\n", hr);
6452 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_0S2_TAG, (const void**)&tt_os2, &size, &os2_context, &exists);
6453 ok(hr == S_OK, "got 0x%08x\n", hr);
6455 if (tt_os2) {
6456 fontsig->fsUsb[0] = GET_BE_DWORD(tt_os2->ulUnicodeRange1);
6457 fontsig->fsUsb[1] = GET_BE_DWORD(tt_os2->ulUnicodeRange2);
6458 fontsig->fsUsb[2] = GET_BE_DWORD(tt_os2->ulUnicodeRange3);
6459 fontsig->fsUsb[3] = GET_BE_DWORD(tt_os2->ulUnicodeRange4);
6461 if (GET_BE_WORD(tt_os2->version) == 0) {
6462 fontsig->fsCsb[0] = 0;
6463 fontsig->fsCsb[1] = 0;
6465 else {
6466 fontsig->fsCsb[0] = GET_BE_DWORD(tt_os2->ulCodePageRange1);
6467 fontsig->fsCsb[1] = GET_BE_DWORD(tt_os2->ulCodePageRange2);
6470 IDWriteFontFace_ReleaseFontTable(fontface, os2_context);
6473 IDWriteFontFace_Release(fontface);
6476 static void test_GetFontSignature(void)
6478 IDWriteFontCollection *syscollection;
6479 IDWriteGdiInterop1 *interop1;
6480 IDWriteGdiInterop *interop;
6481 IDWriteFactory *factory;
6482 FONTSIGNATURE fontsig;
6483 UINT count, i;
6484 HRESULT hr;
6486 factory = create_factory();
6488 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
6489 ok(hr == S_OK, "got 0x%08x\n", hr);
6491 hr = IDWriteGdiInterop_QueryInterface(interop, &IID_IDWriteGdiInterop1, (void**)&interop1);
6492 IDWriteGdiInterop_Release(interop);
6493 if (FAILED(hr)) {
6494 win_skip("GetFontSignature() is not supported.\n");
6495 IDWriteGdiInterop_Release(interop);
6496 IDWriteFactory_Release(factory);
6497 return;
6499 ok(hr == S_OK, "got 0x%08x\n", hr);
6501 hr = IDWriteGdiInterop1_GetFontSignature(interop1, NULL, &fontsig);
6502 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
6504 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
6505 ok(hr == S_OK, "got 0x%08x\n", hr);
6506 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
6508 for (i = 0; i < count; i++) {
6509 FONTSIGNATURE expected_signature;
6510 IDWriteLocalizedStrings *names;
6511 IDWriteFontFamily *family;
6512 IDWriteFont *font;
6513 WCHAR nameW[256];
6515 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
6516 ok(hr == S_OK, "got 0x%08x\n", hr);
6518 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
6519 DWRITE_FONT_STYLE_NORMAL, &font);
6520 ok(hr == S_OK, "got 0x%08x\n", hr);
6522 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
6523 ok(hr == S_OK, "got 0x%08x\n", hr);
6525 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
6527 IDWriteLocalizedStrings_Release(names);
6529 hr = IDWriteGdiInterop1_GetFontSignature(interop1, font, &fontsig);
6530 ok(hr == S_OK, "got 0x%08x\n", hr);
6532 get_expected_fontsig(font, &expected_signature);
6534 ok(fontsig.fsUsb[0] == expected_signature.fsUsb[0], "%s: fsUsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
6535 fontsig.fsUsb[0], expected_signature.fsUsb[0]);
6536 ok(fontsig.fsUsb[1] == expected_signature.fsUsb[1], "%s: fsUsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
6537 fontsig.fsUsb[1], expected_signature.fsUsb[1]);
6538 ok(fontsig.fsUsb[2] == expected_signature.fsUsb[2], "%s: fsUsb[2] %#x, expected %#x\n", wine_dbgstr_w(nameW),
6539 fontsig.fsUsb[2], expected_signature.fsUsb[2]);
6540 ok(fontsig.fsUsb[3] == expected_signature.fsUsb[3], "%s: fsUsb[3] %#x, expected %#x\n", wine_dbgstr_w(nameW),
6541 fontsig.fsUsb[3], expected_signature.fsUsb[3]);
6543 ok(fontsig.fsCsb[0] == expected_signature.fsCsb[0], "%s: fsCsb[0] %#x, expected %#x\n", wine_dbgstr_w(nameW),
6544 fontsig.fsCsb[0], expected_signature.fsCsb[0]);
6545 ok(fontsig.fsCsb[1] == expected_signature.fsCsb[1], "%s: fsCsb[1] %#x, expected %#x\n", wine_dbgstr_w(nameW),
6546 fontsig.fsCsb[1], expected_signature.fsCsb[1]);
6548 IDWriteFont_Release(font);
6549 IDWriteFontFamily_Release(family);
6552 IDWriteGdiInterop1_Release(interop1);
6553 IDWriteFontCollection_Release(syscollection);
6554 IDWriteFactory_Release(factory);
6557 static void test_font_properties(void)
6559 IDWriteFontFace3 *fontface3;
6560 IDWriteFontFace *fontface;
6561 IDWriteFactory *factory;
6562 DWRITE_FONT_STYLE style;
6563 IDWriteFont *font;
6564 HRESULT hr;
6566 factory = create_factory();
6568 /* this creates simulated font */
6569 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
6571 style = IDWriteFont_GetStyle(font);
6572 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
6574 hr = IDWriteFont_CreateFontFace(font, &fontface);
6575 ok(hr == S_OK, "got 0x%08x\n", hr);
6577 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace3, (void**)&fontface3);
6578 IDWriteFontFace_Release(fontface);
6579 if (hr == S_OK) {
6580 style = IDWriteFontFace3_GetStyle(fontface3);
6581 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %u\n", style);
6583 IDWriteFontFace3_Release(fontface3);
6586 IDWriteFont_Release(font);
6587 IDWriteFactory_Release(factory);
6590 static BOOL has_vertical_glyph_variants(IDWriteFontFace1 *fontface)
6592 const OT_FeatureList *featurelist;
6593 const OT_LookupList *lookup_list;
6594 BOOL exists = FALSE, ret = FALSE;
6595 const GSUB_Header *header;
6596 const void *data;
6597 void *context;
6598 UINT32 size;
6599 HRESULT hr;
6600 UINT16 i;
6602 hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_GSUB_TAG, &data, &size, &context, &exists);
6603 ok(hr == S_OK, "got 0x%08x\n", hr);
6605 if (!exists)
6606 return FALSE;
6608 header = data;
6609 featurelist = (OT_FeatureList*)((BYTE*)header + GET_BE_WORD(header->FeatureList));
6610 lookup_list = (const OT_LookupList*)((BYTE*)header + GET_BE_WORD(header->LookupList));
6612 for (i = 0; i < GET_BE_WORD(featurelist->FeatureCount); i++) {
6613 if (*(UINT32*)featurelist->FeatureRecord[i].FeatureTag == DWRITE_FONT_FEATURE_TAG_VERTICAL_WRITING) {
6614 const OT_Feature *feature = (const OT_Feature*)((BYTE*)featurelist + GET_BE_WORD(featurelist->FeatureRecord[i].Feature));
6615 UINT16 lookup_count = GET_BE_WORD(feature->LookupCount), i, index, count, type;
6616 const GSUB_SingleSubstFormat2 *subst2;
6617 const OT_LookupTable *lookup_table;
6618 UINT32 offset;
6620 if (lookup_count == 0)
6621 continue;
6623 for (i = 0; i < lookup_count; i++) {
6624 /* check if lookup is empty */
6625 index = GET_BE_WORD(feature->LookupListIndex[i]);
6626 lookup_table = (const OT_LookupTable*)((BYTE*)lookup_list + GET_BE_WORD(lookup_list->Lookup[index]));
6628 type = GET_BE_WORD(lookup_table->LookupType);
6629 ok(type == 1 || type == 7, "got unexpected lookup type %u\n", type);
6631 count = GET_BE_WORD(lookup_table->SubTableCount);
6632 if (count == 0)
6633 continue;
6635 ok(count > 0, "got unexpected subtable count %u\n", count);
6637 offset = GET_BE_WORD(lookup_table->SubTable[0]);
6638 if (type == 7) {
6639 const GSUB_ExtensionPosFormat1 *ext = (const GSUB_ExtensionPosFormat1 *)((const BYTE *)lookup_table + offset);
6640 if (GET_BE_WORD(ext->SubstFormat) == 1)
6641 offset += GET_BE_DWORD(ext->ExtensionOffset);
6642 else
6643 ok(0, "Unhandled Extension Substitution Format %u\n", GET_BE_WORD(ext->SubstFormat));
6646 subst2 = (const GSUB_SingleSubstFormat2*)((BYTE*)lookup_table + offset);
6647 index = GET_BE_WORD(subst2->SubstFormat);
6648 if (index == 1)
6649 ok(0, "validate Single Substitution Format 1\n");
6650 else if (index == 2) {
6651 /* SimSun-ExtB has 0 glyph count for this substitution */
6652 if (GET_BE_WORD(subst2->GlyphCount) > 0) {
6653 ret = TRUE;
6654 break;
6657 else
6658 ok(0, "unknown Single Substitution Format, %u\n", index);
6663 IDWriteFontFace1_ReleaseFontTable(fontface, context);
6665 return ret;
6668 static void test_HasVerticalGlyphVariants(void)
6670 IDWriteFontCollection *syscollection;
6671 IDWriteFontFace1 *fontface1;
6672 IDWriteFontFace *fontface;
6673 IDWriteFactory *factory;
6674 UINT32 count, i;
6675 HRESULT hr;
6677 factory = create_factory();
6678 fontface = create_fontface(factory);
6680 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
6681 IDWriteFontFace_Release(fontface);
6682 if (hr != S_OK) {
6683 win_skip("HasVerticalGlyphVariants() is not supported.\n");
6684 IDWriteFactory_Release(factory);
6685 return;
6687 IDWriteFontFace1_Release(fontface1);
6689 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
6690 ok(hr == S_OK, "got 0x%08x\n", hr);
6691 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
6693 for (i = 0; i < count; i++) {
6694 IDWriteLocalizedStrings *names;
6695 BOOL expected_vert, has_vert;
6696 IDWriteFontFamily *family;
6697 IDWriteFont *font;
6698 WCHAR nameW[256];
6700 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
6701 ok(hr == S_OK, "got 0x%08x\n", hr);
6703 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
6704 DWRITE_FONT_STYLE_NORMAL, &font);
6705 ok(hr == S_OK, "got 0x%08x\n", hr);
6707 hr = IDWriteFont_CreateFontFace(font, &fontface);
6708 ok(hr == S_OK, "got 0x%08x\n", hr);
6710 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
6711 ok(hr == S_OK, "got 0x%08x\n", hr);
6713 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
6714 ok(hr == S_OK, "got 0x%08x\n", hr);
6716 get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0]));
6718 expected_vert = has_vertical_glyph_variants(fontface1);
6719 has_vert = IDWriteFontFace1_HasVerticalGlyphVariants(fontface1);
6721 ok(expected_vert == has_vert, "%s: expected vertical feature %d, got %d\n",
6722 wine_dbgstr_w(nameW), expected_vert, has_vert);
6724 IDWriteLocalizedStrings_Release(names);
6725 IDWriteFont_Release(font);
6727 IDWriteFontFace1_Release(fontface1);
6728 IDWriteFontFace_Release(fontface);
6729 IDWriteFontFamily_Release(family);
6732 IDWriteFontCollection_Release(syscollection);
6733 IDWriteFactory_Release(factory);
6736 START_TEST(font)
6738 IDWriteFactory *factory;
6740 if (!(factory = create_factory())) {
6741 win_skip("failed to create factory\n");
6742 return;
6745 test_CreateFontFromLOGFONT();
6746 test_CreateBitmapRenderTarget();
6747 test_GetFontFamily();
6748 test_GetFamilyNames();
6749 test_CreateFontFace();
6750 test_GetMetrics();
6751 test_system_fontcollection();
6752 test_ConvertFontFaceToLOGFONT();
6753 test_CustomFontCollection();
6754 test_CreateCustomFontFileReference();
6755 test_CreateFontFileReference();
6756 test_shared_isolated();
6757 test_GetUnicodeRanges();
6758 test_GetFontFromFontFace();
6759 test_GetFirstMatchingFont();
6760 test_GetMatchingFonts();
6761 test_GetInformationalStrings();
6762 test_GetGdiInterop();
6763 test_CreateFontFaceFromHdc();
6764 test_GetSimulations();
6765 test_GetFaceNames();
6766 test_TryGetFontTable();
6767 test_ConvertFontToLOGFONT();
6768 test_CreateStreamFromKey();
6769 test_ReadFileFragment();
6770 test_GetDesignGlyphMetrics();
6771 test_GetDesignGlyphAdvances();
6772 test_IsMonospacedFont();
6773 test_GetGlyphRunOutline();
6774 test_GetEudcFontCollection();
6775 test_GetCaretMetrics();
6776 test_GetGlyphCount();
6777 test_GetKerningPairAdjustments();
6778 test_CreateRenderingParams();
6779 test_CreateGlyphRunAnalysis();
6780 test_GetGdiCompatibleMetrics();
6781 test_GetPanose();
6782 test_GetGdiCompatibleGlyphAdvances();
6783 test_GetRecommendedRenderingMode();
6784 test_GetAlphaBlendParams();
6785 test_CreateAlphaTexture();
6786 test_IsSymbolFont();
6787 test_GetPaletteEntries();
6788 test_TranslateColorGlyphRun();
6789 test_HasCharacter();
6790 test_CreateFontFaceReference();
6791 test_GetFontSignature();
6792 test_font_properties();
6793 test_HasVerticalGlyphVariants();
6795 IDWriteFactory_Release(factory);