TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / dwrite / tests / font.c
blob681f010ec5df2dd990f081bc09ff3d11b75b8c5d
1 /*
2 * Font related tests
4 * Copyright 2012, 2014 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_2.h"
30 #include "initguid.h"
31 #include "d2d1.h"
33 #include "wine/test.h"
35 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
36 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
37 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
39 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
40 #define MS_VDMX_TAG MS_MAKE_TAG('V','D','M','X')
41 #define MS_GASP_TAG MS_MAKE_TAG('g','a','s','p')
42 #define MS_CPAL_TAG MS_MAKE_TAG('C','P','A','L')
44 #define EXPECT_HR(hr,hr_exp) \
45 ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
47 #define DEFINE_EXPECT(func) \
48 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
50 #define SET_EXPECT(func) \
51 do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
53 #define CHECK_EXPECT2(func) \
54 do { \
55 ok(expect_ ##func, "unexpected call " #func "\n"); \
56 called_ ## func = TRUE; \
57 }while(0)
59 #define CHECK_EXPECT(func) \
60 do { \
61 CHECK_EXPECT2(func); \
62 expect_ ## func = FALSE; \
63 }while(0)
65 #define CHECK_CALLED(func) \
66 do { \
67 ok(called_ ## func, "expected " #func "\n"); \
68 expect_ ## func = called_ ## func = FALSE; \
69 }while(0)
71 #define CLEAR_CALLED(func) \
72 expect_ ## func = called_ ## func = FALSE
74 DEFINE_EXPECT(setfillmode);
76 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
77 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
79 ULONG rc;
80 IUnknown_AddRef(obj);
81 rc = IUnknown_Release(obj);
82 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
85 static inline void *heap_alloc(size_t len)
87 return HeapAlloc(GetProcessHeap(), 0, len);
90 static inline BOOL heap_free(void *mem)
92 return HeapFree(GetProcessHeap(), 0, mem);
95 static const WCHAR test_fontfile[] = {'w','i','n','e','_','t','e','s','t','_','f','o','n','t','.','t','t','f',0};
96 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
97 static const WCHAR arialW[] = {'A','r','i','a','l',0};
98 static const WCHAR tahomaUppercaseW[] = {'T','A','H','O','M','A',0};
99 static const WCHAR tahomaStrangecaseW[] = {'t','A','h','O','m','A',0};
100 static const WCHAR blahW[] = {'B','l','a','h','!',0};
101 static const WCHAR emojiW[] = {'S','e','g','o','e',' ','U','I',' ','E','m','o','j','i',0};
103 static IDWriteFactory *create_factory(void)
105 IDWriteFactory *factory;
106 HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
107 ok(hr == S_OK, "got 0x%08x\n", hr);
108 return factory;
111 static IDWriteFontFace *create_fontface(IDWriteFactory *factory)
113 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
114 IDWriteGdiInterop *interop;
115 IDWriteFontFace *fontface;
116 IDWriteFont *font;
117 LOGFONTW logfont;
118 HRESULT hr;
120 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
121 ok(hr == S_OK, "got 0x%08x\n", hr);
123 memset(&logfont, 0, sizeof(logfont));
124 logfont.lfHeight = 12;
125 logfont.lfWidth = 12;
126 logfont.lfWeight = FW_NORMAL;
127 logfont.lfItalic = 1;
128 lstrcpyW(logfont.lfFaceName, tahomaW);
130 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
131 ok(hr == S_OK, "got 0x%08x\n", hr);
133 hr = IDWriteFont_CreateFontFace(font, &fontface);
134 ok(hr == S_OK, "got 0x%08x\n", hr);
136 IDWriteFont_Release(font);
137 IDWriteGdiInterop_Release(interop);
139 return fontface;
142 static WCHAR *create_testfontfile(const WCHAR *filename)
144 static WCHAR pathW[MAX_PATH];
145 DWORD written;
146 HANDLE file;
147 HRSRC res;
148 void *ptr;
150 GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW);
151 lstrcatW(pathW, filename);
153 file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
154 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", wine_dbgstr_w(pathW),
155 GetLastError());
157 res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
158 ok( res != 0, "couldn't find resource\n" );
159 ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res ));
160 WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL );
161 ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" );
162 CloseHandle( file );
164 return pathW;
167 #define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
168 static void _delete_testfontfile(const WCHAR *filename, int line)
170 BOOL ret = DeleteFileW(filename);
171 ok_(__FILE__,line)(ret, "failed to delete file %s, error %d\n", wine_dbgstr_w(filename), GetLastError());
174 struct test_fontenumerator
176 IDWriteFontFileEnumerator IDWriteFontFileEnumerator_iface;
177 LONG ref;
179 DWORD index;
180 IDWriteFontFile *font_file;
183 static inline struct test_fontenumerator *impl_from_IDWriteFontFileEnumerator(IDWriteFontFileEnumerator* iface)
185 return CONTAINING_RECORD(iface, struct test_fontenumerator, IDWriteFontFileEnumerator_iface);
188 static HRESULT WINAPI singlefontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
190 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
192 *obj = iface;
193 IDWriteFontFileEnumerator_AddRef(iface);
194 return S_OK;
196 return E_NOINTERFACE;
199 static ULONG WINAPI singlefontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
201 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
202 return InterlockedIncrement(&This->ref);
205 static ULONG WINAPI singlefontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
207 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
208 ULONG ref = InterlockedDecrement(&This->ref);
209 if (!ref) {
210 IDWriteFontFile_Release(This->font_file);
211 heap_free(This);
213 return ref;
216 static HRESULT WINAPI singlefontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **font_file)
218 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
219 IDWriteFontFile_AddRef(This->font_file);
220 *font_file = This->font_file;
221 return S_OK;
224 static HRESULT WINAPI singlefontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
226 struct test_fontenumerator *This = impl_from_IDWriteFontFileEnumerator(iface);
228 if (This->index > 1) {
229 *current = FALSE;
230 return S_OK;
233 This->index++;
234 *current = TRUE;
235 return S_OK;
238 static const struct IDWriteFontFileEnumeratorVtbl singlefontfileenumeratorvtbl =
240 singlefontfileenumerator_QueryInterface,
241 singlefontfileenumerator_AddRef,
242 singlefontfileenumerator_Release,
243 singlefontfileenumerator_MoveNext,
244 singlefontfileenumerator_GetCurrentFontFile
247 static HRESULT create_enumerator(IDWriteFontFile *font_file, IDWriteFontFileEnumerator **ret)
249 struct test_fontenumerator *enumerator;
251 enumerator = heap_alloc(sizeof(struct test_fontenumerator));
252 if (!enumerator)
253 return E_OUTOFMEMORY;
255 enumerator->IDWriteFontFileEnumerator_iface.lpVtbl = &singlefontfileenumeratorvtbl;
256 enumerator->ref = 1;
257 enumerator->index = 0;
258 enumerator->font_file = font_file;
259 IDWriteFontFile_AddRef(font_file);
261 *ret = &enumerator->IDWriteFontFileEnumerator_iface;
262 return S_OK;
265 struct test_fontcollectionloader
267 IDWriteFontCollectionLoader IDWriteFontFileCollectionLoader_iface;
268 IDWriteFontFileLoader *loader;
271 static inline struct test_fontcollectionloader *impl_from_IDWriteFontFileCollectionLoader(IDWriteFontCollectionLoader* iface)
273 return CONTAINING_RECORD(iface, struct test_fontcollectionloader, IDWriteFontFileCollectionLoader_iface);
276 static HRESULT WINAPI resourcecollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
278 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontCollectionLoader))
280 *obj = iface;
281 IDWriteFontCollectionLoader_AddRef(iface);
282 return S_OK;
284 return E_NOINTERFACE;
287 static ULONG WINAPI resourcecollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
289 return 2;
292 static ULONG WINAPI resourcecollectionloader_Release(IDWriteFontCollectionLoader *iface)
294 return 1;
297 static HRESULT WINAPI resourcecollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory,
298 const void * collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator ** fontFileEnumerator)
300 struct test_fontcollectionloader *This = impl_from_IDWriteFontFileCollectionLoader(iface);
301 IDWriteFontFile *font_file;
302 HRESULT hr;
304 IDWriteFactory_CreateCustomFontFileReference(factory, collectionKey, collectionKeySize, This->loader, &font_file);
306 hr = create_enumerator(font_file, fontFileEnumerator);
307 ok(hr == S_OK, "got 0x%08x\n", hr);
309 IDWriteFontFile_Release(font_file);
310 return hr;
313 static const struct IDWriteFontCollectionLoaderVtbl resourcecollectionloadervtbl = {
314 resourcecollectionloader_QueryInterface,
315 resourcecollectionloader_AddRef,
316 resourcecollectionloader_Release,
317 resourcecollectionloader_CreateEnumeratorFromKey
320 /* Here is a functional custom font set of interfaces */
321 struct test_fontdatastream
323 IDWriteFontFileStream IDWriteFontFileStream_iface;
324 LONG ref;
326 LPVOID data;
327 DWORD size;
330 static inline struct test_fontdatastream *impl_from_IDWriteFontFileStream(IDWriteFontFileStream* iface)
332 return CONTAINING_RECORD(iface, struct test_fontdatastream, IDWriteFontFileStream_iface);
335 static HRESULT WINAPI fontdatastream_QueryInterface(IDWriteFontFileStream *iface, REFIID riid, void **obj)
337 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileStream))
339 *obj = iface;
340 IDWriteFontFileStream_AddRef(iface);
341 return S_OK;
343 *obj = NULL;
344 return E_NOINTERFACE;
347 static ULONG WINAPI fontdatastream_AddRef(IDWriteFontFileStream *iface)
349 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
350 ULONG ref = InterlockedIncrement(&This->ref);
351 return ref;
354 static ULONG WINAPI fontdatastream_Release(IDWriteFontFileStream *iface)
356 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
357 ULONG ref = InterlockedDecrement(&This->ref);
358 if (ref == 0)
359 HeapFree(GetProcessHeap(), 0, This);
360 return ref;
363 static HRESULT WINAPI fontdatastream_ReadFileFragment(IDWriteFontFileStream *iface, void const **fragment_start, UINT64 offset, UINT64 fragment_size, void **fragment_context)
365 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
366 *fragment_context = NULL;
367 if (offset+fragment_size > This->size)
369 *fragment_start = NULL;
370 return E_FAIL;
372 else
374 *fragment_start = (BYTE*)This->data + offset;
375 return S_OK;
379 static void WINAPI fontdatastream_ReleaseFileFragment(IDWriteFontFileStream *iface, void *fragment_context)
381 /* Do Nothing */
384 static HRESULT WINAPI fontdatastream_GetFileSize(IDWriteFontFileStream *iface, UINT64 *size)
386 struct test_fontdatastream *This = impl_from_IDWriteFontFileStream(iface);
387 *size = This->size;
388 return S_OK;
391 static HRESULT WINAPI fontdatastream_GetLastWriteTime(IDWriteFontFileStream *iface, UINT64 *last_writetime)
393 return E_NOTIMPL;
396 static const IDWriteFontFileStreamVtbl fontdatastreamvtbl =
398 fontdatastream_QueryInterface,
399 fontdatastream_AddRef,
400 fontdatastream_Release,
401 fontdatastream_ReadFileFragment,
402 fontdatastream_ReleaseFileFragment,
403 fontdatastream_GetFileSize,
404 fontdatastream_GetLastWriteTime
407 static HRESULT create_fontdatastream(LPVOID data, UINT size, IDWriteFontFileStream** iface)
409 struct test_fontdatastream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct test_fontdatastream));
410 if (!This)
411 return E_OUTOFMEMORY;
413 This->data = data;
414 This->size = size;
415 This->ref = 1;
416 This->IDWriteFontFileStream_iface.lpVtbl = &fontdatastreamvtbl;
418 *iface = &This->IDWriteFontFileStream_iface;
419 return S_OK;
422 static HRESULT WINAPI resourcefontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
424 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
426 *obj = iface;
427 return S_OK;
429 *obj = NULL;
430 return E_NOINTERFACE;
433 static ULONG WINAPI resourcefontfileloader_AddRef(IDWriteFontFileLoader *iface)
435 return 2;
438 static ULONG WINAPI resourcefontfileloader_Release(IDWriteFontFileLoader *iface)
440 return 1;
443 static HRESULT WINAPI resourcefontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *fontFileReferenceKey, UINT32 fontFileReferenceKeySize, IDWriteFontFileStream **fontFileStream)
445 LPVOID data;
446 DWORD size;
447 HGLOBAL mem;
449 mem = LoadResource(GetModuleHandleA(NULL), *(HRSRC*)fontFileReferenceKey);
450 ok(mem != NULL, "Failed to lock font resource\n");
451 if (mem)
453 size = SizeofResource(GetModuleHandleA(NULL), *(HRSRC*)fontFileReferenceKey);
454 data = LockResource(mem);
455 return create_fontdatastream(data, size, fontFileStream);
457 return E_FAIL;
460 static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = {
461 resourcefontfileloader_QueryInterface,
462 resourcefontfileloader_AddRef,
463 resourcefontfileloader_Release,
464 resourcefontfileloader_CreateStreamFromKey
467 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
469 static D2D1_POINT_2F g_startpoints[2];
470 static int g_startpoint_count;
472 static HRESULT WINAPI test_geometrysink_QueryInterface(ID2D1SimplifiedGeometrySink *iface, REFIID riid, void **ret)
474 if (IsEqualIID(riid, &IID_ID2D1SimplifiedGeometrySink) ||
475 IsEqualIID(riid, &IID_IUnknown))
477 *ret = iface;
478 ID2D1SimplifiedGeometrySink_AddRef(iface);
479 return S_OK;
482 *ret = NULL;
483 return E_NOINTERFACE;
486 static ULONG WINAPI test_geometrysink_AddRef(ID2D1SimplifiedGeometrySink *iface)
488 return 2;
491 static ULONG WINAPI test_geometrysink_Release(ID2D1SimplifiedGeometrySink *iface)
493 return 1;
496 static void WINAPI test_geometrysink_SetFillMode(ID2D1SimplifiedGeometrySink *iface, D2D1_FILL_MODE mode)
498 CHECK_EXPECT(setfillmode);
499 ok(mode == D2D1_FILL_MODE_WINDING, "fill mode %d\n", mode);
502 static void WINAPI test_geometrysink_SetSegmentFlags(ID2D1SimplifiedGeometrySink *iface, D2D1_PATH_SEGMENT flags)
504 ok(0, "unexpected SetSegmentFlags() - flags %d\n", flags);
507 static void WINAPI test_geometrysink_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
508 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
510 ok(figureBegin == D2D1_FIGURE_BEGIN_FILLED, "begin figure %d\n", figureBegin);
511 if (g_startpoint_count < sizeof(g_startpoints)/sizeof(g_startpoints[0]))
512 g_startpoints[g_startpoint_count] = startPoint;
513 g_startpoint_count++;
516 static void WINAPI test_geometrysink_AddLines(ID2D1SimplifiedGeometrySink *iface,
517 const D2D1_POINT_2F *points, UINT32 count)
521 static void WINAPI test_geometrysink_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
522 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
526 static void WINAPI test_geometrysink_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
528 ok(figureEnd == D2D1_FIGURE_END_CLOSED, "end figure %d\n", figureEnd);
531 static HRESULT WINAPI test_geometrysink_Close(ID2D1SimplifiedGeometrySink *iface)
533 ok(0, "unexpected Close()\n");
534 return E_NOTIMPL;
537 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink_vtbl = {
538 test_geometrysink_QueryInterface,
539 test_geometrysink_AddRef,
540 test_geometrysink_Release,
541 test_geometrysink_SetFillMode,
542 test_geometrysink_SetSegmentFlags,
543 test_geometrysink_BeginFigure,
544 test_geometrysink_AddLines,
545 test_geometrysink_AddBeziers,
546 test_geometrysink_EndFigure,
547 test_geometrysink_Close
550 static void WINAPI test_geometrysink2_BeginFigure(ID2D1SimplifiedGeometrySink *iface,
551 D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin)
553 ok(0, "unexpected call\n");
556 static void WINAPI test_geometrysink2_AddLines(ID2D1SimplifiedGeometrySink *iface,
557 const D2D1_POINT_2F *points, UINT32 count)
559 ok(0, "unexpected call\n");
562 static void WINAPI test_geometrysink2_AddBeziers(ID2D1SimplifiedGeometrySink *iface,
563 const D2D1_BEZIER_SEGMENT *beziers, UINT32 count)
565 ok(0, "unexpected call\n");
568 static void WINAPI test_geometrysink2_EndFigure(ID2D1SimplifiedGeometrySink *iface, D2D1_FIGURE_END figureEnd)
570 ok(0, "unexpected call\n");
573 static const ID2D1SimplifiedGeometrySinkVtbl test_geometrysink2_vtbl = {
574 test_geometrysink_QueryInterface,
575 test_geometrysink_AddRef,
576 test_geometrysink_Release,
577 test_geometrysink_SetFillMode,
578 test_geometrysink_SetSegmentFlags,
579 test_geometrysink2_BeginFigure,
580 test_geometrysink2_AddLines,
581 test_geometrysink2_AddBeziers,
582 test_geometrysink2_EndFigure,
583 test_geometrysink_Close
586 static ID2D1SimplifiedGeometrySink test_geomsink = { &test_geometrysink_vtbl };
587 static ID2D1SimplifiedGeometrySink test_geomsink2 = { &test_geometrysink2_vtbl };
589 static void test_CreateFontFromLOGFONT(void)
591 static const WCHAR tahomaspW[] = {'T','a','h','o','m','a',' ',0};
592 IDWriteGdiInterop *interop;
593 DWRITE_FONT_WEIGHT weight;
594 DWRITE_FONT_STYLE style;
595 IDWriteFont *font;
596 LOGFONTW logfont;
597 LONG weights[][2] = {
598 {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
599 {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
600 { 0, DWRITE_FONT_WEIGHT_NORMAL},
601 { 50, DWRITE_FONT_WEIGHT_NORMAL},
602 {150, DWRITE_FONT_WEIGHT_NORMAL},
603 {250, DWRITE_FONT_WEIGHT_NORMAL},
604 {350, DWRITE_FONT_WEIGHT_NORMAL},
605 {450, DWRITE_FONT_WEIGHT_NORMAL},
606 {650, DWRITE_FONT_WEIGHT_BOLD},
607 {750, DWRITE_FONT_WEIGHT_BOLD},
608 {850, DWRITE_FONT_WEIGHT_BOLD},
609 {950, DWRITE_FONT_WEIGHT_BOLD},
610 {960, DWRITE_FONT_WEIGHT_BOLD},
612 OUTLINETEXTMETRICW otm;
613 IDWriteFactory *factory;
614 HRESULT hr;
615 BOOL ret;
616 HDC hdc;
617 HFONT hfont;
618 BOOL exists;
619 int i;
620 UINT r;
622 factory = create_factory();
624 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
625 EXPECT_HR(hr, S_OK);
627 if (0)
628 /* null out parameter crashes this call */
629 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
631 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
632 EXPECT_HR(hr, E_INVALIDARG);
634 memset(&logfont, 0, sizeof(logfont));
635 logfont.lfHeight = 12;
636 logfont.lfWidth = 12;
637 logfont.lfWeight = FW_NORMAL;
638 logfont.lfItalic = 1;
639 lstrcpyW(logfont.lfFaceName, tahomaW);
641 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
642 EXPECT_HR(hr, S_OK);
644 hfont = CreateFontIndirectW(&logfont);
645 hdc = CreateCompatibleDC(0);
646 SelectObject(hdc, hfont);
648 otm.otmSize = sizeof(otm);
649 r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
650 ok(r, "got %d\n", r);
651 DeleteDC(hdc);
652 DeleteObject(hfont);
654 exists = TRUE;
655 hr = IDWriteFont_HasCharacter(font, 0xd800, &exists);
656 ok(hr == S_OK, "got 0x%08x\n", hr);
657 ok(exists == FALSE, "got %d\n", exists);
659 exists = FALSE;
660 hr = IDWriteFont_HasCharacter(font, 0x20, &exists);
661 ok(hr == S_OK, "got 0x%08x\n", hr);
662 ok(exists == TRUE, "got %d\n", exists);
664 /* now check properties */
665 weight = IDWriteFont_GetWeight(font);
666 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
668 style = IDWriteFont_GetStyle(font);
669 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
670 todo_wine
671 ok(otm.otmfsSelection == 1, "got 0x%08x\n", otm.otmfsSelection);
673 ret = IDWriteFont_IsSymbolFont(font);
674 ok(!ret, "got %d\n", ret);
676 IDWriteFont_Release(font);
678 /* weight values */
679 for (i = 0; i < sizeof(weights)/(2*sizeof(LONG)); i++)
681 memset(&logfont, 0, sizeof(logfont));
682 logfont.lfHeight = 12;
683 logfont.lfWidth = 12;
684 logfont.lfWeight = weights[i][0];
685 lstrcpyW(logfont.lfFaceName, tahomaW);
687 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
688 EXPECT_HR(hr, S_OK);
690 weight = IDWriteFont_GetWeight(font);
691 ok(weight == weights[i][1],
692 "%d: got %d, expected %d\n", i, weight, weights[i][1]);
694 IDWriteFont_Release(font);
697 /* weight not from enum */
698 memset(&logfont, 0, sizeof(logfont));
699 logfont.lfHeight = 12;
700 logfont.lfWidth = 12;
701 logfont.lfWeight = 550;
702 lstrcpyW(logfont.lfFaceName, tahomaW);
704 font = NULL;
705 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
706 ok(hr == S_OK, "got 0x%08x\n", hr);
708 weight = IDWriteFont_GetWeight(font);
709 ok(weight == DWRITE_FONT_WEIGHT_NORMAL || weight == DWRITE_FONT_WEIGHT_BOLD,
710 "got %d\n", weight);
711 IDWriteFont_Release(font);
713 /* empty or nonexistent face name */
714 memset(&logfont, 0, sizeof(logfont));
715 logfont.lfHeight = 12;
716 logfont.lfWidth = 12;
717 logfont.lfWeight = FW_NORMAL;
718 lstrcpyW(logfont.lfFaceName, blahW);
720 font = (void*)0xdeadbeef;
721 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
722 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
723 ok(font == NULL, "got %p\n", font);
725 /* Try with name 'Tahoma ' */
726 memset(&logfont, 0, sizeof(logfont));
727 logfont.lfHeight = 12;
728 logfont.lfWidth = 12;
729 logfont.lfWeight = FW_NORMAL;
730 lstrcpyW(logfont.lfFaceName, tahomaspW);
732 font = (void*)0xdeadbeef;
733 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
734 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
735 ok(font == NULL, "got %p\n", font);
737 /* empty string as a facename */
738 memset(&logfont, 0, sizeof(logfont));
739 logfont.lfHeight = 12;
740 logfont.lfWidth = 12;
741 logfont.lfWeight = FW_NORMAL;
743 font = (void*)0xdeadbeef;
744 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
745 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
746 ok(font == NULL, "got %p\n", font);
748 IDWriteGdiInterop_Release(interop);
749 IDWriteFactory_Release(factory);
752 static void test_CreateBitmapRenderTarget(void)
754 IDWriteBitmapRenderTarget *target, *target2;
755 IDWriteBitmapRenderTarget1 *target1;
756 IDWriteGdiInterop *interop;
757 IDWriteFactory *factory;
758 HBITMAP hbm, hbm2;
759 DWRITE_MATRIX m;
760 DIBSECTION ds;
761 XFORM xform;
762 COLORREF c;
763 HRESULT hr;
764 FLOAT pdip;
765 SIZE size;
766 HDC hdc;
767 int ret;
769 factory = create_factory();
771 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
772 EXPECT_HR(hr, S_OK);
774 target = NULL;
775 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
776 EXPECT_HR(hr, S_OK);
778 if (0) /* crashes on native */
779 hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
781 size.cx = size.cy = -1;
782 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
783 EXPECT_HR(hr, S_OK);
784 ok(size.cx == 0, "got %d\n", size.cx);
785 ok(size.cy == 0, "got %d\n", size.cy);
787 target2 = NULL;
788 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
789 EXPECT_HR(hr, S_OK);
790 ok(target != target2, "got %p, %p\n", target2, target);
791 IDWriteBitmapRenderTarget_Release(target2);
793 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
794 ok(hdc != NULL, "got %p\n", hdc);
796 /* test mode */
797 ret = GetGraphicsMode(hdc);
798 ok(ret == GM_ADVANCED, "got %d\n", ret);
800 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
801 ok(hbm != NULL, "got %p\n", hbm);
803 /* check DIB properties */
804 ret = GetObjectW(hbm, sizeof(ds), &ds);
805 ok(ret == sizeof(BITMAP), "got %d\n", ret);
806 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
807 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
808 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
809 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
810 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
812 IDWriteBitmapRenderTarget_Release(target);
814 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
815 ok(!hbm, "got %p\n", hbm);
817 target = NULL;
818 hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
819 EXPECT_HR(hr, S_OK);
821 hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
822 ok(hdc != NULL, "got %p\n", hdc);
824 /* test context settings */
825 c = GetTextColor(hdc);
826 ok(c == RGB(0, 0, 0), "got 0x%08x\n", c);
827 ret = GetBkMode(hdc);
828 ok(ret == OPAQUE, "got %d\n", ret);
829 c = GetBkColor(hdc);
830 ok(c == RGB(255, 255, 255), "got 0x%08x\n", c);
832 hbm = GetCurrentObject(hdc, OBJ_BITMAP);
833 ok(hbm != NULL, "got %p\n", hbm);
835 /* check DIB properties */
836 ret = GetObjectW(hbm, sizeof(ds), &ds);
837 ok(ret == sizeof(ds), "got %d\n", ret);
838 ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
839 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
840 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
841 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
842 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
844 size.cx = size.cy = -1;
845 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
846 EXPECT_HR(hr, S_OK);
847 ok(size.cx == 10, "got %d\n", size.cx);
848 ok(size.cy == 5, "got %d\n", size.cy);
850 /* resize to same size */
851 hr = IDWriteBitmapRenderTarget_Resize(target, 10, 5);
852 ok(hr == S_OK, "got 0x%08x\n", hr);
854 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
855 ok(hbm2 == hbm, "got %p, %p\n", hbm2, hbm);
857 /* shrink */
858 hr = IDWriteBitmapRenderTarget_Resize(target, 5, 5);
859 ok(hr == S_OK, "got 0x%08x\n", hr);
861 size.cx = size.cy = -1;
862 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
863 ok(hr == S_OK, "got 0x%08x\n", hr);
864 ok(size.cx == 5, "got %d\n", size.cx);
865 ok(size.cy == 5, "got %d\n", size.cy);
867 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
868 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
870 hr = IDWriteBitmapRenderTarget_Resize(target, 20, 5);
871 ok(hr == S_OK, "got 0x%08x\n", hr);
873 size.cx = size.cy = -1;
874 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
875 ok(hr == S_OK, "got 0x%08x\n", hr);
876 ok(size.cx == 20, "got %d\n", size.cx);
877 ok(size.cy == 5, "got %d\n", size.cy);
879 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
880 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
882 hr = IDWriteBitmapRenderTarget_Resize(target, 1, 5);
883 ok(hr == S_OK, "got 0x%08x\n", hr);
885 size.cx = size.cy = -1;
886 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
887 ok(hr == S_OK, "got 0x%08x\n", hr);
888 ok(size.cx == 1, "got %d\n", size.cx);
889 ok(size.cy == 5, "got %d\n", size.cy);
891 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
892 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
894 ret = GetObjectW(hbm2, sizeof(ds), &ds);
895 ok(ret == sizeof(ds), "got %d\n", ret);
896 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
897 ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
898 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
899 ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
900 ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
902 /* empty rectangle */
903 hr = IDWriteBitmapRenderTarget_Resize(target, 0, 5);
904 ok(hr == S_OK, "got 0x%08x\n", hr);
906 size.cx = size.cy = -1;
907 hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
908 ok(hr == S_OK, "got 0x%08x\n", hr);
909 ok(size.cx == 0, "got %d\n", size.cx);
910 ok(size.cy == 5, "got %d\n", size.cy);
912 hbm2 = GetCurrentObject(hdc, OBJ_BITMAP);
913 ok(hbm2 != hbm, "got %p, %p\n", hbm2, hbm);
915 ret = GetObjectW(hbm2, sizeof(ds), &ds);
916 ok(ret == sizeof(BITMAP), "got %d\n", ret);
917 ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
918 ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
919 ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
920 ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
921 ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
923 /* transform tests, current hdc transform is not immediately affected */
924 if (0) /* crashes on native */
925 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, NULL);
927 memset(&m, 0xcc, sizeof(m));
928 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
929 ok(hr == S_OK, "got 0x%08x\n", hr);
930 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);
931 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
932 ret = GetWorldTransform(hdc, &xform);
933 ok(ret, "got %d\n", ret);
934 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
935 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
937 memset(&m, 0, sizeof(m));
938 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
939 ok(hr == S_OK, "got 0x%08x\n", hr);
941 memset(&m, 0xcc, sizeof(m));
942 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
943 ok(hr == S_OK, "got 0x%08x\n", hr);
944 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);
945 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
946 ret = GetWorldTransform(hdc, &xform);
947 ok(ret, "got %d\n", ret);
948 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
949 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
951 memset(&m, 0, sizeof(m));
952 m.m11 = 2.0; m.m22 = 1.0;
953 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m);
954 ok(hr == S_OK, "got 0x%08x\n", hr);
955 ret = GetWorldTransform(hdc, &xform);
956 ok(ret, "got %d\n", ret);
957 ok(xform.eM11 == 1.0 && xform.eM22 == 1.0 && xform.eM12 == 0.0 && xform.eM21 == 0.0, "got wrong transform\n");
958 ok(xform.eDx == 0.0 && xform.eDy == 0.0, "got %.1f,%.1f\n", xform.eDx, xform.eDy);
960 hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, NULL);
961 ok(hr == S_OK, "got 0x%08x\n", hr);
963 memset(&m, 0xcc, sizeof(m));
964 hr = IDWriteBitmapRenderTarget_GetCurrentTransform(target, &m);
965 ok(hr == S_OK, "got 0x%08x\n", hr);
966 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);
967 ok(m.dx == 0.0 && m.dy == 0.0, "got %.1f,%.1f\n", m.dx, m.dy);
969 /* pixels per dip */
970 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
971 ok(pdip == 1.0, "got %.2f\n", pdip);
973 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
974 ok(hr == S_OK, "got 0x%08x\n", hr);
976 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, -1.0);
977 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
979 hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 0.0);
980 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
982 pdip = IDWriteBitmapRenderTarget_GetPixelsPerDip(target);
983 ok(pdip == 2.0, "got %.2f\n", pdip);
985 hr = IDWriteBitmapRenderTarget_QueryInterface(target, &IID_IDWriteBitmapRenderTarget1, (void**)&target1);
986 if (hr == S_OK) {
987 DWRITE_TEXT_ANTIALIAS_MODE mode;
989 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
990 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
992 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE+1);
993 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
995 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
996 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, "got %d\n", mode);
998 hr = IDWriteBitmapRenderTarget1_SetTextAntialiasMode(target1, DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
999 ok(hr == S_OK, "got 0x%08x\n", hr);
1001 mode = IDWriteBitmapRenderTarget1_GetTextAntialiasMode(target1);
1002 ok(mode == DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE, "got %d\n", mode);
1004 IDWriteBitmapRenderTarget1_Release(target1);
1006 else
1007 win_skip("IDWriteBitmapRenderTarget1 is not supported.\n");
1009 IDWriteBitmapRenderTarget_Release(target);
1010 IDWriteGdiInterop_Release(interop);
1011 IDWriteFactory_Release(factory);
1014 static void test_GetFontFamily(void)
1016 IDWriteFontCollection *collection, *collection2;
1017 IDWriteFontCollection *syscoll;
1018 IDWriteFontFamily *family, *family2;
1019 IDWriteGdiInterop *interop;
1020 IDWriteFont *font, *font2;
1021 IDWriteFactory *factory;
1022 LOGFONTW logfont;
1023 HRESULT hr;
1025 factory = create_factory();
1027 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1028 EXPECT_HR(hr, S_OK);
1030 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1031 ok(hr == S_OK, "got 0x%08x\n", hr);
1033 memset(&logfont, 0, sizeof(logfont));
1034 logfont.lfHeight = 12;
1035 logfont.lfWidth = 12;
1036 logfont.lfWeight = FW_NORMAL;
1037 logfont.lfItalic = 1;
1038 lstrcpyW(logfont.lfFaceName, tahomaW);
1040 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1041 ok(hr == S_OK, "got 0x%08x\n", hr);
1043 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1044 ok(hr == S_OK, "got 0x%08x\n", hr);
1045 ok(font2 != font, "got %p, %p\n", font2, font);
1047 if (0) /* crashes on native */
1048 hr = IDWriteFont_GetFontFamily(font, NULL);
1050 EXPECT_REF(font, 1);
1051 hr = IDWriteFont_GetFontFamily(font, &family);
1052 EXPECT_HR(hr, S_OK);
1053 EXPECT_REF(font, 1);
1054 EXPECT_REF(family, 2);
1056 hr = IDWriteFont_GetFontFamily(font, &family2);
1057 EXPECT_HR(hr, S_OK);
1058 ok(family2 == family, "got %p, previous %p\n", family2, family);
1059 EXPECT_REF(font, 1);
1060 EXPECT_REF(family, 3);
1061 IDWriteFontFamily_Release(family2);
1063 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
1064 EXPECT_HR(hr, E_NOINTERFACE);
1065 ok(family2 == NULL, "got %p\n", family2);
1067 hr = IDWriteFont_GetFontFamily(font2, &family2);
1068 ok(hr == S_OK, "got 0x%08x\n", hr);
1069 ok(family2 != family, "got %p, %p\n", family2, family);
1071 collection = NULL;
1072 hr = IDWriteFontFamily_GetFontCollection(family, &collection);
1073 ok(hr == S_OK, "got 0x%08x\n", hr);
1075 collection2 = NULL;
1076 hr = IDWriteFontFamily_GetFontCollection(family2, &collection2);
1077 ok(hr == S_OK, "got 0x%08x\n", hr);
1078 ok(collection == collection2, "got %p, %p\n", collection, collection2);
1079 ok(collection == syscoll, "got %p, %p\n", collection, syscoll);
1081 IDWriteFontCollection_Release(syscoll);
1082 IDWriteFontCollection_Release(collection2);
1083 IDWriteFontCollection_Release(collection);
1084 IDWriteFontFamily_Release(family2);
1085 IDWriteFontFamily_Release(family);
1086 IDWriteFont_Release(font);
1087 IDWriteFont_Release(font2);
1088 IDWriteGdiInterop_Release(interop);
1089 IDWriteFactory_Release(factory);
1092 static void test_GetFamilyNames(void)
1094 IDWriteFontFamily *family;
1095 IDWriteLocalizedStrings *names, *names2;
1096 IDWriteGdiInterop *interop;
1097 IDWriteFactory *factory;
1098 IDWriteFont *font;
1099 LOGFONTW logfont;
1100 WCHAR buffer[100];
1101 HRESULT hr;
1102 UINT32 len;
1104 factory = create_factory();
1106 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1107 EXPECT_HR(hr, S_OK);
1109 memset(&logfont, 0, sizeof(logfont));
1110 logfont.lfHeight = 12;
1111 logfont.lfWidth = 12;
1112 logfont.lfWeight = FW_NORMAL;
1113 logfont.lfItalic = 1;
1114 lstrcpyW(logfont.lfFaceName, tahomaW);
1116 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1117 EXPECT_HR(hr, S_OK);
1119 hr = IDWriteFont_GetFontFamily(font, &family);
1120 EXPECT_HR(hr, S_OK);
1122 if (0) /* crashes on native */
1123 hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
1125 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1126 ok(hr == S_OK, "got 0x%08x\n", hr);
1127 EXPECT_REF(names, 1);
1129 hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
1130 ok(hr == S_OK, "got 0x%08x\n", hr);
1131 EXPECT_REF(names2, 1);
1132 ok(names != names2, "got %p, was %p\n", names2, names);
1134 IDWriteLocalizedStrings_Release(names2);
1136 /* GetStringLength */
1137 if (0) /* crashes on native */
1138 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
1140 len = 100;
1141 hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
1142 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1143 ok(len == (UINT32)-1, "got %u\n", len);
1145 len = 0;
1146 hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
1147 ok(hr == S_OK, "got 0x%08x\n", hr);
1148 ok(len > 0, "got %u\n", len);
1150 /* GetString */
1151 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
1152 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1154 hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
1155 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1157 if (0)
1158 hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
1160 buffer[0] = 1;
1161 hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
1162 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1163 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1165 buffer[0] = 1;
1166 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
1167 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1168 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1170 buffer[0] = 1;
1171 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
1172 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1173 ok(buffer[0] == 0, "got %x\n", buffer[0]);
1175 buffer[0] = 0;
1176 hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
1177 ok(hr == S_OK, "got 0x%08x\n", hr);
1178 ok(buffer[0] != 0, "got %x\n", buffer[0]);
1180 IDWriteLocalizedStrings_Release(names);
1182 IDWriteFontFamily_Release(family);
1183 IDWriteFont_Release(font);
1184 IDWriteGdiInterop_Release(interop);
1185 IDWriteFactory_Release(factory);
1188 static void test_CreateFontFace(void)
1190 IDWriteFontFace *fontface, *fontface2;
1191 IDWriteFontCollection *collection;
1192 DWRITE_FONT_FILE_TYPE file_type;
1193 DWRITE_FONT_FACE_TYPE face_type;
1194 IDWriteGdiInterop *interop;
1195 IDWriteFont *font, *font2;
1196 IDWriteFontFamily *family;
1197 IDWriteFactory *factory;
1198 IDWriteFontFile *file;
1199 LOGFONTW logfont;
1200 BOOL supported;
1201 UINT32 count;
1202 WCHAR *path;
1203 HRESULT hr;
1205 factory = create_factory();
1207 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1208 EXPECT_HR(hr, S_OK);
1210 memset(&logfont, 0, sizeof(logfont));
1211 logfont.lfHeight = 12;
1212 logfont.lfWidth = 12;
1213 logfont.lfWeight = FW_NORMAL;
1214 logfont.lfItalic = 1;
1215 lstrcpyW(logfont.lfFaceName, tahomaW);
1217 font = NULL;
1218 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1219 ok(hr == S_OK, "got 0x%08x\n", hr);
1221 font2 = NULL;
1222 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font2);
1223 ok(hr == S_OK, "got 0x%08x\n", hr);
1224 ok(font != font2, "got %p, %p\n", font, font2);
1226 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
1227 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1229 if (0) /* crashes on native */
1230 hr = IDWriteFont_CreateFontFace(font, NULL);
1232 fontface = NULL;
1233 hr = IDWriteFont_CreateFontFace(font, &fontface);
1234 ok(hr == S_OK, "got 0x%08x\n", hr);
1236 fontface2 = NULL;
1237 hr = IDWriteFont_CreateFontFace(font, &fontface2);
1238 ok(hr == S_OK, "got 0x%08x\n", hr);
1239 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1240 IDWriteFontFace_Release(fontface2);
1242 fontface2 = NULL;
1243 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1244 ok(hr == S_OK, "got 0x%08x\n", hr);
1245 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1246 IDWriteFontFace_Release(fontface2);
1248 IDWriteFont_Release(font2);
1249 IDWriteFont_Release(font);
1251 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFont, (void**)&font);
1252 ok(hr == E_NOINTERFACE || broken(hr == E_NOTIMPL), "got 0x%08x\n", hr);
1254 IDWriteFontFace_Release(fontface);
1255 IDWriteGdiInterop_Release(interop);
1257 /* Create from system collection */
1258 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1259 ok(hr == S_OK, "got 0x%08x\n", hr);
1261 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
1262 ok(hr == S_OK, "got 0x%08x\n", hr);
1264 font = NULL;
1265 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1266 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1267 ok(hr == S_OK, "got 0x%08x\n", hr);
1269 font2 = NULL;
1270 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1271 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font2);
1272 ok(hr == S_OK, "got 0x%08x\n", hr);
1273 ok(font != font2, "got %p, %p\n", font, font2);
1275 fontface = NULL;
1276 hr = IDWriteFont_CreateFontFace(font, &fontface);
1277 ok(hr == S_OK, "got 0x%08x\n", hr);
1279 fontface2 = NULL;
1280 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
1281 ok(hr == S_OK, "got 0x%08x\n", hr);
1282 ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
1284 IDWriteFontFace_Release(fontface);
1285 IDWriteFontFace_Release(fontface2);
1286 IDWriteFont_Release(font2);
1287 IDWriteFont_Release(font);
1288 IDWriteFontFamily_Release(family);
1289 IDWriteFontCollection_Release(collection);
1291 /* IDWriteFactory::CreateFontFace() */
1292 path = create_testfontfile(test_fontfile);
1293 factory = create_factory();
1295 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
1296 ok(hr == S_OK, "got 0x%08x\n",hr);
1298 supported = FALSE;
1299 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
1300 face_type = DWRITE_FONT_FACE_TYPE_CFF;
1301 count = 0;
1302 hr = IDWriteFontFile_Analyze(file, &supported, &file_type, &face_type, &count);
1303 ok(hr == S_OK, "got 0x%08x\n", hr);
1304 ok(supported == TRUE, "got %i\n", supported);
1305 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
1306 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
1307 ok(count == 1, "got %i\n", count);
1309 /* try mismatching face type, the one that's not supported */
1310 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1311 ok(hr == DWRITE_E_FILEFORMAT, "got 0x%08x\n", hr);
1313 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION, 1, &file, 0,
1314 DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1315 ok(hr == DWRITE_E_FILEFORMAT || broken(hr == E_FAIL) /* < win10 */, "got 0x%08x\n", hr);
1317 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_RAW_CFF, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1318 todo_wine
1319 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == E_INVALIDARG) /* older versions */, "got 0x%08x\n", hr);
1321 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TYPE1, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1322 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1324 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_VECTOR, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1325 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1327 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_BITMAP, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1328 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1330 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_UNKNOWN, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
1331 todo_wine
1332 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* < win10 */, "got 0x%08x\n", hr);
1333 if (hr == S_OK) {
1334 ok(fontface != NULL, "got %p\n", fontface);
1335 face_type = IDWriteFontFace_GetType(fontface);
1336 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %d\n", face_type);
1337 IDWriteFontFace_Release(fontface);
1340 IDWriteFontFile_Release(file);
1341 IDWriteFactory_Release(factory);
1342 DELETE_FONTFILE(path);
1345 static void test_GetMetrics(void)
1347 IDWriteGdiInterop *interop;
1348 DWRITE_FONT_METRICS metrics;
1349 IDWriteFontFace *fontface;
1350 IDWriteFactory *factory;
1351 OUTLINETEXTMETRICW otm;
1352 IDWriteFont1 *font1;
1353 IDWriteFont *font;
1354 LOGFONTW logfont;
1355 HRESULT hr;
1356 HDC hdc;
1357 HFONT hfont;
1358 int ret;
1360 factory = create_factory();
1362 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1363 EXPECT_HR(hr, S_OK);
1365 memset(&logfont, 0, sizeof(logfont));
1366 logfont.lfHeight = 12;
1367 logfont.lfWidth = 12;
1368 logfont.lfWeight = FW_NORMAL;
1369 logfont.lfItalic = 1;
1370 lstrcpyW(logfont.lfFaceName, tahomaW);
1372 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1373 ok(hr == S_OK, "got 0x%08x\n", hr);
1375 hfont = CreateFontIndirectW(&logfont);
1376 hdc = CreateCompatibleDC(0);
1377 SelectObject(hdc, hfont);
1379 otm.otmSize = sizeof(otm);
1380 ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
1381 ok(ret, "got %d\n", ret);
1382 DeleteDC(hdc);
1383 DeleteObject(hfont);
1385 if (0) /* crashes on native */
1386 IDWriteFont_GetMetrics(font, NULL);
1388 memset(&metrics, 0, sizeof(metrics));
1389 IDWriteFont_GetMetrics(font, &metrics);
1391 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
1392 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
1393 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
1394 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
1395 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
1396 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
1397 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
1398 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
1399 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
1400 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
1402 hr = IDWriteFont_CreateFontFace(font, &fontface);
1403 ok(hr == S_OK, "got 0x%08x\n", hr);
1405 memset(&metrics, 0, sizeof(metrics));
1406 IDWriteFontFace_GetMetrics(fontface, &metrics);
1408 ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
1409 ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
1410 ok(metrics.descent != 0, "descent %u\n", metrics.descent);
1411 ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
1412 ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
1413 ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
1414 ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
1415 ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
1416 ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
1417 ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
1419 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
1420 if (hr == S_OK) {
1421 DWRITE_FONT_METRICS1 metrics1;
1422 IDWriteFontFace1 *fontface1;
1424 memset(&metrics1, 0, sizeof(metrics1));
1425 IDWriteFont1_GetMetrics(font1, &metrics1);
1427 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
1428 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
1429 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
1430 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
1431 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
1432 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
1433 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
1434 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
1435 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
1436 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
1437 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
1438 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
1439 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
1440 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
1441 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
1442 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
1443 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
1444 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
1445 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
1446 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
1447 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
1449 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
1450 ok(hr == S_OK, "got 0x%08x\n", hr);
1452 memset(&metrics1, 0, sizeof(metrics1));
1453 IDWriteFontFace1_GetMetrics(fontface1, &metrics1);
1455 ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm);
1456 ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent);
1457 ok(metrics1.descent != 0, "descent %u\n", metrics1.descent);
1458 ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap);
1459 ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight);
1460 ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight);
1461 ok(metrics1.underlinePosition < 0, "underlinePosition %d\n", metrics1.underlinePosition);
1462 ok(metrics1.underlineThickness != 0, "underlineThickness %u\n", metrics1.underlineThickness);
1463 ok(metrics1.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics1.strikethroughPosition);
1464 ok(metrics1.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics1.strikethroughThickness);
1465 ok(metrics1.glyphBoxLeft < 0, "glyphBoxLeft %d\n", metrics1.glyphBoxLeft);
1466 ok(metrics1.glyphBoxTop > 0, "glyphBoxTop %d\n", metrics1.glyphBoxTop);
1467 ok(metrics1.glyphBoxRight > 0, "glyphBoxRight %d\n", metrics1.glyphBoxRight);
1468 ok(metrics1.glyphBoxBottom < 0, "glyphBoxBottom %d\n", metrics1.glyphBoxBottom);
1469 ok(metrics1.subscriptPositionY < 0, "subscriptPositionY %d\n", metrics1.subscriptPositionY);
1470 ok(metrics1.subscriptSizeX > 0, "subscriptSizeX %d\n", metrics1.subscriptSizeX);
1471 ok(metrics1.subscriptSizeY > 0, "subscriptSizeY %d\n", metrics1.subscriptSizeY);
1472 ok(metrics1.superscriptPositionY > 0, "superscriptPositionY %d\n", metrics1.superscriptPositionY);
1473 ok(metrics1.superscriptSizeX > 0, "superscriptSizeX %d\n", metrics1.superscriptSizeX);
1474 ok(metrics1.superscriptSizeY > 0, "superscriptSizeY %d\n", metrics1.superscriptSizeY);
1475 ok(!metrics1.hasTypographicMetrics, "hasTypographicMetrics %d\n", metrics1.hasTypographicMetrics);
1477 IDWriteFontFace1_Release(fontface1);
1478 IDWriteFont1_Release(font1);
1480 else
1481 win_skip("DWRITE_FONT_METRICS1 is not supported.\n");
1483 IDWriteFontFace_Release(fontface);
1485 IDWriteFont_Release(font);
1486 IDWriteGdiInterop_Release(interop);
1487 IDWriteFactory_Release(factory);
1490 static void test_system_fontcollection(void)
1492 IDWriteFontCollection *collection, *coll2;
1493 IDWriteLocalFontFileLoader *localloader;
1494 IDWriteFactory *factory, *factory2;
1495 IDWriteFontFileLoader *loader;
1496 IDWriteFontFamily *family;
1497 IDWriteFontFace *fontface;
1498 IDWriteFontFile *file;
1499 IDWriteFont *font;
1500 HRESULT hr;
1501 UINT32 i;
1502 BOOL ret;
1504 factory = create_factory();
1506 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
1507 ok(hr == S_OK, "got 0x%08x\n", hr);
1509 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, FALSE);
1510 ok(hr == S_OK, "got 0x%08x\n", hr);
1511 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
1512 IDWriteFontCollection_Release(coll2);
1514 hr = IDWriteFactory_GetSystemFontCollection(factory, &coll2, TRUE);
1515 ok(hr == S_OK, "got 0x%08x\n", hr);
1516 ok(coll2 == collection, "got %p, was %p\n", coll2, collection);
1517 IDWriteFontCollection_Release(coll2);
1519 factory2 = create_factory();
1520 hr = IDWriteFactory_GetSystemFontCollection(factory2, &coll2, FALSE);
1521 ok(hr == S_OK, "got 0x%08x\n", hr);
1522 ok(coll2 != collection, "got %p, was %p\n", coll2, collection);
1523 IDWriteFontCollection_Release(coll2);
1524 IDWriteFactory_Release(factory2);
1526 i = IDWriteFontCollection_GetFontFamilyCount(collection);
1527 ok(i, "got %u\n", i);
1529 /* invalid index */
1530 family = (void*)0xdeadbeef;
1531 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
1532 ok(hr == E_FAIL, "got 0x%08x\n", hr);
1533 ok(family == NULL, "got %p\n", family);
1535 ret = FALSE;
1536 i = (UINT32)-1;
1537 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaW, &i, &ret);
1538 ok(hr == S_OK, "got 0x%08x\n", hr);
1539 ok(ret, "got %d\n", ret);
1540 ok(i != (UINT32)-1, "got %u\n", i);
1542 ret = FALSE;
1543 i = (UINT32)-1;
1544 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaUppercaseW, &i, &ret);
1545 ok(hr == S_OK, "got 0x%08x\n", hr);
1546 ok(ret, "got %d\n", ret);
1547 ok(i != (UINT32)-1, "got %u\n", i);
1549 ret = FALSE;
1550 i = (UINT32)-1;
1551 hr = IDWriteFontCollection_FindFamilyName(collection, tahomaStrangecaseW, &i, &ret);
1552 ok(hr == S_OK, "got 0x%08x\n", hr);
1553 ok(ret, "got %d\n", ret);
1554 ok(i != (UINT32)-1, "got %u\n", i);
1556 /* get back local file loader */
1557 hr = IDWriteFontCollection_GetFontFamily(collection, i, &family);
1558 ok(hr == S_OK, "got 0x%08x\n", hr);
1560 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
1561 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
1562 ok(hr == S_OK, "got 0x%08x\n", hr);
1563 IDWriteFontFamily_Release(family);
1565 hr = IDWriteFont_CreateFontFace(font, &fontface);
1566 ok(hr == S_OK, "got 0x%08x\n", hr);
1567 IDWriteFont_Release(font);
1569 i = 1;
1570 file = NULL;
1571 hr = IDWriteFontFace_GetFiles(fontface, &i, &file);
1572 ok(hr == S_OK, "got 0x%08x\n", hr);
1573 ok(file != NULL, "got %p\n", file);
1575 hr = IDWriteFontFile_GetLoader(file, &loader);
1576 ok(hr == S_OK, "got 0x%08x\n", hr);
1577 IDWriteFontFile_Release(file);
1579 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
1580 ok(hr == S_OK, "got 0x%08x\n", hr);
1581 IDWriteLocalFontFileLoader_Release(localloader);
1583 /* local loader is not registered by default */
1584 hr = IDWriteFactory_RegisterFontFileLoader(factory, loader);
1585 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
1586 hr = IDWriteFactory_UnregisterFontFileLoader(factory, loader);
1587 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
1589 /* try with a different factory */
1590 factory2 = create_factory();
1591 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
1592 ok(hr == S_OK || broken(hr == DWRITE_E_ALREADYREGISTERED), "got 0x%08x\n", hr);
1593 hr = IDWriteFactory_RegisterFontFileLoader(factory2, loader);
1594 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
1595 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
1596 ok(hr == S_OK || broken(hr == E_INVALIDARG), "got 0x%08x\n", hr);
1597 hr = IDWriteFactory_UnregisterFontFileLoader(factory2, loader);
1598 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1599 IDWriteFactory_Release(factory2);
1601 IDWriteFontFileLoader_Release(loader);
1603 ret = TRUE;
1604 i = 0;
1605 hr = IDWriteFontCollection_FindFamilyName(collection, blahW, &i, &ret);
1606 ok(hr == S_OK, "got 0x%08x\n", hr);
1607 ok(!ret, "got %d\n", ret);
1608 ok(i == (UINT32)-1, "got %u\n", i);
1610 IDWriteFontCollection_Release(collection);
1611 IDWriteFactory_Release(factory);
1614 static void test_ConvertFontFaceToLOGFONT(void)
1616 DWRITE_FONT_SIMULATIONS sim;
1617 IDWriteGdiInterop *interop;
1618 IDWriteFontFace *fontface;
1619 IDWriteFactory *factory;
1620 IDWriteFont *font;
1621 LOGFONTW logfont;
1622 HRESULT hr;
1624 factory = create_factory();
1626 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
1627 ok(hr == S_OK, "got 0x%08x\n", hr);
1629 memset(&logfont, 0, sizeof(logfont));
1630 logfont.lfHeight = 12;
1631 logfont.lfWidth = 12;
1632 logfont.lfEscapement = 100;
1633 logfont.lfWeight = FW_NORMAL;
1634 logfont.lfItalic = 1;
1635 logfont.lfUnderline = 1;
1636 logfont.lfStrikeOut = 1;
1638 lstrcpyW(logfont.lfFaceName, tahomaW);
1640 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
1641 ok(hr == S_OK, "got 0x%08x\n", hr);
1643 hr = IDWriteFont_CreateFontFace(font, &fontface);
1644 ok(hr == S_OK, "got 0x%08x\n", hr);
1646 sim = IDWriteFont_GetSimulations(font);
1647 ok(sim == DWRITE_FONT_SIMULATIONS_OBLIQUE, "sim %d\n", sim);
1649 sim = IDWriteFontFace_GetSimulations(fontface);
1650 ok(sim == DWRITE_FONT_SIMULATIONS_OBLIQUE, "sim %d\n", sim);
1652 IDWriteFont_Release(font);
1654 if (0) /* crashes on native */
1656 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, NULL, NULL);
1657 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, NULL);
1660 memset(&logfont, 0xa, sizeof(logfont));
1661 logfont.lfFaceName[0] = 0;
1663 hr = IDWriteGdiInterop_ConvertFontFaceToLOGFONT(interop, fontface, &logfont);
1664 ok(hr == S_OK, "got 0x%08x\n", hr);
1665 ok(logfont.lfHeight == 0, "got %d\n", logfont.lfHeight);
1666 ok(logfont.lfWidth == 0, "got %d\n", logfont.lfWidth);
1667 ok(logfont.lfWeight == FW_NORMAL, "got %d\n", logfont.lfWeight);
1668 ok(logfont.lfEscapement == 0, "got %d\n", logfont.lfEscapement);
1669 ok(logfont.lfItalic == 1, "got %d\n", logfont.lfItalic);
1670 ok(logfont.lfUnderline == 0, "got %d\n", logfont.lfUnderline);
1671 ok(logfont.lfStrikeOut == 0, "got %d\n", logfont.lfStrikeOut);
1672 ok(!lstrcmpW(logfont.lfFaceName, tahomaW), "got %s\n", wine_dbgstr_w(logfont.lfFaceName));
1674 IDWriteGdiInterop_Release(interop);
1675 IDWriteFontFace_Release(fontface);
1676 IDWriteFactory_Release(factory);
1679 static HRESULT WINAPI fontfileenumerator_QueryInterface(IDWriteFontFileEnumerator *iface, REFIID riid, void **obj)
1681 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileEnumerator))
1683 *obj = iface;
1684 IDWriteFontFileEnumerator_AddRef(iface);
1685 return S_OK;
1687 return E_NOINTERFACE;
1690 static ULONG WINAPI fontfileenumerator_AddRef(IDWriteFontFileEnumerator *iface)
1692 return 2;
1695 static ULONG WINAPI fontfileenumerator_Release(IDWriteFontFileEnumerator *iface)
1697 return 1;
1700 static HRESULT WINAPI fontfileenumerator_GetCurrentFontFile(IDWriteFontFileEnumerator *iface, IDWriteFontFile **file)
1702 *file = NULL;
1703 return E_FAIL;
1706 static HRESULT WINAPI fontfileenumerator_MoveNext(IDWriteFontFileEnumerator *iface, BOOL *current)
1708 *current = FALSE;
1709 return S_OK;
1712 static const struct IDWriteFontFileEnumeratorVtbl dwritefontfileenumeratorvtbl =
1714 fontfileenumerator_QueryInterface,
1715 fontfileenumerator_AddRef,
1716 fontfileenumerator_Release,
1717 fontfileenumerator_MoveNext,
1718 fontfileenumerator_GetCurrentFontFile,
1721 static HRESULT WINAPI fontcollectionloader_QueryInterface(IDWriteFontCollectionLoader *iface, REFIID riid, void **obj)
1723 *obj = iface;
1724 return S_OK;
1727 static ULONG WINAPI fontcollectionloader_AddRef(IDWriteFontCollectionLoader *iface)
1729 return 2;
1732 static ULONG WINAPI fontcollectionloader_Release(IDWriteFontCollectionLoader *iface)
1734 return 1;
1737 static HRESULT WINAPI fontcollectionloader_CreateEnumeratorFromKey(IDWriteFontCollectionLoader *iface, IDWriteFactory *factory, const void *key,
1738 UINT32 key_size, IDWriteFontFileEnumerator **ret)
1740 static IDWriteFontFileEnumerator enumerator = { &dwritefontfileenumeratorvtbl };
1741 *ret = &enumerator;
1742 return S_OK;
1745 static const struct IDWriteFontCollectionLoaderVtbl dwritefontcollectionloadervtbl = {
1746 fontcollectionloader_QueryInterface,
1747 fontcollectionloader_AddRef,
1748 fontcollectionloader_Release,
1749 fontcollectionloader_CreateEnumeratorFromKey
1752 static void test_CustomFontCollection(void)
1754 static const WCHAR fontnameW[] = {'w','i','n','e','_','t','e','s','t',0};
1755 IDWriteFontCollectionLoader collection = { &dwritefontcollectionloadervtbl };
1756 IDWriteFontCollectionLoader collection2 = { &dwritefontcollectionloadervtbl };
1757 IDWriteFontCollectionLoader collection3 = { &dwritefontcollectionloadervtbl };
1758 IDWriteFontCollection *font_collection = NULL;
1759 static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl };
1760 struct test_fontcollectionloader resource_collection = { { &resourcecollectionloadervtbl }, &rloader };
1761 IDWriteFontFamily *family, *family2, *family3;
1762 IDWriteFontFace *idfontface, *idfontface2;
1763 IDWriteFontFile *fontfile, *fontfile2;
1764 IDWriteLocalizedStrings *string;
1765 IDWriteFont *idfont, *idfont2;
1766 IDWriteFactory *factory;
1767 UINT32 index, count;
1768 BOOL exists;
1769 HRESULT hr;
1770 HRSRC font;
1772 factory = create_factory();
1774 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, NULL);
1775 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1777 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, NULL);
1778 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1780 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &collection);
1781 ok(hr == S_OK, "got 0x%08x\n", hr);
1782 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &collection2);
1783 ok(hr == S_OK, "got 0x%08x\n", hr);
1784 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &collection);
1785 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
1787 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
1788 ok(hr == S_OK, "got 0x%08x\n", hr);
1789 hr = IDWriteFactory_RegisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
1790 ok(hr == S_OK, "got 0x%08x\n", hr);
1792 hr = IDWriteFactory_CreateCustomFontCollection(factory, &collection3, "Billy", 6, &font_collection);
1793 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1795 hr = IDWriteFactory_CreateCustomFontCollection(factory, &collection, "Billy", 6, &font_collection);
1796 ok(hr == S_OK, "got 0x%08x\n", hr);
1797 IDWriteFontCollection_Release(font_collection);
1799 hr = IDWriteFactory_CreateCustomFontCollection(factory, &collection2, "Billy", 6, &font_collection);
1800 ok(hr == S_OK, "got 0x%08x\n", hr);
1801 IDWriteFontCollection_Release(font_collection);
1803 hr = IDWriteFactory_CreateCustomFontCollection(factory, (IDWriteFontCollectionLoader*)0xdeadbeef, "Billy", 6, &font_collection);
1804 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1806 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
1807 ok(font != NULL, "Failed to find font resource\n");
1809 hr = IDWriteFactory_CreateCustomFontCollection(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface,
1810 &font, sizeof(HRSRC), &font_collection);
1811 ok(hr == S_OK, "got 0x%08x\n",hr);
1813 index = 1;
1814 exists = FALSE;
1815 hr = IDWriteFontCollection_FindFamilyName(font_collection, fontnameW, &index, &exists);
1816 ok(hr == S_OK, "got 0x%08x\n", hr);
1817 ok(index == 0, "got index %i\n", index);
1818 ok(exists, "got exists %i\n", exists);
1820 count = IDWriteFontCollection_GetFontFamilyCount(font_collection);
1821 ok(count == 1, "got %u\n", count);
1823 family = NULL;
1824 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family);
1825 ok(hr == S_OK, "got 0x%08x\n", hr);
1826 EXPECT_REF(family, 1);
1828 family2 = NULL;
1829 hr = IDWriteFontCollection_GetFontFamily(font_collection, 0, &family2);
1830 ok(hr == S_OK, "got 0x%08x\n", hr);
1831 EXPECT_REF(family2, 1);
1832 ok(family != family2, "got %p, %p\n", family, family2);
1834 hr = IDWriteFontFamily_GetFont(family, 0, &idfont);
1835 ok(hr == S_OK, "got 0x%08x\n", hr);
1836 EXPECT_REF(idfont, 1);
1837 EXPECT_REF(family, 2);
1838 hr = IDWriteFontFamily_GetFont(family, 0, &idfont2);
1839 ok(hr == S_OK, "got 0x%08x\n", hr);
1840 EXPECT_REF(idfont2, 1);
1841 EXPECT_REF(family, 3);
1842 ok(idfont != idfont2, "got %p, %p\n", idfont, idfont2);
1843 IDWriteFont_Release(idfont2);
1845 hr = IDWriteFont_GetInformationalStrings(idfont, DWRITE_INFORMATIONAL_STRING_COPYRIGHT_NOTICE, &string, &exists);
1846 ok(hr == S_OK, "got 0x%08x\n", hr);
1847 ok(exists, "got %d\n", exists);
1848 EXPECT_REF(string, 1);
1849 IDWriteLocalizedStrings_Release(string);
1851 family3 = NULL;
1852 hr = IDWriteFont_GetFontFamily(idfont, &family3);
1853 ok(hr == S_OK, "got 0x%08x\n", hr);
1854 EXPECT_REF(family, 3);
1855 ok(family == family3, "got %p, %p\n", family, family3);
1856 IDWriteFontFamily_Release(family3);
1858 idfontface = NULL;
1859 hr = IDWriteFont_CreateFontFace(idfont, &idfontface);
1860 ok(hr == S_OK, "got 0x%08x\n", hr);
1861 EXPECT_REF(idfont, 1);
1863 idfont2 = NULL;
1864 hr = IDWriteFontFamily_GetFont(family2, 0, &idfont2);
1865 ok(hr == S_OK, "got 0x%08x\n", hr);
1866 EXPECT_REF(idfont2, 1);
1867 EXPECT_REF(idfont, 1);
1868 ok(idfont2 != idfont, "Font instances should not match\n");
1870 idfontface2 = NULL;
1871 hr = IDWriteFont_CreateFontFace(idfont2, &idfontface2);
1872 ok(hr == S_OK, "got 0x%08x\n", hr);
1873 ok(idfontface2 == idfontface, "fontfaces should match\n");
1875 index = 1;
1876 fontfile = NULL;
1877 hr = IDWriteFontFace_GetFiles(idfontface, &index, &fontfile);
1878 ok(hr == S_OK, "got 0x%08x\n", hr);
1880 index = 1;
1881 fontfile2 = NULL;
1882 hr = IDWriteFontFace_GetFiles(idfontface2, &index, &fontfile2);
1883 ok(hr == S_OK, "got 0x%08x\n", hr);
1884 ok(fontfile == fontfile2, "fontfiles should match\n");
1886 IDWriteFont_Release(idfont);
1887 IDWriteFont_Release(idfont2);
1888 IDWriteFontFile_Release(fontfile);
1889 IDWriteFontFile_Release(fontfile2);
1890 IDWriteFontFace_Release(idfontface);
1891 IDWriteFontFace_Release(idfontface2);
1892 IDWriteFontFamily_Release(family2);
1893 IDWriteFontFamily_Release(family);
1894 IDWriteFontCollection_Release(font_collection);
1896 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &collection);
1897 ok(hr == S_OK, "got 0x%08x\n", hr);
1898 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &collection);
1899 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1900 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &collection2);
1901 ok(hr == S_OK, "got 0x%08x\n", hr);
1902 hr = IDWriteFactory_UnregisterFontCollectionLoader(factory, &resource_collection.IDWriteFontFileCollectionLoader_iface);
1903 ok(hr == S_OK, "got 0x%08x\n", hr);
1904 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
1905 ok(hr == S_OK, "got 0x%08x\n", hr);
1907 IDWriteFactory_Release(factory);
1910 static HRESULT WINAPI fontfileloader_QueryInterface(IDWriteFontFileLoader *iface, REFIID riid, void **obj)
1912 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDWriteFontFileLoader))
1914 *obj = iface;
1915 IDWriteFontFileLoader_AddRef(iface);
1916 return S_OK;
1919 *obj = NULL;
1920 return E_NOINTERFACE;
1923 static ULONG WINAPI fontfileloader_AddRef(IDWriteFontFileLoader *iface)
1925 return 2;
1928 static ULONG WINAPI fontfileloader_Release(IDWriteFontFileLoader *iface)
1930 return 1;
1933 static HRESULT WINAPI fontfileloader_CreateStreamFromKey(IDWriteFontFileLoader *iface, const void *fontFileReferenceKey, UINT32 fontFileReferenceKeySize, IDWriteFontFileStream **fontFileStream)
1935 return 0x8faecafe;
1938 static const struct IDWriteFontFileLoaderVtbl dwritefontfileloadervtbl = {
1939 fontfileloader_QueryInterface,
1940 fontfileloader_AddRef,
1941 fontfileloader_Release,
1942 fontfileloader_CreateStreamFromKey
1945 static void test_CreateCustomFontFileReference(void)
1947 IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl };
1948 IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl };
1949 IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl };
1950 IDWriteFactory *factory, *factory2;
1951 IDWriteFontFile *file, *file2;
1952 BOOL support;
1953 DWRITE_FONT_FILE_TYPE file_type;
1954 DWRITE_FONT_FACE_TYPE face_type;
1955 UINT32 count;
1956 IDWriteFontFace *face, *face2;
1957 HRESULT hr;
1958 HRSRC fontrsrc;
1959 UINT32 codePoints[1] = {0xa8};
1960 UINT16 indices[2];
1962 factory = create_factory();
1963 factory2 = create_factory();
1965 if (0) { /* crashes on win10 */
1966 hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
1967 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1969 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
1970 ok(hr == S_OK, "got 0x%08x\n", hr);
1971 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader2);
1972 ok(hr == S_OK, "got 0x%08x\n", hr);
1973 hr = IDWriteFactory_RegisterFontFileLoader(factory, &floader);
1974 ok(hr == DWRITE_E_ALREADYREGISTERED, "got 0x%08x\n", hr);
1975 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
1976 ok(hr == S_OK, "got 0x%08x\n", hr);
1978 file = NULL;
1979 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
1980 ok(hr == S_OK, "got 0x%08x\n", hr);
1981 IDWriteFontFile_Release(file);
1983 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader3, &file);
1984 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1986 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, NULL, &file);
1987 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1989 file = NULL;
1990 hr = IDWriteFactory_CreateCustomFontFileReference(factory, "test", 4, &floader, &file);
1991 ok(hr == S_OK, "got 0x%08x\n", hr);
1993 file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
1994 face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
1995 support = TRUE;
1996 count = 1;
1997 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
1998 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
1999 ok(support == FALSE, "got %i\n", support);
2000 ok(file_type == DWRITE_FONT_FILE_TYPE_UNKNOWN, "got %i\n", file_type);
2001 ok(face_type == DWRITE_FONT_FACE_TYPE_UNKNOWN, "got %i\n", face_type);
2002 ok(count == 0, "got %i\n", count);
2004 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_CFF, 1, &file, 0, 0, &face);
2005 ok(hr == 0x8faecafe, "got 0x%08x\n", hr);
2006 IDWriteFontFile_Release(file);
2008 fontrsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
2009 ok(fontrsrc != NULL, "Failed to find font resource\n");
2011 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file);
2012 ok(hr == S_OK, "got 0x%08x\n", hr);
2014 file_type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
2015 face_type = DWRITE_FONT_FACE_TYPE_UNKNOWN;
2016 support = FALSE;
2017 count = 0;
2018 hr = IDWriteFontFile_Analyze(file, &support, &file_type, &face_type, &count);
2019 ok(hr == S_OK, "got 0x%08x\n", hr);
2020 ok(support == TRUE, "got %i\n", support);
2021 ok(file_type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", file_type);
2022 ok(face_type == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face_type);
2023 ok(count == 1, "got %i\n", count);
2025 /* invalid index */
2026 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 1, DWRITE_FONT_SIMULATIONS_NONE, &face);
2027 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2029 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
2030 ok(hr == S_OK, "got 0x%08x\n", hr);
2032 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
2033 ok(hr == S_OK, "got 0x%08x\n", hr);
2034 /* fontface instances are reused starting with win7 */
2035 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
2036 IDWriteFontFace_Release(face2);
2038 /* file was created with different factory */
2039 face2 = NULL;
2040 hr = IDWriteFactory_CreateFontFace(factory2, face_type, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
2041 todo_wine
2042 ok(hr == S_OK, "got 0x%08x\n", hr);
2043 if (face2)
2044 IDWriteFontFace_Release(face2);
2046 file2 = NULL;
2047 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontrsrc, sizeof(HRSRC), &rloader, &file2);
2048 ok(hr == S_OK, "got 0x%08x\n", hr);
2049 ok(file != file2, "got %p, %p\n", file, file2);
2051 hr = IDWriteFactory_CreateFontFace(factory, face_type, 1, &file2, 0, DWRITE_FONT_SIMULATIONS_NONE, &face2);
2052 ok(hr == S_OK, "got 0x%08x\n", hr);
2053 /* fontface instances are reused starting with win7 */
2054 ok(face == face2 || broken(face != face2), "got %p, %p\n", face, face2);
2055 IDWriteFontFace_Release(face2);
2056 IDWriteFontFile_Release(file2);
2058 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, NULL);
2059 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
2061 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, NULL);
2062 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
2064 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 0, indices);
2065 ok(hr == S_OK, "got 0x%08x\n", hr);
2067 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 0, indices);
2068 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
2070 indices[0] = indices[1] = 11;
2071 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, indices);
2072 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2073 ok(indices[0] == 0, "got index %i\n", indices[0]);
2074 ok(indices[1] == 11, "got index %i\n", indices[1]);
2076 if (0) /* crashes on native */
2077 hr = IDWriteFontFace_GetGlyphIndices(face, NULL, 1, NULL);
2079 hr = IDWriteFontFace_GetGlyphIndices(face, codePoints, 1, indices);
2080 ok(hr == S_OK, "got 0x%08x\n", hr);
2081 ok(indices[0] == 6, "got index %i\n", indices[0]);
2082 IDWriteFontFace_Release(face);
2083 IDWriteFontFile_Release(file);
2085 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
2086 ok(hr == S_OK, "got 0x%08x\n", hr);
2087 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader);
2088 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2089 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &floader2);
2090 ok(hr == S_OK, "got 0x%08x\n", hr);
2091 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
2092 ok(hr == S_OK, "got 0x%08x\n", hr);
2094 IDWriteFactory_Release(factory2);
2095 IDWriteFactory_Release(factory);
2098 static void test_CreateFontFileReference(void)
2100 HRESULT hr;
2101 IDWriteFontFile *ffile = NULL;
2102 BOOL support;
2103 DWRITE_FONT_FILE_TYPE type;
2104 DWRITE_FONT_FACE_TYPE face;
2105 UINT32 count;
2106 IDWriteFontFace *fface = NULL;
2107 IDWriteFactory *factory;
2108 WCHAR *path;
2110 path = create_testfontfile(test_fontfile);
2111 factory = create_factory();
2113 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &ffile);
2114 ok(hr == S_OK, "got 0x%08x\n",hr);
2116 support = FALSE;
2117 type = DWRITE_FONT_FILE_TYPE_UNKNOWN;
2118 face = DWRITE_FONT_FACE_TYPE_CFF;
2119 count = 0;
2120 hr = IDWriteFontFile_Analyze(ffile, &support, &type, &face, &count);
2121 ok(hr == S_OK, "got 0x%08x\n", hr);
2122 ok(support == TRUE, "got %i\n", support);
2123 ok(type == DWRITE_FONT_FILE_TYPE_TRUETYPE, "got %i\n", type);
2124 ok(face == DWRITE_FONT_FACE_TYPE_TRUETYPE, "got %i\n", face);
2125 ok(count == 1, "got %i\n", count);
2127 hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fface);
2128 ok(hr == S_OK, "got 0x%08x\n", hr);
2130 IDWriteFontFace_Release(fface);
2131 IDWriteFontFile_Release(ffile);
2132 IDWriteFactory_Release(factory);
2134 DELETE_FONTFILE(path);
2137 static void test_shared_isolated(void)
2139 IDWriteFactory *isolated, *isolated2;
2140 IDWriteFactory *shared, *shared2;
2141 HRESULT hr;
2143 /* invalid type */
2144 shared = NULL;
2145 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&shared);
2146 ok(hr == S_OK, "got 0x%08x\n", hr);
2147 ok(shared != NULL, "got %p\n", shared);
2148 IDWriteFactory_Release(shared);
2150 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared);
2151 ok(hr == S_OK, "got 0x%08x\n", hr);
2153 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
2154 ok(hr == S_OK, "got 0x%08x\n", hr);
2155 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
2157 IDWriteFactory_Release(shared);
2158 IDWriteFactory_Release(shared2);
2160 /* we got 2 references, released 2 - still same pointer is returned */
2161 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown**)&shared2);
2162 ok(hr == S_OK, "got 0x%08x\n", hr);
2163 ok(shared == shared2, "got %p, and %p\n", shared, shared2);
2164 IDWriteFactory_Release(shared2);
2166 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated);
2167 ok(hr == S_OK, "got 0x%08x\n", hr);
2169 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&isolated2);
2170 ok(hr == S_OK, "got 0x%08x\n", hr);
2171 ok(isolated != isolated2, "got %p, and %p\n", isolated, isolated2);
2172 IDWriteFactory_Release(isolated2);
2174 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED+1, &IID_IDWriteFactory, (IUnknown**)&isolated2);
2175 ok(hr == S_OK, "got 0x%08x\n", hr);
2176 ok(shared != isolated2, "got %p, and %p\n", shared, isolated2);
2178 IDWriteFactory_Release(isolated);
2179 IDWriteFactory_Release(isolated2);
2182 static void test_GetUnicodeRanges(void)
2184 DWRITE_UNICODE_RANGE *ranges, r;
2185 IDWriteFontFile *ffile = NULL;
2186 IDWriteFontFace1 *fontface1;
2187 IDWriteFontFace *fontface;
2188 IDWriteFactory *factory;
2189 UINT32 count;
2190 HRESULT hr;
2191 HRSRC font;
2193 factory = create_factory();
2195 hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader);
2196 ok(hr == S_OK, "got 0x%08x\n", hr);
2198 font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA);
2199 ok(font != NULL, "Failed to find font resource\n");
2201 hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile);
2202 ok(hr == S_OK, "got 0x%08x\n", hr);
2204 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2205 ok(hr == S_OK, "got 0x%08x\n", hr);
2206 IDWriteFontFile_Release(ffile);
2208 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
2209 IDWriteFontFace_Release(fontface);
2210 if (hr != S_OK) {
2211 win_skip("GetUnicodeRanges() is not supported.\n");
2212 IDWriteFactory_Release(factory);
2213 return;
2216 count = 0;
2217 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
2218 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2219 ok(count > 0, "got %u\n", count);
2221 count = 1;
2222 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count);
2223 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2224 ok(count == 0, "got %u\n", count);
2226 count = 0;
2227 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count);
2228 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2229 ok(count > 1, "got %u\n", count);
2231 ranges = heap_alloc(count*sizeof(DWRITE_UNICODE_RANGE));
2232 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
2233 ok(hr == S_OK, "got 0x%08x\n", hr);
2235 ranges[0].first = ranges[0].last = 0;
2236 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count);
2237 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2238 ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last);
2240 heap_free(ranges);
2242 hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader);
2243 ok(hr == S_OK, "got 0x%08x\n", hr);
2245 IDWriteFontFace1_Release(fontface1);
2246 IDWriteFactory_Release(factory);
2249 static void test_GetFontFromFontFace(void)
2251 IDWriteFontFace *fontface, *fontface2;
2252 IDWriteFontCollection *collection;
2253 IDWriteFont *font, *font2, *font3;
2254 IDWriteFontFamily *family;
2255 IDWriteFactory *factory;
2256 IDWriteFontFile *file;
2257 WCHAR *path;
2258 HRESULT hr;
2260 factory = create_factory();
2262 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2263 ok(hr == S_OK, "got 0x%08x\n", hr);
2265 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
2266 ok(hr == S_OK, "got 0x%08x\n", hr);
2268 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2269 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2270 ok(hr == S_OK, "got 0x%08x\n", hr);
2272 hr = IDWriteFont_CreateFontFace(font, &fontface);
2273 ok(hr == S_OK, "got 0x%08x\n", hr);
2275 font2 = NULL;
2276 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font2);
2277 ok(hr == S_OK, "got 0x%08x\n", hr);
2278 ok(font2 != font, "got %p, %p\n", font2, font);
2280 font3 = NULL;
2281 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
2282 ok(hr == S_OK, "got 0x%08x\n", hr);
2283 ok(font3 != font && font3 != font2, "got %p, %p, %p\n", font3, font2, font);
2285 hr = IDWriteFont_CreateFontFace(font2, &fontface2);
2286 ok(hr == S_OK, "got 0x%08x\n", hr);
2287 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
2288 IDWriteFontFace_Release(fontface2);
2290 hr = IDWriteFont_CreateFontFace(font3, &fontface2);
2291 ok(hr == S_OK, "got 0x%08x\n", hr);
2292 ok(fontface2 == fontface, "got %p, %p\n", fontface2, fontface);
2293 IDWriteFontFace_Release(fontface2);
2294 IDWriteFontFace_Release(fontface);
2295 IDWriteFont_Release(font3);
2296 IDWriteFactory_Release(factory);
2298 /* fontface that wasn't created from this collection */
2299 factory = create_factory();
2300 path = create_testfontfile(test_fontfile);
2302 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
2303 ok(hr == S_OK, "got 0x%08x\n",hr);
2305 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2306 ok(hr == S_OK, "got 0x%08x\n", hr);
2307 IDWriteFontFile_Release(file);
2309 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font3);
2310 ok(hr == DWRITE_E_NOFONT, "got 0x%08x\n", hr);
2311 ok(font3 == NULL, "got %p\n", font3);
2312 IDWriteFontFace_Release(fontface);
2314 IDWriteFont_Release(font);
2315 IDWriteFont_Release(font2);
2316 IDWriteFontFamily_Release(family);
2317 IDWriteFontCollection_Release(collection);
2318 IDWriteFactory_Release(factory);
2319 DELETE_FONTFILE(path);
2322 static IDWriteFont *get_font(IDWriteFactory *factory, const WCHAR *name, DWRITE_FONT_STYLE style)
2324 IDWriteFontCollection *collection;
2325 IDWriteFontFamily *family;
2326 IDWriteFont *font = NULL;
2327 UINT32 index;
2328 BOOL exists;
2329 HRESULT hr;
2331 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2332 ok(hr == S_OK, "got 0x%08x\n", hr);
2334 index = ~0;
2335 exists = FALSE;
2336 hr = IDWriteFontCollection_FindFamilyName(collection, name, &index, &exists);
2337 ok(hr == S_OK, "got 0x%08x\n", hr);
2338 if (!exists) goto not_found;
2340 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
2341 ok(hr == S_OK, "got 0x%08x\n", hr);
2343 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2344 DWRITE_FONT_STRETCH_NORMAL, style, &font);
2345 ok(hr == S_OK, "got 0x%08x\n", hr);
2347 IDWriteFontFamily_Release(family);
2348 not_found:
2349 IDWriteFontCollection_Release(collection);
2350 return font;
2353 static IDWriteFont *get_tahoma_instance(IDWriteFactory *factory, DWRITE_FONT_STYLE style)
2355 IDWriteFont *font = get_font(factory, tahomaW, style);
2356 ok(font != NULL, "failed to get Tahoma\n");
2357 return font;
2360 static void test_GetFirstMatchingFont(void)
2362 DWRITE_FONT_SIMULATIONS simulations;
2363 IDWriteFont *font, *font2;
2364 IDWriteFactory *factory;
2366 factory = create_factory();
2368 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
2369 font2 = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
2370 ok(font != font2, "got %p, %p\n", font, font2);
2371 IDWriteFont_Release(font);
2372 IDWriteFont_Release(font2);
2374 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
2375 simulations = IDWriteFont_GetSimulations(font);
2376 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "%d\n", simulations);
2377 IDWriteFont_Release(font);
2379 IDWriteFactory_Release(factory);
2382 static void test_GetInformationalStrings(void)
2384 IDWriteLocalizedStrings *strings, *strings2;
2385 IDWriteFontCollection *collection;
2386 IDWriteFontFamily *family;
2387 IDWriteFactory *factory;
2388 IDWriteFont *font;
2389 BOOL exists;
2390 HRESULT hr;
2392 factory = create_factory();
2394 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
2395 ok(hr == S_OK, "got 0x%08x\n", hr);
2397 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
2398 ok(hr == S_OK, "got 0x%08x\n", hr);
2400 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2401 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2402 ok(hr == S_OK, "got 0x%08x\n", hr);
2404 exists = TRUE;
2405 strings = (void*)0xdeadbeef;
2406 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_CID_NAME+1, &strings, &exists);
2407 ok(hr == S_OK, "got 0x%08x\n", hr);
2408 ok(exists == FALSE, "got %d\n", exists);
2409 ok(strings == NULL, "got %p\n", strings);
2411 exists = TRUE;
2412 strings = NULL;
2413 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_NONE, &strings, &exists);
2414 ok(hr == S_OK, "got 0x%08x\n", hr);
2415 ok(exists == FALSE, "got %d\n", exists);
2417 exists = FALSE;
2418 strings = NULL;
2419 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
2420 ok(hr == S_OK, "got 0x%08x\n", hr);
2421 ok(exists == TRUE, "got %d\n", exists);
2423 /* strings instance is not reused */
2424 strings2 = NULL;
2425 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings2, &exists);
2426 ok(hr == S_OK, "got 0x%08x\n", hr);
2427 ok(strings2 != strings, "got %p, %p\n", strings2, strings);
2429 IDWriteLocalizedStrings_Release(strings);
2430 IDWriteLocalizedStrings_Release(strings2);
2431 IDWriteFont_Release(font);
2432 IDWriteFontFamily_Release(family);
2433 IDWriteFontCollection_Release(collection);
2434 IDWriteFactory_Release(factory);
2437 static void test_GetGdiInterop(void)
2439 IDWriteGdiInterop *interop, *interop2;
2440 IDWriteFactory *factory, *factory2;
2441 IDWriteFont *font;
2442 LOGFONTW logfont;
2443 HRESULT hr;
2445 factory = create_factory();
2447 interop = NULL;
2448 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2449 ok(hr == S_OK, "got 0x%08x\n", hr);
2451 interop2 = NULL;
2452 hr = IDWriteFactory_GetGdiInterop(factory, &interop2);
2453 ok(hr == S_OK, "got 0x%08x\n", hr);
2454 ok(interop == interop2, "got %p, %p\n", interop, interop2);
2455 IDWriteGdiInterop_Release(interop2);
2457 hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory2);
2458 ok(hr == S_OK, "got 0x%08x\n", hr);
2460 /* each factory gets its own interop */
2461 interop2 = NULL;
2462 hr = IDWriteFactory_GetGdiInterop(factory2, &interop2);
2463 ok(hr == S_OK, "got 0x%08x\n", hr);
2464 ok(interop != interop2, "got %p, %p\n", interop, interop2);
2466 /* release factory - interop still works */
2467 IDWriteFactory_Release(factory2);
2469 memset(&logfont, 0, sizeof(logfont));
2470 logfont.lfHeight = 12;
2471 logfont.lfWidth = 12;
2472 logfont.lfWeight = FW_NORMAL;
2473 logfont.lfItalic = 1;
2474 lstrcpyW(logfont.lfFaceName, tahomaW);
2476 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop2, &logfont, &font);
2477 ok(hr == S_OK, "got 0x%08x\n", hr);
2478 IDWriteFont_Release(font);
2480 IDWriteGdiInterop_Release(interop2);
2481 IDWriteGdiInterop_Release(interop);
2482 IDWriteFactory_Release(factory);
2485 static void test_CreateFontFaceFromHdc(void)
2487 IDWriteGdiInterop *interop;
2488 IDWriteFontFace *fontface;
2489 IDWriteFactory *factory;
2490 HFONT hfont, oldhfont;
2491 LOGFONTW logfont;
2492 HRESULT hr;
2493 HDC hdc;
2495 factory = create_factory();
2497 interop = NULL;
2498 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2499 ok(hr == S_OK, "got 0x%08x\n", hr);
2501 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, NULL, &fontface);
2502 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2504 memset(&logfont, 0, sizeof(logfont));
2505 logfont.lfHeight = 12;
2506 logfont.lfWidth = 12;
2507 logfont.lfWeight = FW_NORMAL;
2508 logfont.lfItalic = 1;
2509 lstrcpyW(logfont.lfFaceName, tahomaW);
2511 hfont = CreateFontIndirectW(&logfont);
2512 hdc = CreateCompatibleDC(0);
2513 oldhfont = SelectObject(hdc, hfont);
2515 fontface = NULL;
2516 hr = IDWriteGdiInterop_CreateFontFaceFromHdc(interop, hdc, &fontface);
2517 ok(hr == S_OK, "got 0x%08x\n", hr);
2518 IDWriteFontFace_Release(fontface);
2519 DeleteObject(SelectObject(hdc, oldhfont));
2520 DeleteDC(hdc);
2522 IDWriteGdiInterop_Release(interop);
2523 IDWriteFactory_Release(factory);
2526 static void test_GetSimulations(void)
2528 DWRITE_FONT_SIMULATIONS simulations;
2529 IDWriteGdiInterop *interop;
2530 IDWriteFontFace *fontface;
2531 IDWriteFactory *factory;
2532 IDWriteFont *font;
2533 LOGFONTW logfont;
2534 HRESULT hr;
2536 factory = create_factory();
2538 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2539 ok(hr == S_OK, "got 0x%08x\n", hr);
2541 memset(&logfont, 0, sizeof(logfont));
2542 logfont.lfHeight = 12;
2543 logfont.lfWidth = 12;
2544 logfont.lfWeight = FW_NORMAL;
2545 logfont.lfItalic = 1;
2546 lstrcpyW(logfont.lfFaceName, tahomaW);
2548 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2549 ok(hr == S_OK, "got 0x%08x\n", hr);
2551 simulations = IDWriteFont_GetSimulations(font);
2552 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
2553 hr = IDWriteFont_CreateFontFace(font, &fontface);
2554 ok(hr == S_OK, "got 0x%08x\n", hr);
2555 simulations = IDWriteFontFace_GetSimulations(fontface);
2556 ok(simulations == DWRITE_FONT_SIMULATIONS_OBLIQUE, "got %d\n", simulations);
2557 IDWriteFontFace_Release(fontface);
2558 IDWriteFont_Release(font);
2560 memset(&logfont, 0, sizeof(logfont));
2561 logfont.lfHeight = 12;
2562 logfont.lfWidth = 12;
2563 logfont.lfWeight = FW_NORMAL;
2564 logfont.lfItalic = 0;
2565 lstrcpyW(logfont.lfFaceName, tahomaW);
2567 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2568 ok(hr == S_OK, "got 0x%08x\n", hr);
2570 simulations = IDWriteFont_GetSimulations(font);
2571 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
2572 hr = IDWriteFont_CreateFontFace(font, &fontface);
2573 ok(hr == S_OK, "got 0x%08x\n", hr);
2574 simulations = IDWriteFontFace_GetSimulations(fontface);
2575 ok(simulations == DWRITE_FONT_SIMULATIONS_NONE, "got %d\n", simulations);
2576 IDWriteFontFace_Release(fontface);
2577 IDWriteFont_Release(font);
2579 IDWriteGdiInterop_Release(interop);
2580 IDWriteFactory_Release(factory);
2583 static void test_GetFaceNames(void)
2585 static const WCHAR obliqueW[] = {'O','b','l','i','q','u','e',0};
2586 static const WCHAR enus2W[] = {'e','n','-','U','s',0};
2587 static const WCHAR enusW[] = {'e','n','-','u','s',0};
2588 IDWriteLocalizedStrings *strings, *strings2;
2589 IDWriteGdiInterop *interop;
2590 IDWriteFactory *factory;
2591 UINT32 count, index;
2592 IDWriteFont *font;
2593 LOGFONTW logfont;
2594 WCHAR buffW[255];
2595 BOOL exists;
2596 HRESULT hr;
2598 factory = create_factory();
2600 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2601 ok(hr == S_OK, "got 0x%08x\n", hr);
2603 memset(&logfont, 0, sizeof(logfont));
2604 logfont.lfHeight = 12;
2605 logfont.lfWidth = 12;
2606 logfont.lfWeight = FW_NORMAL;
2607 logfont.lfItalic = 1;
2608 lstrcpyW(logfont.lfFaceName, tahomaW);
2610 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
2611 ok(hr == S_OK, "got 0x%08x\n", hr);
2613 hr = IDWriteFont_GetFaceNames(font, &strings);
2614 ok(hr == S_OK, "got 0x%08x\n", hr);
2616 hr = IDWriteFont_GetFaceNames(font, &strings2);
2617 ok(hr == S_OK, "got 0x%08x\n", hr);
2618 ok(strings != strings2, "got %p, %p\n", strings2, strings);
2619 IDWriteLocalizedStrings_Release(strings2);
2621 count = IDWriteLocalizedStrings_GetCount(strings);
2622 ok(count == 1, "got %d\n", count);
2624 index = 1;
2625 exists = FALSE;
2626 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enus2W, &index, &exists);
2627 ok(hr == S_OK, "got 0x%08x\n", hr);
2628 ok(index == 0 && exists, "got %d, %d\n", index, exists);
2630 count = 0;
2631 hr = IDWriteLocalizedStrings_GetLocaleNameLength(strings, 1, &count);
2632 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2633 ok(count == ~0, "got %d\n", count);
2635 /* for simulated faces names are also simulated */
2636 buffW[0] = 0;
2637 hr = IDWriteLocalizedStrings_GetLocaleName(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
2638 ok(hr == S_OK, "got 0x%08x\n", hr);
2639 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2641 buffW[0] = 0;
2642 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
2643 ok(hr == S_OK, "got 0x%08x\n", hr);
2644 ok(!lstrcmpW(buffW, obliqueW), "got %s\n", wine_dbgstr_w(buffW));
2645 IDWriteLocalizedStrings_Release(strings);
2647 IDWriteFont_Release(font);
2648 IDWriteGdiInterop_Release(interop);
2649 IDWriteFactory_Release(factory);
2652 struct local_refkey
2654 FILETIME writetime;
2655 WCHAR name[1];
2658 static void test_TryGetFontTable(void)
2660 IDWriteLocalFontFileLoader *localloader;
2661 WIN32_FILE_ATTRIBUTE_DATA info;
2662 const struct local_refkey *key;
2663 IDWriteFontFileLoader *loader;
2664 const void *table, *table2;
2665 IDWriteFontFace *fontface;
2666 void *context, *context2;
2667 IDWriteFactory *factory;
2668 IDWriteFontFile *file;
2669 WCHAR buffW[MAX_PATH];
2670 BOOL exists, ret;
2671 UINT32 size, len;
2672 WCHAR *path;
2673 HRESULT hr;
2675 path = create_testfontfile(test_fontfile);
2677 factory = create_factory();
2679 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
2680 ok(hr == S_OK, "got 0x%08x\n",hr);
2682 key = NULL;
2683 size = 0;
2684 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
2685 ok(hr == S_OK, "got 0x%08x\n", hr);
2686 ok(size != 0, "got %u\n", size);
2688 ret = GetFileAttributesExW(path, GetFileExInfoStandard, &info);
2689 ok(ret, "got %d\n", ret);
2690 ok(!memcmp(&info.ftLastWriteTime, &key->writetime, sizeof(key->writetime)), "got wrong write time\n");
2692 hr = IDWriteFontFile_GetLoader(file, &loader);
2693 ok(hr == S_OK, "got 0x%08x\n", hr);
2694 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2695 IDWriteFontFileLoader_Release(loader);
2697 hr = IDWriteLocalFontFileLoader_GetFilePathLengthFromKey(localloader, key, size, &len);
2698 ok(hr == S_OK, "got 0x%08x\n", hr);
2699 ok(lstrlenW(key->name) == len, "path length %d\n", len);
2701 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, size, buffW, sizeof(buffW)/sizeof(WCHAR));
2702 ok(hr == S_OK, "got 0x%08x\n", hr);
2703 ok(!lstrcmpW(buffW, key->name), "got %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(key->name));
2704 IDWriteLocalFontFileLoader_Release(localloader);
2706 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, 0, &fontface);
2707 ok(hr == S_OK, "got 0x%08x\n",hr);
2709 exists = FALSE;
2710 context = (void*)0xdeadbeef;
2711 table = NULL;
2712 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table, &size, &context, &exists);
2713 ok(hr == S_OK, "got 0x%08x\n",hr);
2714 ok(exists == TRUE, "got %d\n", exists);
2715 ok(context == NULL && table != NULL, "cmap: context %p, table %p\n", context, table);
2717 exists = FALSE;
2718 context2 = (void*)0xdeadbeef;
2719 table2 = NULL;
2720 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_CMAP_TAG, &table2, &size, &context2, &exists);
2721 ok(hr == S_OK, "got 0x%08x\n",hr);
2722 ok(exists == TRUE, "got %d\n", exists);
2723 ok(context2 == context && table2 == table, "cmap: context2 %p, table2 %p\n", context2, table2);
2725 IDWriteFontFace_ReleaseFontTable(fontface, context2);
2726 IDWriteFontFace_ReleaseFontTable(fontface, context);
2728 IDWriteFontFace_Release(fontface);
2729 IDWriteFontFile_Release(file);
2730 IDWriteFactory_Release(factory);
2731 DELETE_FONTFILE(path);
2734 static void test_ConvertFontToLOGFONT(void)
2736 IDWriteFactory *factory, *factory2;
2737 IDWriteFontCollection *collection;
2738 IDWriteGdiInterop *interop;
2739 IDWriteFontFamily *family;
2740 IDWriteFont *font;
2741 LOGFONTW logfont;
2742 BOOL system;
2743 HRESULT hr;
2745 factory = create_factory();
2746 factory2 = create_factory();
2748 interop = NULL;
2749 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
2750 ok(hr == S_OK, "got 0x%08x\n", hr);
2752 hr = IDWriteFactory_GetSystemFontCollection(factory2, &collection, FALSE);
2753 ok(hr == S_OK, "got 0x%08x\n", hr);
2755 hr = IDWriteFontCollection_GetFontFamily(collection, 0, &family);
2756 ok(hr == S_OK, "got 0x%08x\n", hr);
2758 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
2759 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
2760 ok(hr == S_OK, "got 0x%08x\n", hr);
2762 if (0) { /* crashes on native */
2763 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, NULL, NULL);
2764 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, NULL);
2765 IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, NULL, &system);
2768 memset(&logfont, 0xcc, sizeof(logfont));
2769 system = TRUE;
2770 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, NULL, &logfont, &system);
2771 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2772 ok(!system, "got %d\n", system);
2773 ok(logfont.lfFaceName[0] == 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2775 system = FALSE;
2777 logfont.lfHeight = 10;
2778 logfont.lfWidth = 11;
2779 logfont.lfEscapement = 10;
2780 logfont.lfOrientation = 10;
2781 logfont.lfWeight = 0;
2782 logfont.lfItalic = 1;
2783 logfont.lfUnderline = 1;
2784 logfont.lfStrikeOut = 1;
2785 logfont.lfCharSet = 0;
2786 logfont.lfOutPrecision = 0;
2787 logfont.lfClipPrecision = 0;
2788 logfont.lfQuality = 0;
2789 logfont.lfPitchAndFamily = 0;
2790 logfont.lfFaceName[0] = 0;
2792 hr = IDWriteGdiInterop_ConvertFontToLOGFONT(interop, font, &logfont, &system);
2793 ok(hr == S_OK, "got 0x%08x\n", hr);
2794 ok(system, "got %d\n", system);
2796 ok(logfont.lfHeight == 0, "got %d\n", logfont.lfHeight);
2797 ok(logfont.lfWidth == 0, "got %d\n", logfont.lfWidth);
2798 ok(logfont.lfEscapement == 0, "got %d\n", logfont.lfEscapement);
2799 ok(logfont.lfOrientation == 0, "got %d\n", logfont.lfOrientation);
2800 ok(logfont.lfWeight > 0, "got %d\n", logfont.lfWeight);
2801 ok(logfont.lfItalic == 0, "got %d\n", logfont.lfItalic);
2802 ok(logfont.lfUnderline == 0, "got %d\n", logfont.lfUnderline);
2803 ok(logfont.lfStrikeOut == 0, "got %d\n", logfont.lfStrikeOut);
2804 ok(logfont.lfCharSet == DEFAULT_CHARSET, "got %d\n", logfont.lfCharSet);
2805 ok(logfont.lfOutPrecision == OUT_OUTLINE_PRECIS, "got %d\n", logfont.lfOutPrecision);
2806 ok(logfont.lfClipPrecision == 0, "got %d\n", logfont.lfClipPrecision);
2807 ok(logfont.lfQuality == 0, "got %d\n", logfont.lfQuality);
2808 ok(logfont.lfPitchAndFamily == 0, "got %d\n", logfont.lfPitchAndFamily);
2809 ok(logfont.lfFaceName[0] != 0, "got face name %s\n", wine_dbgstr_w(logfont.lfFaceName));
2811 IDWriteFactory_Release(factory2);
2813 IDWriteFontCollection_Release(collection);
2814 IDWriteFontFamily_Release(family);
2815 IDWriteFont_Release(font);
2816 IDWriteGdiInterop_Release(interop);
2817 IDWriteFactory_Release(factory);
2820 static void test_CreateStreamFromKey(void)
2822 IDWriteLocalFontFileLoader *localloader;
2823 IDWriteFontFileStream *stream, *stream2;
2824 IDWriteFontFileLoader *loader;
2825 IDWriteFactory *factory;
2826 IDWriteFontFile *file;
2827 UINT64 writetime;
2828 WCHAR *path;
2829 void *key;
2830 UINT32 size;
2831 HRESULT hr;
2833 factory = create_factory();
2835 path = create_testfontfile(test_fontfile);
2837 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
2838 ok(hr == S_OK, "got 0x%08x\n",hr);
2840 key = NULL;
2841 size = 0;
2842 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
2843 ok(hr == S_OK, "got 0x%08x\n", hr);
2844 ok(size != 0, "got %u\n", size);
2846 hr = IDWriteFontFile_GetLoader(file, &loader);
2847 ok(hr == S_OK, "got 0x%08x\n", hr);
2848 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2849 IDWriteFontFileLoader_Release(loader);
2851 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
2852 ok(hr == S_OK, "got 0x%08x\n", hr);
2853 EXPECT_REF(stream, 1);
2855 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream2);
2856 ok(hr == S_OK, "got 0x%08x\n", hr);
2857 ok(stream == stream2 || broken(stream != stream2) /* Win7 SP0 */, "got %p, %p\n", stream, stream2);
2858 if (stream == stream2)
2859 EXPECT_REF(stream, 2);
2860 IDWriteFontFileStream_Release(stream);
2861 IDWriteFontFileStream_Release(stream2);
2863 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
2864 ok(hr == S_OK, "got 0x%08x\n", hr);
2865 EXPECT_REF(stream, 1);
2867 writetime = 0;
2868 hr = IDWriteFontFileStream_GetLastWriteTime(stream, &writetime);
2869 ok(hr == S_OK, "got 0x%08x\n", hr);
2870 ok(writetime != 0, "got %08x%08x\n", (UINT)(writetime >> 32), (UINT)writetime);
2872 IDWriteFontFileStream_Release(stream);
2873 IDWriteFontFile_Release(file);
2875 IDWriteLocalFontFileLoader_Release(localloader);
2876 IDWriteFactory_Release(factory);
2877 DELETE_FONTFILE(path);
2880 static void test_ReadFileFragment(void)
2882 IDWriteLocalFontFileLoader *localloader;
2883 IDWriteFontFileStream *stream;
2884 IDWriteFontFileLoader *loader;
2885 IDWriteFactory *factory;
2886 IDWriteFontFile *file;
2887 const void *fragment, *fragment2;
2888 void *key, *context, *context2;
2889 UINT64 filesize;
2890 UINT32 size;
2891 WCHAR *path;
2892 HRESULT hr;
2894 factory = create_factory();
2896 path = create_testfontfile(test_fontfile);
2898 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
2899 ok(hr == S_OK, "got 0x%08x\n",hr);
2901 key = NULL;
2902 size = 0;
2903 hr = IDWriteFontFile_GetReferenceKey(file, (const void**)&key, &size);
2904 ok(hr == S_OK, "got 0x%08x\n", hr);
2905 ok(size != 0, "got %u\n", size);
2907 hr = IDWriteFontFile_GetLoader(file, &loader);
2908 ok(hr == S_OK, "got 0x%08x\n", hr);
2909 IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
2910 IDWriteFontFileLoader_Release(loader);
2912 hr = IDWriteLocalFontFileLoader_CreateStreamFromKey(localloader, key, size, &stream);
2913 ok(hr == S_OK, "got 0x%08x\n", hr);
2915 hr = IDWriteFontFileStream_GetFileSize(stream, &filesize);
2916 ok(hr == S_OK, "got 0x%08x\n", hr);
2918 /* reading past the end of the stream */
2919 fragment = (void*)0xdeadbeef;
2920 context = (void*)0xdeadbeef;
2921 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize+1, &context);
2922 ok(hr == E_FAIL, "got 0x%08x\n", hr);
2923 ok(context == NULL, "got %p\n", context);
2924 ok(fragment == NULL, "got %p\n", fragment);
2926 fragment = (void*)0xdeadbeef;
2927 context = (void*)0xdeadbeef;
2928 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
2929 ok(hr == S_OK, "got 0x%08x\n", hr);
2930 ok(context == NULL, "got %p\n", context);
2931 ok(fragment != NULL, "got %p\n", fragment);
2933 fragment2 = (void*)0xdeadbeef;
2934 context2 = (void*)0xdeadbeef;
2935 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment2, 0, filesize, &context2);
2936 ok(hr == S_OK, "got 0x%08x\n", hr);
2937 ok(context2 == NULL, "got %p\n", context2);
2938 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
2940 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
2941 IDWriteFontFileStream_ReleaseFileFragment(stream, context2);
2943 /* fragment is released, try again */
2944 fragment = (void*)0xdeadbeef;
2945 context = (void*)0xdeadbeef;
2946 hr = IDWriteFontFileStream_ReadFileFragment(stream, &fragment, 0, filesize, &context);
2947 ok(hr == S_OK, "got 0x%08x\n", hr);
2948 ok(context == NULL, "got %p\n", context);
2949 ok(fragment == fragment2, "got %p, %p\n", fragment, fragment2);
2950 IDWriteFontFileStream_ReleaseFileFragment(stream, context);
2952 IDWriteFontFile_Release(file);
2953 IDWriteFontFileStream_Release(stream);
2954 IDWriteLocalFontFileLoader_Release(localloader);
2955 IDWriteFactory_Release(factory);
2956 DELETE_FONTFILE(path);
2959 static void test_GetDesignGlyphMetrics(void)
2961 DWRITE_GLYPH_METRICS metrics[2];
2962 IDWriteFontFace *fontface;
2963 IDWriteFactory *factory;
2964 IDWriteFontFile *file;
2965 UINT16 indices[2];
2966 UINT32 codepoint;
2967 WCHAR *path;
2968 HRESULT hr;
2970 factory = create_factory();
2972 path = create_testfontfile(test_fontfile);
2974 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
2975 ok(hr == S_OK, "got 0x%08x\n",hr);
2977 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
2978 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
2979 ok(hr == S_OK, "got 0x%08x\n",hr);
2980 IDWriteFontFile_Release(file);
2982 codepoint = 'A';
2983 indices[0] = 0;
2984 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &indices[0]);
2985 ok(hr == S_OK, "got 0x%08x\n", hr);
2986 ok(indices[0] > 0, "got %u\n", indices[0]);
2988 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 0, metrics, FALSE);
2989 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
2991 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, NULL, 1, metrics, FALSE);
2992 ok(hr == E_INVALIDARG, "got 0x%08x\n",hr);
2994 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 0, metrics, FALSE);
2995 ok(hr == S_OK, "got 0x%08x\n",hr);
2997 /* missing glyphs are ignored */
2998 indices[1] = 1;
2999 memset(metrics, 0xcc, sizeof(metrics));
3000 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, indices, 2, metrics, FALSE);
3001 ok(hr == S_OK, "got 0x%08x\n",hr);
3002 ok(metrics[0].advanceWidth == 1000, "got %d\n", metrics[0].advanceWidth);
3003 ok(metrics[1].advanceWidth == 0, "got %d\n", metrics[1].advanceWidth);
3005 IDWriteFontFace_Release(fontface);
3006 IDWriteFactory_Release(factory);
3007 DELETE_FONTFILE(path);
3010 static void test_IsMonospacedFont(void)
3012 static const WCHAR courierW[] = {'C','o','u','r','i','e','r',' ','N','e','w',0};
3013 IDWriteFontCollection *collection;
3014 IDWriteFactory *factory;
3015 UINT32 index;
3016 BOOL exists;
3017 HRESULT hr;
3019 factory = create_factory();
3020 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
3021 ok(hr == S_OK, "got 0x%08x\n", hr);
3023 exists = FALSE;
3024 hr = IDWriteFontCollection_FindFamilyName(collection, courierW, &index, &exists);
3025 ok(hr == S_OK, "got 0x%08x\n", hr);
3026 if (exists) {
3027 IDWriteFontFamily *family;
3028 IDWriteFont1 *font1;
3029 IDWriteFont *font;
3031 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
3032 ok(hr == S_OK, "got 0x%08x\n", hr);
3034 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL,
3035 DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font);
3036 ok(hr == S_OK, "got 0x%08x\n", hr);
3037 IDWriteFontFamily_Release(family);
3039 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
3040 if (hr == S_OK) {
3041 IDWriteFontFace1 *fontface1;
3042 IDWriteFontFace *fontface;
3043 BOOL is_monospaced;
3045 is_monospaced = IDWriteFont1_IsMonospacedFont(font1);
3046 ok(is_monospaced, "got %d\n", is_monospaced);
3048 hr = IDWriteFont1_CreateFontFace(font1, &fontface);
3049 ok(hr == S_OK, "got 0x%08x\n", hr);
3050 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3051 ok(hr == S_OK, "got 0x%08x\n", hr);
3052 is_monospaced = IDWriteFontFace1_IsMonospacedFont(fontface1);
3053 ok(is_monospaced, "got %d\n", is_monospaced);
3054 IDWriteFontFace1_Release(fontface1);
3056 IDWriteFontFace_Release(fontface);
3057 IDWriteFont1_Release(font1);
3059 else
3060 win_skip("IsMonospacedFont() is not supported.\n");
3062 else
3063 skip("Courier New font not found.\n");
3065 IDWriteFontCollection_Release(collection);
3068 static void test_GetDesignGlyphAdvances(void)
3070 IDWriteFontFace1 *fontface1;
3071 IDWriteFontFace *fontface;
3072 IDWriteFactory *factory;
3073 IDWriteFontFile *file;
3074 WCHAR *path;
3075 HRESULT hr;
3077 factory = create_factory();
3079 path = create_testfontfile(test_fontfile);
3081 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3082 ok(hr == S_OK, "got 0x%08x\n", hr);
3084 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file,
3085 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3086 ok(hr == S_OK, "got 0x%08x\n", hr);
3087 IDWriteFontFile_Release(file);
3089 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3090 if (hr == S_OK) {
3091 UINT32 codepoint;
3092 UINT16 index;
3093 INT32 advance;
3095 codepoint = 'A';
3096 index = 0;
3097 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &index);
3098 ok(hr == S_OK, "got 0x%08x\n", hr);
3099 ok(index > 0, "got %u\n", index);
3101 advance = 0;
3102 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, FALSE);
3103 ok(hr == S_OK, "got 0x%08x\n", hr);
3104 ok(advance == 1000, "got %i\n", advance);
3106 advance = 0;
3107 hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &index, &advance, TRUE);
3108 ok(hr == S_OK, "got 0x%08x\n", hr);
3109 todo_wine
3110 ok(advance == 2048, "got %i\n", advance);
3112 IDWriteFontFace1_Release(fontface1);
3114 else
3115 win_skip("GetDesignGlyphAdvances() is not supported.\n");
3117 IDWriteFontFace_Release(fontface);
3118 IDWriteFactory_Release(factory);
3119 DELETE_FONTFILE(path);
3122 static void test_GetGlyphRunOutline(void)
3124 DWRITE_GLYPH_OFFSET offsets[2];
3125 IDWriteFactory *factory;
3126 IDWriteFontFile *file;
3127 IDWriteFontFace *face;
3128 UINT32 codepoint;
3129 FLOAT advances[2];
3130 UINT16 glyphs[2];
3131 WCHAR *path;
3132 HRESULT hr;
3134 path = create_testfontfile(test_fontfile);
3135 factory = create_factory();
3137 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3138 ok(hr == S_OK, "got 0x%08x\n",hr);
3140 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face);
3141 ok(hr == S_OK, "got 0x%08x\n", hr);
3142 IDWriteFontFile_Release(file);
3144 codepoint = 'A';
3145 glyphs[0] = 0;
3146 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
3147 ok(hr == S_OK, "got 0x%08x\n", hr);
3148 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
3149 glyphs[1] = glyphs[0];
3151 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, glyphs, advances, offsets, 1, FALSE, FALSE, NULL);
3152 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3154 hr = IDWriteFontFace_GetGlyphRunOutline(face, 2048.0, NULL, NULL, offsets, 1, FALSE, FALSE, &test_geomsink);
3155 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3157 advances[0] = 1.0;
3158 advances[1] = 0.0;
3160 offsets[0].advanceOffset = 1.0;
3161 offsets[0].ascenderOffset = 1.0;
3162 offsets[1].advanceOffset = 0.0;
3163 offsets[1].ascenderOffset = 0.0;
3165 /* default advances, no offsets */
3166 memset(g_startpoints, 0, sizeof(g_startpoints));
3167 g_startpoint_count = 0;
3168 SET_EXPECT(setfillmode);
3169 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, FALSE, &test_geomsink);
3170 ok(hr == S_OK, "got 0x%08x\n", hr);
3171 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
3172 if (g_startpoint_count == 2) {
3173 /* glyph advance of 500 is applied */
3174 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);
3175 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);
3177 CHECK_CALLED(setfillmode);
3179 /* default advances, no offsets, RTL */
3180 memset(g_startpoints, 0, sizeof(g_startpoints));
3181 g_startpoint_count = 0;
3182 SET_EXPECT(setfillmode);
3183 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 2, FALSE, TRUE, &test_geomsink);
3184 ok(hr == S_OK, "got 0x%08x\n", hr);
3185 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
3186 if (g_startpoint_count == 2) {
3187 /* advance is -500 now */
3188 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);
3189 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);
3191 CHECK_CALLED(setfillmode);
3193 /* default advances, additional offsets */
3194 memset(g_startpoints, 0, sizeof(g_startpoints));
3195 g_startpoint_count = 0;
3196 SET_EXPECT(setfillmode);
3197 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, FALSE, &test_geomsink);
3198 ok(hr == S_OK, "got 0x%08x\n", hr);
3199 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
3200 if (g_startpoint_count == 2) {
3201 /* offsets applied to first contour */
3202 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);
3203 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);
3205 CHECK_CALLED(setfillmode);
3207 /* default advances, additional offsets, RTL */
3208 memset(g_startpoints, 0, sizeof(g_startpoints));
3209 g_startpoint_count = 0;
3210 SET_EXPECT(setfillmode);
3211 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, offsets, 2, FALSE, TRUE, &test_geomsink);
3212 ok(hr == S_OK, "got 0x%08x\n", hr);
3213 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
3214 if (g_startpoint_count == 2) {
3215 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);
3216 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);
3218 CHECK_CALLED(setfillmode);
3220 /* custom advances and offsets, offset turns total advance value to zero */
3221 memset(g_startpoints, 0, sizeof(g_startpoints));
3222 g_startpoint_count = 0;
3223 SET_EXPECT(setfillmode);
3224 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, advances, offsets, 2, FALSE, FALSE, &test_geomsink);
3225 ok(hr == S_OK, "got 0x%08x\n", hr);
3226 ok(g_startpoint_count == 2, "got %d\n", g_startpoint_count);
3227 if (g_startpoint_count == 2) {
3228 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);
3229 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);
3231 CHECK_CALLED(setfillmode);
3233 /* 0 glyph count */
3234 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 0, FALSE, FALSE, &test_geomsink2);
3235 ok(hr == S_OK, "got 0x%08x\n", hr);
3237 IDWriteFactory_Release(factory);
3238 IDWriteFontFace_Release(face);
3239 DELETE_FONTFILE(path);
3241 /* space glyph */
3242 factory = create_factory();
3243 face = create_fontface(factory);
3245 codepoint = ' ';
3246 glyphs[0] = 0;
3247 hr = IDWriteFontFace_GetGlyphIndices(face, &codepoint, 1, glyphs);
3248 ok(hr == S_OK, "got 0x%08x\n", hr);
3249 ok(glyphs[0] > 0, "got %u\n", glyphs[0]);
3251 SET_EXPECT(setfillmode);
3252 hr = IDWriteFontFace_GetGlyphRunOutline(face, 1024.0, glyphs, NULL, NULL, 1, FALSE, FALSE, &test_geomsink2);
3253 ok(hr == S_OK, "got 0x%08x\n", hr);
3254 CHECK_CALLED(setfillmode);
3256 IDWriteFactory_Release(factory);
3257 IDWriteFontFace_Release(face);
3260 static void test_GetEudcFontCollection(void)
3262 IDWriteFontCollection *coll, *coll2;
3263 IDWriteFactory1 *factory1;
3264 IDWriteFactory *factory;
3265 HRESULT hr;
3267 factory = create_factory();
3269 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory1, (void**)&factory1);
3270 IDWriteFactory_Release(factory);
3271 if (hr != S_OK) {
3272 win_skip("GetEudcFontCollection() is not supported.\n");
3273 return;
3276 hr = IDWriteFactory1_GetEudcFontCollection(factory1, &coll, FALSE);
3277 ok(hr == S_OK, "got 0x%08x\n", hr);
3278 hr = IDWriteFactory1_GetEudcFontCollection(factory1, &coll2, FALSE);
3279 ok(hr == S_OK, "got 0x%08x\n", hr);
3280 ok(coll == coll2, "got %p, %p\n", coll, coll2);
3281 IDWriteFontCollection_Release(coll);
3282 IDWriteFontCollection_Release(coll2);
3284 IDWriteFactory1_Release(factory1);
3287 static void test_GetCaretMetrics(void)
3289 DWRITE_FONT_METRICS1 metrics;
3290 IDWriteFontFace1 *fontface1;
3291 DWRITE_CARET_METRICS caret;
3292 IDWriteFontFace *fontface;
3293 IDWriteFactory *factory;
3294 IDWriteFontFile *file;
3295 IDWriteFont *font;
3296 WCHAR *path;
3297 HRESULT hr;
3299 path = create_testfontfile(test_fontfile);
3300 factory = create_factory();
3302 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3303 ok(hr == S_OK, "got 0x%08x\n", hr);
3305 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3306 ok(hr == S_OK, "got 0x%08x\n", hr);
3307 IDWriteFontFile_Release(file);
3309 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3310 IDWriteFontFace_Release(fontface);
3311 if (hr != S_OK) {
3312 win_skip("GetCaretMetrics() is not supported.\n");
3313 IDWriteFactory_Release(factory);
3314 DELETE_FONTFILE(path);
3315 return;
3318 memset(&caret, 0xcc, sizeof(caret));
3319 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
3320 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
3321 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
3322 ok(caret.offset == 0, "got %d\n", caret.offset);
3323 IDWriteFontFace1_Release(fontface1);
3324 IDWriteFactory_Release(factory);
3326 /* now with Tahoma Normal */
3327 factory = create_factory();
3328 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
3329 hr = IDWriteFont_CreateFontFace(font, &fontface);
3330 ok(hr == S_OK, "got 0x%08x\n", hr);
3331 IDWriteFont_Release(font);
3332 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3333 ok(hr == S_OK, "got 0x%08x\n", hr);
3334 IDWriteFontFace_Release(fontface);
3336 memset(&caret, 0xcc, sizeof(caret));
3337 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
3338 ok(caret.slopeRise == 1, "got %d\n", caret.slopeRise);
3339 ok(caret.slopeRun == 0, "got %d\n", caret.slopeRun);
3340 ok(caret.offset == 0, "got %d\n", caret.offset);
3341 IDWriteFontFace1_Release(fontface1);
3343 /* simulated italic */
3344 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_ITALIC);
3345 hr = IDWriteFont_CreateFontFace(font, &fontface);
3346 ok(hr == S_OK, "got 0x%08x\n", hr);
3347 IDWriteFont_Release(font);
3348 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3349 ok(hr == S_OK, "got 0x%08x\n", hr);
3350 IDWriteFontFace_Release(fontface);
3352 IDWriteFontFace1_GetMetrics(fontface1, &metrics);
3354 memset(&caret, 0xcc, sizeof(caret));
3355 IDWriteFontFace1_GetCaretMetrics(fontface1, &caret);
3356 ok(caret.slopeRise == metrics.designUnitsPerEm, "got %d\n", caret.slopeRise);
3357 ok(caret.slopeRun > 0, "got %d\n", caret.slopeRun);
3358 ok(caret.offset == 0, "got %d\n", caret.offset);
3359 IDWriteFontFace1_Release(fontface1);
3361 IDWriteFactory_Release(factory);
3362 DELETE_FONTFILE(path);
3365 static void test_GetGlyphCount(void)
3367 IDWriteFontFace *fontface;
3368 IDWriteFactory *factory;
3369 IDWriteFontFile *file;
3370 UINT16 count;
3371 WCHAR *path;
3372 HRESULT hr;
3374 path = create_testfontfile(test_fontfile);
3375 factory = create_factory();
3377 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3378 ok(hr == S_OK, "got 0x%08x\n", hr);
3380 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3381 ok(hr == S_OK, "got 0x%08x\n", hr);
3382 IDWriteFontFile_Release(file);
3384 count = IDWriteFontFace_GetGlyphCount(fontface);
3385 ok(count == 7, "got %u\n", count);
3387 IDWriteFontFace_Release(fontface);
3388 IDWriteFactory_Release(factory);
3389 DELETE_FONTFILE(path);
3392 static void test_GetKerningPairAdjustments(void)
3394 IDWriteFontFace1 *fontface1;
3395 IDWriteFontFace *fontface;
3396 IDWriteFactory *factory;
3397 IDWriteFontFile *file;
3398 WCHAR *path;
3399 HRESULT hr;
3401 path = create_testfontfile(test_fontfile);
3402 factory = create_factory();
3404 hr = IDWriteFactory_CreateFontFileReference(factory, path, NULL, &file);
3405 ok(hr == S_OK, "got 0x%08x\n", hr);
3407 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface);
3408 ok(hr == S_OK, "got 0x%08x\n", hr);
3409 IDWriteFontFile_Release(file);
3411 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
3412 if (hr == S_OK) {
3413 INT32 adjustments[1];
3415 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 0, NULL, NULL);
3416 ok(hr == E_INVALIDARG || broken(hr == S_OK) /* win8 */, "got 0x%08x\n", hr);
3418 if (0) /* crashes on native */
3419 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, NULL);
3421 adjustments[0] = 1;
3422 hr = IDWriteFontFace1_GetKerningPairAdjustments(fontface1, 1, NULL, adjustments);
3423 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3424 ok(adjustments[0] == 0, "got %d\n", adjustments[0]);
3426 IDWriteFontFace1_Release(fontface1);
3428 else
3429 win_skip("GetKerningPairAdjustments() is not supported.\n");
3431 IDWriteFontFace_Release(fontface);
3432 IDWriteFactory_Release(factory);
3433 DELETE_FONTFILE(path);
3436 static void test_CreateRenderingParams(void)
3438 IDWriteRenderingParams2 *params2;
3439 IDWriteRenderingParams1 *params1;
3440 IDWriteRenderingParams *params;
3441 DWRITE_RENDERING_MODE mode;
3442 IDWriteFactory *factory;
3443 HRESULT hr;
3445 factory = create_factory();
3447 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
3448 DWRITE_RENDERING_MODE_DEFAULT, &params);
3449 ok(hr == S_OK, "got 0x%08x\n", hr);
3451 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams1, (void**)&params1);
3452 if (hr == S_OK) {
3453 FLOAT enhcontrast;
3455 /* test what enhanced contrast setting set by default to */
3456 enhcontrast = IDWriteRenderingParams1_GetGrayscaleEnhancedContrast(params1);
3457 ok(enhcontrast == 1.0, "got %.2f\n", enhcontrast);
3458 IDWriteRenderingParams1_Release(params1);
3460 hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)&params2);
3461 if (hr == S_OK) {
3462 DWRITE_GRID_FIT_MODE gridfit;
3464 /* default gridfit mode */
3465 gridfit = IDWriteRenderingParams2_GetGridFitMode(params2);
3466 ok(gridfit == DWRITE_GRID_FIT_MODE_DEFAULT, "got %d\n", gridfit);
3468 IDWriteRenderingParams2_Release(params2);
3470 else
3471 win_skip("IDWriteRenderingParams2 not supported.\n");
3473 else
3474 win_skip("IDWriteRenderingParams1 not supported.\n");
3476 IDWriteRenderingParams_Release(params);
3478 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
3479 ok(hr == S_OK, "got 0x%08x\n", hr);
3481 mode = IDWriteRenderingParams_GetRenderingMode(params);
3482 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
3483 IDWriteRenderingParams_Release(params);
3485 IDWriteFactory_Release(factory);
3488 static void test_CreateGlyphRunAnalysis(void)
3490 static const DWRITE_RENDERING_MODE rendermodes[] = {
3491 DWRITE_RENDERING_MODE_ALIASED,
3492 DWRITE_RENDERING_MODE_GDI_CLASSIC,
3493 DWRITE_RENDERING_MODE_GDI_NATURAL,
3494 DWRITE_RENDERING_MODE_NATURAL,
3495 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
3498 IDWriteGlyphRunAnalysis *analysis, *analysis2;
3499 IDWriteFactory *factory;
3500 DWRITE_GLYPH_RUN run;
3501 IDWriteFontFace *face;
3502 UINT16 glyph, glyphs[10];
3503 FLOAT advances[2];
3504 HRESULT hr;
3505 UINT32 ch;
3506 RECT rect, rect2;
3507 DWRITE_GLYPH_OFFSET offsets[2];
3508 DWRITE_GLYPH_METRICS metrics;
3509 DWRITE_FONT_METRICS fm;
3510 DWRITE_MATRIX m;
3511 int i;
3513 factory = create_factory();
3514 face = create_fontface(factory);
3516 ch = 'A';
3517 glyph = 0;
3518 hr = IDWriteFontFace_GetGlyphIndices(face, &ch, 1, &glyph);
3519 ok(hr == S_OK, "got 0x%08x\n", hr);
3520 ok(glyph > 0, "got %u\n", glyph);
3522 hr = IDWriteFontFace_GetDesignGlyphMetrics(face, &glyph, 1, &metrics, FALSE);
3523 ok(hr == S_OK, "got 0x%08x\n", hr);
3524 advances[0] = metrics.advanceWidth;
3526 offsets[0].advanceOffset = 0.0;
3527 offsets[0].ascenderOffset = 0.0;
3529 run.fontFace = face;
3530 run.fontEmSize = 24.0;
3531 run.glyphCount = 1;
3532 run.glyphIndices = &glyph;
3533 run.glyphAdvances = advances;
3534 run.glyphOffsets = offsets;
3535 run.isSideways = FALSE;
3536 run.bidiLevel = 0;
3538 /* zero ppdip */
3539 analysis = (void*)0xdeadbeef;
3540 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 0.0, NULL,
3541 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3542 0.0, 0.0, &analysis);
3543 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3544 ok(analysis == NULL, "got %p\n", analysis);
3546 /* negative ppdip */
3547 analysis = (void*)0xdeadbeef;
3548 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, -1.0, NULL,
3549 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3550 0.0, 0.0, &analysis);
3551 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3552 ok(analysis == NULL, "got %p\n", analysis);
3554 /* default mode is not allowed */
3555 analysis = (void*)0xdeadbeef;
3556 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3557 DWRITE_RENDERING_MODE_DEFAULT, DWRITE_MEASURING_MODE_NATURAL,
3558 0.0, 0.0, &analysis);
3559 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3560 ok(analysis == NULL, "got %p\n", analysis);
3562 /* outline too */
3563 analysis = (void*)0xdeadbeef;
3564 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3565 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_MEASURING_MODE_NATURAL,
3566 0.0, 0.0, &analysis);
3567 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3568 ok(analysis == NULL, "got %p\n", analysis);
3570 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3571 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3572 0.0, 0.0, &analysis);
3573 ok(hr == S_OK, "got 0x%08x\n", hr);
3575 /* invalid texture type */
3576 memset(&rect, 0xcc, sizeof(rect));
3577 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &rect);
3578 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3579 ok(rect.left == 0 && rect.right == 0 &&
3580 rect.top == 0 && rect.bottom == 0, "unexpected rect\n");
3582 /* check how origin affects bounds */
3583 memset(&rect, 0, sizeof(rect));
3584 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3585 ok(hr == S_OK, "got 0x%08x\n", hr);
3586 ok(!IsRectEmpty(&rect), "got empty rect\n");
3587 IDWriteGlyphRunAnalysis_Release(analysis);
3589 /* doubled ppdip */
3590 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
3591 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3592 0.0, 0.0, &analysis);
3593 ok(hr == S_OK, "got 0x%08x\n", hr);
3594 memset(&rect2, 0, sizeof(rect2));
3595 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
3596 ok(hr == S_OK, "got 0x%08x\n", hr);
3597 ok(rect.right - rect.left < rect2.right - rect2.left, "expected wider rect\n");
3598 ok(rect.bottom - rect.top < rect2.bottom - rect2.top, "expected taller rect\n");
3599 IDWriteGlyphRunAnalysis_Release(analysis);
3601 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3602 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3603 10.0, -5.0, &analysis);
3604 ok(hr == S_OK, "got 0x%08x\n", hr);
3606 memset(&rect2, 0, sizeof(rect2));
3607 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
3608 ok(hr == S_OK, "got 0x%08x\n", hr);
3609 ok(!IsRectEmpty(&rect2), "got empty rect\n");
3610 IDWriteGlyphRunAnalysis_Release(analysis);
3612 ok(!EqualRect(&rect, &rect2), "got equal bounds\n");
3613 OffsetRect(&rect, 10, -5);
3614 ok(EqualRect(&rect, &rect2), "got different bounds\n");
3616 for (i = 0; i < sizeof(rendermodes)/sizeof(rendermodes[0]); i++) {
3617 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3618 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
3619 0.0, 0.0, &analysis);
3620 ok(hr == S_OK, "got 0x%08x\n", hr);
3622 if (rendermodes[i] == DWRITE_RENDERING_MODE_ALIASED) {
3623 memset(&rect, 0, sizeof(rect));
3624 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3625 ok(hr == S_OK, "got 0x%08x\n", hr);
3626 ok(!IsRectEmpty(&rect), "got empty rect\n");
3628 rect.left = rect.top = 0;
3629 rect.bottom = rect.right = 1;
3630 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
3631 ok(hr == S_OK, "got 0x%08x\n", hr);
3632 ok(IsRectEmpty(&rect), "unexpected empty rect\n");
3634 else {
3635 rect.left = rect.top = 0;
3636 rect.bottom = rect.right = 1;
3637 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3638 ok(hr == S_OK, "got 0x%08x\n", hr);
3639 ok(IsRectEmpty(&rect), "got empty rect\n");
3641 memset(&rect, 0, sizeof(rect));
3642 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
3643 ok(hr == S_OK, "got 0x%08x\n", hr);
3644 ok(!IsRectEmpty(&rect), "got empty rect\n");
3647 IDWriteGlyphRunAnalysis_Release(analysis);
3650 IDWriteFontFace_GetMetrics(run.fontFace, &fm);
3652 /* check bbox for a single glyph run */
3653 for (run.fontEmSize = 1.0; run.fontEmSize <= 100.0; run.fontEmSize += 1.0) {
3654 DWRITE_GLYPH_METRICS gm;
3655 LONG bboxX, bboxY;
3657 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3658 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
3659 0.0, 0.0, &analysis);
3660 ok(hr == S_OK, "got 0x%08x\n", hr);
3662 memset(&rect, 0, sizeof(rect));
3663 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3664 ok(hr == S_OK, "got 0x%08x\n", hr);
3666 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(run.fontFace, run.fontEmSize, 1.0, NULL,
3667 DWRITE_MEASURING_MODE_GDI_CLASSIC, run.glyphIndices, 1, &gm, run.isSideways);
3668 ok(hr == S_OK, "got 0x%08x\n", hr);
3670 /* metrics are in design units */
3671 bboxX = (int)floorf((gm.advanceWidth - gm.leftSideBearing - gm.rightSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
3672 bboxY = (int)floorf((gm.advanceHeight - gm.topSideBearing - gm.bottomSideBearing) * run.fontEmSize / fm.designUnitsPerEm + 0.5f);
3674 rect.right -= rect.left;
3675 rect.bottom -= rect.top;
3676 ok(abs(bboxX - rect.right) <= 2, "%.0f: bbox width %d, from metrics %d\n", run.fontEmSize, rect.right, bboxX);
3677 ok(abs(bboxY - rect.bottom) <= 2, "%.0f: bbox height %d, from metrics %d\n", run.fontEmSize, rect.bottom, bboxY);
3679 IDWriteGlyphRunAnalysis_Release(analysis);
3682 /* without offsets */
3683 run.fontFace = face;
3684 run.fontEmSize = 24.0;
3685 run.glyphCount = 1;
3686 run.glyphIndices = &glyph;
3687 run.glyphAdvances = advances;
3688 run.glyphOffsets = NULL;
3689 run.isSideways = FALSE;
3690 run.bidiLevel = 0;
3692 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3693 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3694 0.0, 0.0, &analysis);
3695 ok(hr == S_OK, "got 0x%08x\n", hr);
3697 SetRectEmpty(&rect);
3698 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3699 ok(hr == S_OK, "got 0x%08x\n", hr);
3700 ok(!IsRectEmpty(&rect), "got empty bounds\n");
3702 IDWriteGlyphRunAnalysis_Release(analysis);
3704 /* without explicit advances */
3705 run.fontFace = face;
3706 run.fontEmSize = 24.0;
3707 run.glyphCount = 1;
3708 run.glyphIndices = &glyph;
3709 run.glyphAdvances = NULL;
3710 run.glyphOffsets = NULL;
3711 run.isSideways = FALSE;
3712 run.bidiLevel = 0;
3714 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3715 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3716 0.0, 0.0, &analysis);
3717 ok(hr == S_OK, "got 0x%08x\n", hr);
3719 SetRectEmpty(&rect);
3720 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3721 ok(hr == S_OK, "got 0x%08x\n", hr);
3722 ok(!IsRectEmpty(&rect), "got empty bounds\n");
3724 IDWriteGlyphRunAnalysis_Release(analysis);
3726 /* test that advances are scaled according to ppdip too */
3727 glyphs[0] = glyphs[1] = glyph;
3728 advances[0] = advances[1] = 100.0f;
3729 run.fontFace = face;
3730 run.fontEmSize = 24.0;
3731 run.glyphCount = 2;
3732 run.glyphIndices = glyphs;
3733 run.glyphAdvances = advances;
3734 run.glyphOffsets = NULL;
3735 run.isSideways = FALSE;
3736 run.bidiLevel = 0;
3738 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3739 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3740 0.0, 0.0, &analysis);
3741 ok(hr == S_OK, "got 0x%08x\n", hr);
3743 SetRectEmpty(&rect2);
3744 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
3745 ok(hr == S_OK, "got 0x%08x\n", hr);
3746 ok(!IsRectEmpty(&rect2), "got empty bounds\n");
3747 ok(!EqualRect(&rect, &rect2), "got wrong rect2\n");
3748 ok((rect2.right - rect.left) > advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
3749 IDWriteGlyphRunAnalysis_Release(analysis);
3751 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 2.0, NULL,
3752 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3753 0.0, 0.0, &analysis);
3754 ok(hr == S_OK, "got 0x%08x\n", hr);
3756 SetRectEmpty(&rect);
3757 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3758 ok(hr == S_OK, "got 0x%08x\n", hr);
3759 ok((rect.right - rect.left) > 2 * advances[0], "got rect width %d for advance %f\n", rect.right - rect.left, advances[0]);
3760 IDWriteGlyphRunAnalysis_Release(analysis);
3762 /* with scaling transform */
3763 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
3764 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3765 0.0, 0.0, &analysis);
3766 ok(hr == S_OK, "got 0x%08x\n", hr);
3768 SetRectEmpty(&rect);
3769 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect);
3770 ok(hr == S_OK, "got 0x%08x\n", hr);
3771 ok(!IsRectEmpty(&rect), "got rect width %d\n", rect.right - rect.left);
3772 IDWriteGlyphRunAnalysis_Release(analysis);
3774 memset(&m, 0, sizeof(m));
3775 m.m11 = 2.0;
3776 m.m22 = 1.0;
3777 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
3778 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3779 0.0, 0.0, &analysis);
3780 ok(hr == S_OK, "got 0x%08x\n", hr);
3782 SetRectEmpty(&rect2);
3783 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2);
3784 ok(hr == S_OK, "got 0x%08x\n", hr);
3785 ok((rect2.right - rect2.left) > (rect.right - rect.left), "got rect width %d\n", rect2.right - rect2.left);
3787 /* instances are not reused for same runs */
3788 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, &m,
3789 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL,
3790 0.0, 0.0, &analysis2);
3791 ok(hr == S_OK, "got 0x%08x\n", hr);
3792 ok(analysis2 != analysis, "got %p, previous instance %p\n", analysis2, analysis);
3793 IDWriteGlyphRunAnalysis_Release(analysis2);
3795 IDWriteGlyphRunAnalysis_Release(analysis);
3797 IDWriteFontFace_Release(face);
3798 IDWriteFactory_Release(factory);
3801 #define round(x) ((int)floor((x) + 0.5))
3803 struct VDMX_Header
3805 WORD version;
3806 WORD numRecs;
3807 WORD numRatios;
3810 struct VDMX_Ratio
3812 BYTE bCharSet;
3813 BYTE xRatio;
3814 BYTE yStartRatio;
3815 BYTE yEndRatio;
3818 struct VDMX_group
3820 WORD recs;
3821 BYTE startsz;
3822 BYTE endsz;
3825 struct VDMX_vTable
3827 WORD yPelHeight;
3828 SHORT yMax;
3829 SHORT yMin;
3832 #ifdef WORDS_BIGENDIAN
3833 #define GET_BE_WORD(x) (x)
3834 #else
3835 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
3836 #endif
3838 static const struct VDMX_group *find_vdmx_group(const struct VDMX_Header *hdr)
3840 WORD num_ratios, i, group_offset = 0;
3841 struct VDMX_Ratio *ratios = (struct VDMX_Ratio*)(hdr + 1);
3842 BYTE dev_x_ratio = 1, dev_y_ratio = 1;
3844 num_ratios = GET_BE_WORD(hdr->numRatios);
3846 for (i = 0; i < num_ratios; i++)
3848 if (!ratios[i].bCharSet) continue;
3850 if ((ratios[i].xRatio == 0 && ratios[i].yStartRatio == 0 &&
3851 ratios[i].yEndRatio == 0) ||
3852 (ratios[i].xRatio == dev_x_ratio && ratios[i].yStartRatio <= dev_y_ratio &&
3853 ratios[i].yEndRatio >= dev_y_ratio))
3855 group_offset = GET_BE_WORD(*((WORD *)(ratios + num_ratios) + i));
3856 break;
3859 if (group_offset)
3860 return (const struct VDMX_group *)((BYTE *)hdr + group_offset);
3861 return NULL;
3864 static BOOL get_vdmx_size(const struct VDMX_group *group, int emsize, int *a, int *d)
3866 WORD recs, i;
3867 const struct VDMX_vTable *tables;
3869 if (!group) return FALSE;
3871 recs = GET_BE_WORD(group->recs);
3872 if (emsize < group->startsz || emsize >= group->endsz) return FALSE;
3874 tables = (const struct VDMX_vTable *)(group + 1);
3875 for (i = 0; i < recs; i++)
3877 WORD ppem = GET_BE_WORD(tables[i].yPelHeight);
3878 if (ppem > emsize)
3880 /* FIXME: Supposed to interpolate */
3881 trace("FIXME interpolate %d\n", emsize);
3882 return FALSE;
3885 if (ppem == emsize)
3887 *a = (SHORT)GET_BE_WORD(tables[i].yMax);
3888 *d = -(SHORT)GET_BE_WORD(tables[i].yMin);
3889 return TRUE;
3892 return FALSE;
3895 static void test_metrics_cmp(FLOAT emsize, const DWRITE_FONT_METRICS *metrics, const DWRITE_FONT_METRICS1 *expected)
3897 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
3898 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
3899 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
3900 emsize, metrics->ascent, expected->ascent);
3901 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
3902 emsize, metrics->descent, expected->descent);
3903 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
3904 emsize, metrics->lineGap, expected->lineGap);
3905 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
3906 emsize, metrics->capHeight, expected->capHeight);
3907 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
3908 emsize, metrics->xHeight, expected->xHeight);
3909 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
3910 emsize, metrics->underlinePosition, expected->underlinePosition);
3911 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
3912 emsize, metrics->underlineThickness, expected->underlineThickness);
3913 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
3914 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
3915 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
3916 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
3919 static void test_metrics1_cmp(FLOAT emsize, const DWRITE_FONT_METRICS1 *metrics, const DWRITE_FONT_METRICS1 *expected)
3921 ok(metrics->designUnitsPerEm == expected->designUnitsPerEm, "%.2f: emsize: got %u expect %u\n",
3922 emsize, metrics->designUnitsPerEm, expected->designUnitsPerEm);
3923 ok(metrics->ascent == expected->ascent, "%.2f a: got %u expect %u\n",
3924 emsize, metrics->ascent, expected->ascent);
3925 ok(metrics->descent == expected->descent, "%.2f d: got %u expect %u\n",
3926 emsize, metrics->descent, expected->descent);
3927 ok(metrics->lineGap == expected->lineGap, "%.2f lg: got %d expect %d\n",
3928 emsize, metrics->lineGap, expected->lineGap);
3929 ok(metrics->capHeight == expected->capHeight, "%.2f capH: got %u expect %u\n",
3930 emsize, metrics->capHeight, expected->capHeight);
3931 ok(metrics->xHeight == expected->xHeight, "%.2f xH: got %u expect %u\n",
3932 emsize, metrics->xHeight, expected->xHeight);
3933 ok(metrics->underlinePosition == expected->underlinePosition, "%.2f ulP: got %d expect %d\n",
3934 emsize, metrics->underlinePosition, expected->underlinePosition);
3935 ok(metrics->underlineThickness == expected->underlineThickness, "%.2f ulTh: got %u expect %u\n",
3936 emsize, metrics->underlineThickness, expected->underlineThickness);
3937 ok(metrics->strikethroughPosition == expected->strikethroughPosition, "%.2f stP: got %d expect %d\n",
3938 emsize, metrics->strikethroughPosition, expected->strikethroughPosition);
3939 ok(metrics->strikethroughThickness == expected->strikethroughThickness, "%.2f stTh: got %u expect %u\n",
3940 emsize, metrics->strikethroughThickness, expected->strikethroughThickness);
3941 ok(metrics->glyphBoxLeft == expected->glyphBoxLeft, "%.2f box left: got %d expect %d\n",
3942 emsize, metrics->glyphBoxLeft, expected->glyphBoxLeft);
3943 if (0) { /* this is not consistent */
3944 ok(metrics->glyphBoxTop == expected->glyphBoxTop, "%.2f box top: got %d expect %d\n",
3945 emsize, metrics->glyphBoxTop, expected->glyphBoxTop);
3946 ok(metrics->glyphBoxRight == expected->glyphBoxRight, "%.2f box right: got %d expect %d\n",
3947 emsize, metrics->glyphBoxRight, expected->glyphBoxRight);
3949 ok(metrics->glyphBoxBottom == expected->glyphBoxBottom, "%.2f box bottom: got %d expect %d\n",
3950 emsize, metrics->glyphBoxBottom, expected->glyphBoxBottom);
3951 ok(metrics->subscriptPositionX == expected->subscriptPositionX, "%.2f subX: got %d expect %d\n",
3952 emsize, metrics->subscriptPositionX, expected->subscriptPositionX);
3953 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subY: got %d expect %d\n",
3954 emsize, metrics->subscriptPositionY, expected->subscriptPositionY);
3955 ok(metrics->subscriptSizeX == expected->subscriptSizeX, "%.2f subsizeX: got %d expect %d\n",
3956 emsize, metrics->subscriptSizeX, expected->subscriptSizeX);
3957 ok(metrics->subscriptPositionY == expected->subscriptPositionY, "%.2f subsizeY: got %d expect %d\n",
3958 emsize, metrics->subscriptSizeY, expected->subscriptSizeY);
3959 ok(metrics->superscriptPositionX == expected->superscriptPositionX, "%.2f supX: got %d expect %d\n",
3960 emsize, metrics->superscriptPositionX, expected->superscriptPositionX);
3961 if (0)
3962 ok(metrics->superscriptPositionY == expected->superscriptPositionY, "%.2f supY: got %d expect %d\n",
3963 emsize, metrics->superscriptPositionY, expected->superscriptPositionY);
3964 ok(metrics->superscriptSizeX == expected->superscriptSizeX, "%.2f supsizeX: got %d expect %d\n",
3965 emsize, metrics->superscriptSizeX, expected->superscriptSizeX);
3966 ok(metrics->superscriptSizeY == expected->superscriptSizeY, "%.2f supsizeY: got %d expect %d\n",
3967 emsize, metrics->superscriptSizeY, expected->superscriptSizeY);
3968 ok(metrics->hasTypographicMetrics == expected->hasTypographicMetrics, "%.2f hastypo: got %d expect %d\n",
3969 emsize, metrics->hasTypographicMetrics, expected->hasTypographicMetrics);
3972 struct compatmetrics_test {
3973 DWRITE_MATRIX m;
3974 FLOAT ppdip;
3975 FLOAT emsize;
3978 static struct compatmetrics_test compatmetrics_tests[] = {
3979 { { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0, 5.0 },
3980 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 1.0, 5.0 },
3981 { { 0.0, 0.0, 0.0, -1.0, 0.0, 0.0 }, 2.0, 5.0 },
3982 { { 0.0, 0.0, 0.0, 3.0, 0.0, 0.0 }, 2.0, 5.0 },
3983 { { 0.0, 0.0, 0.0, -3.0, 0.0, 0.0 }, 2.0, 5.0 },
3984 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 2.0, 5.0 },
3985 { { 1.0, 0.0, 0.0, 1.0, 5.0, 0.0 }, 2.0, 5.0 },
3986 { { 1.0, 0.0, 0.0, 1.0, 0.0, 5.0 }, 2.0, 5.0 },
3989 static void get_expected_metrics(IDWriteFontFace *fontface, struct compatmetrics_test *ptr,
3990 DWRITE_FONT_METRICS *expected)
3992 HRESULT hr;
3994 memset(expected, 0, sizeof(*expected));
3995 hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, ptr->ppdip * fabsf(ptr->m.m22) * ptr->emsize, 1.0, NULL, expected);
3996 ok(hr == S_OK, "got %08x\n", hr);
3999 static void test_GetGdiCompatibleMetrics_face(IDWriteFontFace *face)
4001 IDWriteFontFace1 *fontface1 = NULL;
4002 HRESULT hr;
4003 DWRITE_FONT_METRICS design_metrics, comp_metrics;
4004 DWRITE_FONT_METRICS1 design_metrics1, expected;
4005 FLOAT emsize, scale;
4006 int ascent, descent;
4007 const struct VDMX_Header *vdmx;
4008 UINT32 vdmx_len;
4009 void *vdmx_ctx;
4010 BOOL exists;
4011 const struct VDMX_group *vdmx_group = NULL;
4012 int i;
4014 hr = IDWriteFontFace_QueryInterface(face, &IID_IDWriteFontFace1, (void**)&fontface1);
4015 if (hr != S_OK)
4016 win_skip("gdi compatible DWRITE_FONT_METRICS1 are not supported.\n");
4018 if (fontface1) {
4019 IDWriteFontFace1_GetMetrics(fontface1, &design_metrics1);
4020 memcpy(&design_metrics, &design_metrics1, sizeof(design_metrics));
4022 else
4023 IDWriteFontFace_GetMetrics(face, &design_metrics);
4025 hr = IDWriteFontFace_TryGetFontTable(face, MS_VDMX_TAG, (const void **)&vdmx,
4026 &vdmx_len, &vdmx_ctx, &exists);
4027 if (hr != S_OK || !exists)
4028 vdmx = NULL;
4029 else
4030 vdmx_group = find_vdmx_group(vdmx);
4032 /* negative emsize */
4033 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4034 memset(&expected, 0, sizeof(expected));
4035 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, -10.0, 1.0, NULL, &comp_metrics);
4036 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4037 test_metrics_cmp(0.0, &comp_metrics, &expected);
4039 /* zero emsize */
4040 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4041 memset(&expected, 0, sizeof(expected));
4042 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 0.0, 1.0, NULL, &comp_metrics);
4043 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4044 test_metrics_cmp(0.0, &comp_metrics, &expected);
4046 /* zero pixels per dip */
4047 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4048 memset(&expected, 0, sizeof(expected));
4049 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, 0.0, NULL, &comp_metrics);
4050 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4051 test_metrics_cmp(5.0, &comp_metrics, &expected);
4053 memset(&comp_metrics, 0xcc, sizeof(comp_metrics));
4054 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, 5.0, -1.0, NULL, &comp_metrics);
4055 ok(hr == E_INVALIDARG, "got %08x\n", hr);
4056 test_metrics_cmp(5.0, &comp_metrics, &expected);
4058 for (i = 0; i < sizeof(compatmetrics_tests)/sizeof(compatmetrics_tests[0]); i++) {
4059 struct compatmetrics_test *ptr = &compatmetrics_tests[i];
4061 get_expected_metrics(face, ptr, (DWRITE_FONT_METRICS*)&expected);
4062 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, ptr->emsize, ptr->ppdip, &ptr->m, &comp_metrics);
4063 ok(hr == S_OK, "got %08x\n", hr);
4064 test_metrics_cmp(ptr->emsize, &comp_metrics, &expected);
4067 for (emsize = 5; emsize <= design_metrics.designUnitsPerEm; emsize++)
4069 DWRITE_FONT_METRICS1 comp_metrics1, expected;
4071 if (fontface1) {
4072 hr = IDWriteFontFace1_GetGdiCompatibleMetrics(fontface1, emsize, 1.0, NULL, &comp_metrics1);
4073 ok(hr == S_OK, "got %08x\n", hr);
4075 else {
4076 hr = IDWriteFontFace_GetGdiCompatibleMetrics(face, emsize, 1.0, NULL, &comp_metrics);
4077 ok(hr == S_OK, "got %08x\n", hr);
4080 scale = emsize / design_metrics.designUnitsPerEm;
4081 if (!get_vdmx_size(vdmx_group, emsize, &ascent, &descent))
4083 ascent = round(design_metrics.ascent * scale);
4084 descent = round(design_metrics.descent * scale);
4087 expected.designUnitsPerEm = design_metrics.designUnitsPerEm;
4088 expected.ascent = round(ascent / scale );
4089 expected.descent = round(descent / scale );
4090 expected.lineGap = round(round(design_metrics.lineGap * scale) / scale);
4091 expected.capHeight = round(round(design_metrics.capHeight * scale) / scale);
4092 expected.xHeight = round(round(design_metrics.xHeight * scale) / scale);
4093 expected.underlinePosition = round(round(design_metrics.underlinePosition * scale) / scale);
4094 expected.underlineThickness = round(round(design_metrics.underlineThickness * scale) / scale);
4095 expected.strikethroughPosition = round(round(design_metrics.strikethroughPosition * scale) / scale);
4096 expected.strikethroughThickness = round(round(design_metrics.strikethroughThickness * scale) / scale);
4098 if (fontface1) {
4099 expected.glyphBoxLeft = round(round(design_metrics1.glyphBoxLeft * scale) / scale);
4101 if (0) { /* those two fail on Tahoma and Win7 */
4102 expected.glyphBoxTop = round(round(design_metrics1.glyphBoxTop * scale) / scale);
4103 expected.glyphBoxRight = round(round(design_metrics1.glyphBoxRight * scale) / scale);
4105 expected.glyphBoxBottom = round(round(design_metrics1.glyphBoxBottom * scale) / scale);
4106 expected.subscriptPositionX = round(round(design_metrics1.subscriptPositionX * scale) / scale);
4107 expected.subscriptPositionY = round(round(design_metrics1.subscriptPositionY * scale) / scale);
4108 expected.subscriptSizeX = round(round(design_metrics1.subscriptSizeX * scale) / scale);
4109 expected.subscriptSizeY = round(round(design_metrics1.subscriptSizeY * scale) / scale);
4110 expected.superscriptPositionX = round(round(design_metrics1.superscriptPositionX * scale) / scale);
4111 if (0) /* this fails for 3 emsizes, Tahoma from [5, 2048] range */
4112 expected.superscriptPositionY = round(round(design_metrics1.superscriptPositionY * scale) / scale);
4113 expected.superscriptSizeX = round(round(design_metrics1.superscriptSizeX * scale) / scale);
4114 expected.superscriptSizeY = round(round(design_metrics1.superscriptSizeY * scale) / scale);
4115 expected.hasTypographicMetrics = design_metrics1.hasTypographicMetrics;
4117 test_metrics1_cmp(emsize, &comp_metrics1, &expected);
4119 else
4120 test_metrics_cmp(emsize, &comp_metrics, &expected);
4124 if (fontface1)
4125 IDWriteFontFace1_Release(fontface1);
4126 if (vdmx) IDWriteFontFace_ReleaseFontTable(face, vdmx_ctx);
4129 static void test_GetGdiCompatibleMetrics(void)
4131 IDWriteFactory *factory;
4132 IDWriteFont *font;
4133 IDWriteFontFace *fontface;
4134 HRESULT hr;
4136 factory = create_factory();
4138 font = get_font(factory, tahomaW, DWRITE_FONT_STYLE_NORMAL);
4139 hr = IDWriteFont_CreateFontFace(font, &fontface);
4140 ok(hr == S_OK, "got 0x%08x\n", hr);
4141 IDWriteFont_Release(font);
4142 test_GetGdiCompatibleMetrics_face(fontface);
4143 IDWriteFontFace_Release(fontface);
4145 font = get_font(factory, arialW, DWRITE_FONT_STYLE_NORMAL);
4146 if (!font)
4147 skip("Skipping tests with Arial\n");
4148 else
4150 hr = IDWriteFont_CreateFontFace(font, &fontface);
4151 ok(hr == S_OK, "got 0x%08x\n", hr);
4152 IDWriteFont_Release(font);
4154 test_GetGdiCompatibleMetrics_face(fontface);
4155 IDWriteFontFace_Release(fontface);
4158 IDWriteFactory_Release(factory);
4161 static void test_GetPanose(void)
4163 IDWriteFactory *factory;
4164 IDWriteFont1 *font1;
4165 IDWriteFont *font;
4166 HRESULT hr;
4168 factory = create_factory();
4169 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
4171 hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFont1, (void**)&font1);
4172 IDWriteFont_Release(font);
4173 if (hr == S_OK) {
4174 DWRITE_PANOSE panose;
4176 if (0) /* crashes on native */
4177 IDWriteFont1_GetPanose(font1, NULL);
4179 memset(&panose, 0, sizeof(panose));
4180 IDWriteFont1_GetPanose(font1, &panose);
4181 ok(panose.familyKind == DWRITE_PANOSE_FAMILY_TEXT_DISPLAY,
4182 "got %u\n", panose.familyKind);
4183 ok(panose.text.serifStyle == DWRITE_PANOSE_SERIF_STYLE_NORMAL_SANS,
4184 "got %u\n", panose.text.serifStyle);
4185 ok(panose.text.weight == DWRITE_PANOSE_WEIGHT_MEDIUM,
4186 "got %u\n", panose.text.weight);
4187 ok(panose.text.proportion == DWRITE_PANOSE_PROPORTION_EVEN_WIDTH,
4188 "got %u\n", panose.text.proportion);
4189 ok(panose.text.contrast == DWRITE_PANOSE_CONTRAST_VERY_LOW,
4190 "got %u\n", panose.text.contrast);
4191 ok(panose.text.strokeVariation == DWRITE_PANOSE_STROKE_VARIATION_GRADUAL_VERTICAL,
4192 "got %u\n", panose.text.strokeVariation);
4193 ok(panose.text.armStyle == DWRITE_PANOSE_ARM_STYLE_STRAIGHT_ARMS_VERTICAL,
4194 "got %u\n", panose.text.armStyle);
4195 ok(panose.text.letterform == DWRITE_PANOSE_LETTERFORM_NORMAL_BOXED,
4196 "got %u\n", panose.text.letterform);
4197 ok(panose.text.midline == DWRITE_PANOSE_MIDLINE_STANDARD_TRIMMED,
4198 "got %u\n", panose.text.midline);
4199 ok(panose.text.xHeight == DWRITE_PANOSE_XHEIGHT_CONSTANT_LARGE,
4200 "got %u\n", panose.text.xHeight);
4202 IDWriteFont1_Release(font1);
4204 else
4205 win_skip("GetPanose() is not supported.\n");
4207 IDWriteFactory_Release(factory);
4210 static INT32 get_gdi_font_advance(HDC hdc, FLOAT emsize)
4212 LOGFONTW logfont;
4213 HFONT hfont;
4214 BOOL ret;
4215 ABC abc;
4217 memset(&logfont, 0, sizeof(logfont));
4218 logfont.lfHeight = (LONG)-emsize;
4219 logfont.lfWeight = FW_NORMAL;
4220 logfont.lfQuality = CLEARTYPE_QUALITY;
4221 lstrcpyW(logfont.lfFaceName, tahomaW);
4223 hfont = CreateFontIndirectW(&logfont);
4224 SelectObject(hdc, hfont);
4226 ret = GetCharABCWidthsW(hdc, 'A', 'A', &abc);
4227 ok(ret, "got %d\n", ret);
4229 DeleteObject(hfont);
4231 return abc.abcA + abc.abcB + abc.abcC;
4234 static void test_GetGdiCompatibleGlyphAdvances(void)
4236 IDWriteFontFace1 *fontface1;
4237 IDWriteFontFace *fontface;
4238 IDWriteFactory *factory;
4239 IDWriteFont *font;
4240 HRESULT hr;
4241 HDC hdc;
4242 UINT32 codepoint;
4243 UINT16 glyph;
4244 FLOAT emsize;
4245 DWRITE_FONT_METRICS1 fm;
4246 INT32 advance;
4248 factory = create_factory();
4249 font = get_tahoma_instance(factory, DWRITE_FONT_STYLE_NORMAL);
4251 hr = IDWriteFont_CreateFontFace(font, &fontface);
4252 ok(hr == S_OK, "got 0x%08x\n", hr);
4253 IDWriteFont_Release(font);
4255 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4256 IDWriteFontFace_Release(fontface);
4258 if (hr != S_OK) {
4259 IDWriteFactory_Release(factory);
4260 win_skip("GetGdiCompatibleGlyphAdvances() is not supported\n");
4261 return;
4264 codepoint = 'A';
4265 glyph = 0;
4266 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &codepoint, 1, &glyph);
4267 ok(hr == S_OK, "got 0x%08x\n", hr);
4268 ok(glyph > 0, "got %u\n", glyph);
4270 /* zero emsize */
4271 advance = 1;
4272 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 0.0,
4273 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
4274 ok(hr == S_OK, "got 0x%08x\n", hr);
4275 ok(advance == 0, "got %d\n", advance);
4277 /* negative emsize */
4278 advance = 1;
4279 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, -1.0,
4280 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
4281 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4282 ok(advance == 0, "got %d\n", advance);
4284 /* zero ppdip */
4285 advance = 1;
4286 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
4287 0.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
4288 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4289 ok(advance == 0, "got %d\n", advance);
4291 /* negative ppdip */
4292 advance = 1;
4293 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, 1.0,
4294 -1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
4295 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4296 ok(advance == 0, "got %d\n", advance);
4298 IDWriteFontFace1_GetMetrics(fontface1, &fm);
4300 hdc = CreateCompatibleDC(0);
4302 for (emsize = 1.0; emsize <= fm.designUnitsPerEm; emsize += 1.0) {
4303 INT32 gdi_advance;
4305 gdi_advance = get_gdi_font_advance(hdc, emsize);
4306 hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emsize,
4307 1.0, NULL, FALSE, FALSE, 1, &glyph, &advance);
4308 ok(hr == S_OK, "got 0x%08x\n", hr);
4310 /* advance is in design units */
4311 advance = (int)floorf(emsize * advance / fm.designUnitsPerEm + 0.5f);
4312 ok((advance - gdi_advance) <= 2, "%.0f: got advance %d, expected %d\n", emsize, advance, gdi_advance);
4315 DeleteObject(hdc);
4317 IDWriteFactory_Release(factory);
4320 static WORD get_gasp_flags(IDWriteFontFace *fontface, FLOAT emsize, FLOAT ppdip)
4322 WORD num_recs, version;
4323 const WORD *ptr;
4324 WORD flags = 0;
4325 UINT32 size;
4326 BOOL exists;
4327 void *ctxt;
4328 HRESULT hr;
4330 emsize *= ppdip;
4332 exists = FALSE;
4333 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GASP_TAG,
4334 (const void**)&ptr, &size, &ctxt, &exists);
4335 ok(hr == S_OK, "got 0x%08x\n", hr);
4337 if (!exists)
4338 goto done;
4340 version = GET_BE_WORD( *ptr++ );
4341 num_recs = GET_BE_WORD( *ptr++ );
4342 if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) {
4343 ok(0, "unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs);
4344 goto done;
4347 while (num_recs--)
4349 flags = GET_BE_WORD( *(ptr + 1) );
4350 if (emsize <= GET_BE_WORD( *ptr )) break;
4351 ptr += 2;
4354 done:
4355 IDWriteFontFace_ReleaseFontTable(fontface, ctxt);
4356 return flags;
4359 #define GASP_GRIDFIT 0x0001
4360 #define GASP_DOGRAY 0x0002
4361 #define GASP_SYMMETRIC_GRIDFIT 0x0004
4362 #define GASP_SYMMETRIC_SMOOTHING 0x0008
4364 static BOOL g_is_vista;
4365 static DWRITE_RENDERING_MODE get_expected_rendering_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
4366 DWRITE_OUTLINE_THRESHOLD threshold)
4368 static const FLOAT aa_threshold = 100.0f;
4369 static const FLOAT a_threshold = 350.0f;
4370 static const FLOAT naturalemsize = 20.0f;
4371 FLOAT v;
4373 /* outline threshold */
4374 if (g_is_vista)
4375 v = mode == DWRITE_MEASURING_MODE_NATURAL ? aa_threshold : a_threshold;
4376 else
4377 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
4379 if (emsize >= v)
4380 return DWRITE_RENDERING_MODE_OUTLINE;
4382 switch (mode)
4384 case DWRITE_MEASURING_MODE_NATURAL:
4385 if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (emsize <= naturalemsize))
4386 return DWRITE_RENDERING_MODE_NATURAL;
4387 else
4388 return DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC;
4389 case DWRITE_MEASURING_MODE_GDI_CLASSIC:
4390 return DWRITE_RENDERING_MODE_GDI_CLASSIC;
4391 case DWRITE_MEASURING_MODE_GDI_NATURAL:
4392 return DWRITE_RENDERING_MODE_GDI_NATURAL;
4393 default:
4397 /* should be unreachable */
4398 return DWRITE_RENDERING_MODE_DEFAULT;
4401 static DWRITE_GRID_FIT_MODE get_expected_gridfit_mode(FLOAT emsize, WORD gasp, DWRITE_MEASURING_MODE mode,
4402 DWRITE_OUTLINE_THRESHOLD threshold)
4404 static const FLOAT aa_threshold = 100.0f;
4405 static const FLOAT a_threshold = 350.0f;
4406 FLOAT v;
4408 v = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? aa_threshold : a_threshold;
4409 if (emsize >= v)
4410 return DWRITE_GRID_FIT_MODE_DISABLED;
4412 if (mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || mode == DWRITE_MEASURING_MODE_GDI_NATURAL)
4413 return DWRITE_GRID_FIT_MODE_ENABLED;
4415 return (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED;
4418 struct recommendedmode_test
4420 DWRITE_MEASURING_MODE measuring;
4421 DWRITE_OUTLINE_THRESHOLD threshold;
4424 static const struct recommendedmode_test recmode_tests[] = {
4425 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
4426 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
4427 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
4430 static const struct recommendedmode_test recmode_tests1[] = {
4431 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
4432 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
4433 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED },
4434 { DWRITE_MEASURING_MODE_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
4435 { DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_OUTLINE_THRESHOLD_ALIASED },
4436 { DWRITE_MEASURING_MODE_GDI_NATURAL, DWRITE_OUTLINE_THRESHOLD_ALIASED },
4439 static void test_GetRecommendedRenderingMode(void)
4441 IDWriteRenderingParams *params;
4442 IDWriteFontFace2 *fontface2;
4443 IDWriteFontFace1 *fontface1;
4444 IDWriteFontFace *fontface;
4445 DWRITE_RENDERING_MODE mode;
4446 IDWriteFactory *factory;
4447 FLOAT emsize;
4448 HRESULT hr;
4450 factory = create_factory();
4451 fontface = create_fontface(factory);
4453 fontface1 = NULL;
4454 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
4455 if (hr != S_OK)
4456 win_skip("IDWriteFontFace1::GetRecommendedRenderingMode() is not supported.\n");
4458 fontface2 = NULL;
4459 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
4460 if (hr != S_OK)
4461 win_skip("IDWriteFontFace2::GetRecommendedRenderingMode() is not supported.\n");
4463 if (0) /* crashes on native */
4464 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
4465 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, NULL);
4467 mode = 10;
4468 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0,
4469 DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode);
4470 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4471 ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode);
4473 hr = IDWriteFactory_CreateRenderingParams(factory, &params);
4474 ok(hr == S_OK, "got 0x%08x\n", hr);
4476 /* detect old dwrite version, that is using higher threshold value */
4477 g_is_vista = fontface1 == NULL;
4479 for (emsize = 1.0; emsize < 500.0; emsize += 1.0) {
4480 DWRITE_RENDERING_MODE expected;
4481 FLOAT ppdip;
4482 WORD gasp;
4483 int i;
4485 for (i = 0; i < sizeof(recmode_tests)/sizeof(recmode_tests[0]); i++) {
4486 ppdip = 1.0f;
4487 mode = 10;
4488 gasp = get_gasp_flags(fontface, emsize, ppdip);
4489 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
4490 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
4491 ok(hr == S_OK, "got 0x%08x\n", hr);
4492 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
4494 /* some ppdip variants */
4495 ppdip = 0.5f;
4496 mode = 10;
4497 gasp = get_gasp_flags(fontface, emsize, ppdip);
4498 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
4499 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
4500 ok(hr == S_OK, "got 0x%08x\n", hr);
4501 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
4503 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
4504 Win8 and Win10 handle this as expected. */
4505 if (emsize > 20.0f) {
4506 ppdip = 1.5f;
4507 mode = 10;
4508 gasp = get_gasp_flags(fontface, emsize, ppdip);
4509 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
4510 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
4511 ok(hr == S_OK, "got 0x%08x\n", hr);
4512 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
4514 ppdip = 2.0f;
4515 mode = 10;
4516 gasp = get_gasp_flags(fontface, emsize, ppdip);
4517 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold);
4518 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, ppdip, recmode_tests[i].measuring, params, &mode);
4519 ok(hr == S_OK, "got 0x%08x\n", hr);
4520 ok(mode == expected, "%.2f/%d: got %d, ppdip %f, flags 0x%04x, expected %d\n", emsize, i, mode, ppdip, gasp, expected);
4524 /* IDWriteFontFace1 offers another variant of this method */
4525 if (fontface1) {
4526 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
4527 FLOAT dpi;
4529 ppdip = 1.0f;
4530 dpi = 96.0f * ppdip;
4531 mode = 10;
4532 gasp = get_gasp_flags(fontface, emsize, ppdip);
4533 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
4534 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
4535 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
4536 ok(hr == S_OK, "got 0x%08x\n", hr);
4537 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
4539 /* Only test larger sizes to workaround Win7 differences, where unscaled natural emsize threshold is used;
4540 Win8 and Win10 handle this as expected. */
4541 if (emsize > 20.0f) {
4542 ppdip = 2.0f;
4543 dpi = 96.0f * ppdip;
4544 mode = 10;
4545 gasp = get_gasp_flags(fontface, emsize, ppdip);
4546 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
4547 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
4548 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
4549 ok(hr == S_OK, "got 0x%08x\n", hr);
4550 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
4552 ppdip = 0.5f;
4553 dpi = 96.0f * ppdip;
4554 mode = 10;
4555 gasp = get_gasp_flags(fontface, emsize, ppdip);
4556 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
4557 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi,
4558 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
4559 ok(hr == S_OK, "got 0x%08x\n", hr);
4560 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
4562 /* try different dpis for X and Y direction */
4563 ppdip = 1.0f;
4564 dpi = 96.0f * ppdip;
4565 mode = 10;
4566 gasp = get_gasp_flags(fontface, emsize, ppdip);
4567 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
4568 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
4569 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
4570 ok(hr == S_OK, "got 0x%08x\n", hr);
4571 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
4573 ppdip = 1.0f;
4574 dpi = 96.0f * ppdip;
4575 mode = 10;
4576 gasp = get_gasp_flags(fontface, emsize, ppdip);
4577 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
4578 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
4579 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
4580 ok(hr == S_OK, "got 0x%08x\n", hr);
4581 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
4583 ppdip = 2.0f;
4584 dpi = 96.0f * ppdip;
4585 mode = 10;
4586 gasp = get_gasp_flags(fontface, emsize, ppdip);
4587 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
4588 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi * 0.5f, dpi,
4589 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
4590 ok(hr == S_OK, "got 0x%08x\n", hr);
4591 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
4593 ppdip = 2.0f;
4594 dpi = 96.0f * ppdip;
4595 mode = 10;
4596 gasp = get_gasp_flags(fontface, emsize, ppdip);
4597 expected = get_expected_rendering_mode(emsize * ppdip, gasp, recmode_tests1[i].measuring, recmode_tests1[i].threshold);
4598 hr = IDWriteFontFace1_GetRecommendedRenderingMode(fontface1, emsize, dpi, dpi * 0.5f,
4599 NULL, FALSE, recmode_tests1[i].threshold, recmode_tests1[i].measuring, &mode);
4600 ok(hr == S_OK, "got 0x%08x\n", hr);
4601 ok(mode == expected, "%.2f/%d: got %d, dpi %f, flags 0x%04x, expected %d\n", emsize, i, mode, dpi, gasp, expected);
4606 /* IDWriteFontFace2 - another one */
4607 if (fontface2) {
4608 DWRITE_GRID_FIT_MODE gridfit, expected_gridfit;
4610 gasp = get_gasp_flags(fontface, emsize, 1.0f);
4611 for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) {
4612 mode = 10;
4613 expected = get_expected_rendering_mode(emsize, gasp, recmode_tests1[0].measuring, recmode_tests1[0].threshold);
4614 expected_gridfit = get_expected_gridfit_mode(emsize, gasp, recmode_tests1[0].measuring, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED);
4615 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, emsize, 96.0, 96.0,
4616 NULL, FALSE, recmode_tests1[0].threshold, recmode_tests1[0].measuring, params, &mode, &gridfit);
4617 ok(hr == S_OK, "got 0x%08x\n", hr);
4618 ok(mode == expected, "%.2f: got %d, flags 0x%04x, expected %d\n", emsize, mode, gasp, expected);
4619 ok(gridfit == expected_gridfit, "%.2f/%d: gridfit: got %d, flags 0x%04x, expected %d\n", emsize, i, gridfit,
4620 gasp, expected_gridfit);
4625 IDWriteRenderingParams_Release(params);
4627 /* test how parameters override returned modes */
4628 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 1.0, 0.0, 0.0, DWRITE_PIXEL_GEOMETRY_FLAT,
4629 DWRITE_RENDERING_MODE_GDI_CLASSIC, &params);
4630 ok(hr == S_OK, "got 0x%08x\n", hr);
4632 mode = 10;
4633 hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode);
4634 ok(hr == S_OK, "got 0x%08x\n", hr);
4635 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
4637 IDWriteRenderingParams_Release(params);
4639 if (fontface2) {
4640 IDWriteRenderingParams2 *params2;
4641 IDWriteFactory2 *factory2;
4642 DWRITE_GRID_FIT_MODE gridfit;
4644 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
4645 ok(hr == S_OK, "got 0x%08x\n", hr);
4647 hr = IDWriteFactory2_CreateCustomRenderingParams(factory2, 1.0, 0.0, 0.0, 0.5, DWRITE_PIXEL_GEOMETRY_FLAT,
4648 DWRITE_RENDERING_MODE_OUTLINE, DWRITE_GRID_FIT_MODE_ENABLED, &params2);
4649 ok(hr == S_OK, "got 0x%08x\n", hr);
4651 mode = 10;
4652 gridfit = 10;
4653 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
4654 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
4655 NULL, &mode, &gridfit);
4656 ok(hr == S_OK, "got 0x%08x\n", hr);
4657 ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode);
4658 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
4660 mode = 10;
4661 gridfit = 10;
4662 hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0,
4663 NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
4664 (IDWriteRenderingParams*)params2, &mode, &gridfit);
4665 ok(hr == S_OK, "got 0x%08x\n", hr);
4666 ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode);
4667 ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit);
4669 IDWriteRenderingParams2_Release(params2);
4670 IDWriteFactory2_Release(factory2);
4673 if (fontface2)
4674 IDWriteFontFace2_Release(fontface2);
4675 if (fontface1)
4676 IDWriteFontFace1_Release(fontface1);
4677 IDWriteFontFace_Release(fontface);
4678 IDWriteFactory_Release(factory);
4681 static inline BOOL float_eq(FLOAT left, FLOAT right)
4683 int x = *(int *)&left;
4684 int y = *(int *)&right;
4686 if (x < 0)
4687 x = INT_MIN - x;
4688 if (y < 0)
4689 y = INT_MIN - y;
4691 return abs(x - y) <= 8;
4694 static void test_GetAlphaBlendParams(void)
4696 static const DWRITE_RENDERING_MODE rendermodes[] = {
4697 DWRITE_RENDERING_MODE_ALIASED,
4698 DWRITE_RENDERING_MODE_GDI_CLASSIC,
4699 DWRITE_RENDERING_MODE_GDI_NATURAL,
4700 DWRITE_RENDERING_MODE_NATURAL,
4701 DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC,
4704 IDWriteGlyphRunAnalysis *analysis;
4705 FLOAT gamma, contrast, ctlevel;
4706 IDWriteRenderingParams *params;
4707 DWRITE_GLYPH_METRICS metrics;
4708 DWRITE_GLYPH_OFFSET offset;
4709 IDWriteFontFace *fontface;
4710 IDWriteFactory *factory;
4711 DWRITE_GLYPH_RUN run;
4712 FLOAT advance, expected_gdi_gamma;
4713 UINT value = 0;
4714 UINT16 glyph;
4715 UINT32 ch, i;
4716 HRESULT hr;
4717 BOOL ret;
4719 factory = create_factory();
4720 fontface = create_fontface(factory);
4722 ch = 'A';
4723 glyph = 0;
4724 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
4725 ok(hr == S_OK, "got 0x%08x\n", hr);
4726 ok(glyph > 0, "got %u\n", glyph);
4728 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
4729 ok(hr == S_OK, "got 0x%08x\n", hr);
4730 advance = metrics.advanceWidth;
4732 offset.advanceOffset = 0.0;
4733 offset.ascenderOffset = 0.0;
4735 run.fontFace = fontface;
4736 run.fontEmSize = 24.0;
4737 run.glyphCount = 1;
4738 run.glyphIndices = &glyph;
4739 run.glyphAdvances = &advance;
4740 run.glyphOffsets = &offset;
4741 run.isSideways = FALSE;
4742 run.bidiLevel = 0;
4744 hr = IDWriteFactory_CreateCustomRenderingParams(factory, 0.9, 0.3, 0.1, DWRITE_PIXEL_GEOMETRY_RGB,
4745 DWRITE_RENDERING_MODE_DEFAULT, &params);
4746 ok(hr == S_OK, "got 0x%08x\n", hr);
4748 value = 0;
4749 ret = SystemParametersInfoW(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0);
4750 ok(ret, "got %d\n", ret);
4751 expected_gdi_gamma = (FLOAT)(value / 1000.0);
4753 for (i = 0; i < sizeof(rendermodes)/sizeof(rendermodes[0]); i++) {
4754 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4755 rendermodes[i], DWRITE_MEASURING_MODE_NATURAL,
4756 0.0, 0.0, &analysis);
4757 ok(hr == S_OK, "got 0x%08x\n", hr);
4759 gamma = contrast = ctlevel = -1.0;
4760 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, NULL, &gamma, &contrast, &ctlevel);
4761 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4762 ok(gamma == -1.0, "got %.2f\n", gamma);
4763 ok(contrast == -1.0, "got %.2f\n", contrast);
4764 ok(ctlevel == -1.0, "got %.2f\n", ctlevel);
4766 gamma = contrast = ctlevel = -1.0;
4767 hr = IDWriteGlyphRunAnalysis_GetAlphaBlendParams(analysis, params, &gamma, &contrast, &ctlevel);
4768 ok(hr == S_OK, "got 0x%08x\n", hr);
4770 if (rendermodes[i] == DWRITE_RENDERING_MODE_GDI_CLASSIC || rendermodes[i] == DWRITE_RENDERING_MODE_GDI_NATURAL) {
4771 ok(float_eq(gamma, expected_gdi_gamma), "got %.2f, expected %.2f\n", gamma, expected_gdi_gamma);
4772 ok(contrast == 0.0f, "got %.2f\n", contrast);
4773 ok(ctlevel == 1.0f, "got %.2f\n", ctlevel);
4775 else {
4776 ok(gamma == 0.9f, "got %.2f\n", gamma);
4777 ok(contrast == 0.3f, "got %.2f\n", contrast);
4778 ok(ctlevel == 0.1f, "got %.2f\n", ctlevel);
4781 IDWriteGlyphRunAnalysis_Release(analysis);
4784 IDWriteRenderingParams_Release(params);
4785 IDWriteFontFace_Release(fontface);
4786 IDWriteFactory_Release(factory);
4789 static void test_CreateAlphaTexture(void)
4791 IDWriteGlyphRunAnalysis *analysis;
4792 DWRITE_GLYPH_METRICS metrics;
4793 DWRITE_GLYPH_OFFSET offset;
4794 IDWriteFontFace *fontface;
4795 IDWriteFactory *factory;
4796 DWRITE_GLYPH_RUN run;
4797 UINT32 ch, size;
4798 BYTE buff[1024];
4799 RECT bounds, r;
4800 FLOAT advance;
4801 UINT16 glyph;
4802 HRESULT hr;
4804 factory = create_factory();
4805 fontface = create_fontface(factory);
4807 ch = 'A';
4808 glyph = 0;
4809 hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, &glyph);
4810 ok(hr == S_OK, "got 0x%08x\n", hr);
4811 ok(glyph > 0, "got %u\n", glyph);
4813 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, &glyph, 1, &metrics, FALSE);
4814 ok(hr == S_OK, "got 0x%08x\n", hr);
4815 advance = metrics.advanceWidth;
4817 offset.advanceOffset = 0.0;
4818 offset.ascenderOffset = 0.0;
4820 run.fontFace = fontface;
4821 run.fontEmSize = 24.0;
4822 run.glyphCount = 1;
4823 run.glyphIndices = &glyph;
4824 run.glyphAdvances = &advance;
4825 run.glyphOffsets = &offset;
4826 run.isSideways = FALSE;
4827 run.bidiLevel = 0;
4829 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4830 DWRITE_RENDERING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
4831 0.0, 0.0, &analysis);
4832 ok(hr == S_OK, "got 0x%08x\n", hr);
4834 SetRectEmpty(&bounds);
4835 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
4836 ok(hr == S_OK, "got 0x%08x\n", hr);
4837 ok(!IsRectEmpty(&bounds), "got empty rect\n");
4838 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top)*3;
4839 ok(sizeof(buff) >= size, "required %u\n", size);
4841 /* invalid type value */
4842 memset(buff, 0xcf, sizeof(buff));
4843 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1+1, &bounds, buff, sizeof(buff));
4844 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4845 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
4847 memset(buff, 0xcf, sizeof(buff));
4848 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, 2);
4849 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4850 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
4852 /* vista version allows texture type mismatch, mark it broken for now */
4853 memset(buff, 0xcf, sizeof(buff));
4854 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, sizeof(buff));
4855 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
4856 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
4858 memset(buff, 0xcf, sizeof(buff));
4859 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, size-1);
4860 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4861 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
4863 IDWriteGlyphRunAnalysis_Release(analysis);
4865 hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL,
4866 DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC,
4867 0.0, 0.0, &analysis);
4868 ok(hr == S_OK, "got 0x%08x\n", hr);
4870 SetRectEmpty(&bounds);
4871 hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds);
4872 ok(hr == S_OK, "got 0x%08x\n", hr);
4873 ok(!IsRectEmpty(&bounds), "got empty rect\n");
4874 size = (bounds.right - bounds.left)*(bounds.bottom - bounds.top);
4875 ok(sizeof(buff) >= size, "required %u\n", size);
4877 memset(buff, 0xcf, sizeof(buff));
4878 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, sizeof(buff));
4879 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4880 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
4882 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, NULL, sizeof(buff));
4883 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4885 memset(buff, 0xcf, sizeof(buff));
4886 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, NULL, buff, 0);
4887 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4888 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
4890 /* buffer size is not enough */
4891 memset(buff, 0xcf, sizeof(buff));
4892 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &bounds, buff, size-1);
4893 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4894 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
4896 /* request texture for rectangle that doesn't intersect */
4897 memset(buff, 0xcf, sizeof(buff));
4898 r = bounds;
4899 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
4900 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
4901 ok(hr == S_OK, "got 0x%08x\n", hr);
4902 ok(buff[0] == 0, "got %1x\n", buff[0]);
4904 memset(buff, 0xcf, sizeof(buff));
4905 r = bounds;
4906 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
4907 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, sizeof(buff));
4908 ok(hr == S_OK, "got 0x%08x\n", hr);
4909 ok(buff[0] == 0, "got %1x\n", buff[0]);
4911 /* request texture for rectangle that doesn't intersect, small buffer */
4912 memset(buff, 0xcf, sizeof(buff));
4913 r = bounds;
4914 OffsetRect(&r, (bounds.right - bounds.left)*2, 0);
4915 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_ALIASED_1x1, &r, buff, size-1);
4916 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4917 ok(buff[0] == 0xcf, "got %1x\n", buff[0]);
4919 /* vista version allows texture type mismatch, mark it broken for now */
4920 memset(buff, 0xcf, sizeof(buff));
4921 hr = IDWriteGlyphRunAnalysis_CreateAlphaTexture(analysis, DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, buff, sizeof(buff));
4922 ok(hr == DWRITE_E_UNSUPPORTEDOPERATION || broken(hr == S_OK), "got 0x%08x\n", hr);
4923 ok(buff[0] == 0xcf || broken(buff[0] == 0), "got %1x\n", buff[0]);
4925 IDWriteGlyphRunAnalysis_Release(analysis);
4926 IDWriteFontFace_Release(fontface);
4927 IDWriteFactory_Release(factory);
4930 static void test_IsSymbolFont(void)
4932 static const WCHAR symbolW[] = {'S','y','m','b','o','l',0};
4933 IDWriteFontCollection *collection;
4934 IDWriteFontFace *fontface;
4935 IDWriteFactory *factory;
4936 IDWriteFont *font;
4937 HRESULT hr;
4938 BOOL ret;
4940 factory = create_factory();
4942 /* Tahoma */
4943 fontface = create_fontface(factory);
4944 ret = IDWriteFontFace_IsSymbolFont(fontface);
4945 ok(!ret, "got %d\n", ret);
4947 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
4948 ok(hr == S_OK, "got 0x%08x\n", hr);
4950 hr = IDWriteFontCollection_GetFontFromFontFace(collection, fontface, &font);
4951 ok(hr == S_OK, "got 0x%08x\n", hr);
4953 ret = IDWriteFont_IsSymbolFont(font);
4954 ok(!ret, "got %d\n", ret);
4956 IDWriteFontCollection_Release(collection);
4957 IDWriteFont_Release(font);
4958 IDWriteFontFace_Release(fontface);
4960 /* Symbol */
4961 font = get_font(factory, symbolW, DWRITE_FONT_STYLE_NORMAL);
4962 ret = IDWriteFont_IsSymbolFont(font);
4963 ok(ret, "got %d\n", ret);
4965 hr = IDWriteFont_CreateFontFace(font, &fontface);
4966 ok(hr == S_OK, "got 0x%08x\n", hr);
4967 ret = IDWriteFontFace_IsSymbolFont(fontface);
4968 ok(ret, "got %d\n", ret);
4969 IDWriteFont_Release(font);
4971 IDWriteFactory_Release(factory);
4974 struct CPAL_Header_0
4976 USHORT version;
4977 USHORT numPaletteEntries;
4978 USHORT numPalette;
4979 USHORT numColorRecords;
4980 ULONG offsetFirstColorRecord;
4981 USHORT colorRecordIndices[1];
4984 static void test_GetPaletteEntries(void)
4986 IDWriteFontFace2 *fontface2;
4987 IDWriteFontFace *fontface;
4988 IDWriteFactory *factory;
4989 IDWriteFont *font;
4990 DWRITE_COLOR_F color;
4991 UINT32 palettecount, entrycount, size, colorrecords;
4992 void *ctxt;
4993 const struct CPAL_Header_0 *cpal_header;
4994 HRESULT hr;
4995 BOOL exists;
4997 factory = create_factory();
4999 /* Tahoma, no color support */
5000 fontface = create_fontface(factory);
5001 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
5002 IDWriteFontFace_Release(fontface);
5003 if (hr != S_OK) {
5004 IDWriteFactory_Release(factory);
5005 win_skip("GetPaletteEntries() is not supported.\n");
5006 return;
5009 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 1, &color);
5010 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
5011 IDWriteFontFace2_Release(fontface2);
5013 /* Segoe UI Emoji, with color support */
5014 font = get_font(factory, emojiW, DWRITE_FONT_STYLE_NORMAL);
5015 if (!font) {
5016 IDWriteFactory_Release(factory);
5017 skip("Segoe UI Emoji font not found.\n");
5018 return;
5021 hr = IDWriteFont_CreateFontFace(font, &fontface);
5022 ok(hr == S_OK, "got 0x%08x\n", hr);
5023 IDWriteFont_Release(font);
5025 hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2);
5026 ok(hr == S_OK, "got 0x%08x\n", hr);
5027 IDWriteFontFace_Release(fontface);
5029 palettecount = IDWriteFontFace2_GetColorPaletteCount(fontface2);
5030 ok(palettecount >= 1, "got %u\n", palettecount);
5032 entrycount = IDWriteFontFace2_GetPaletteEntryCount(fontface2);
5033 ok(entrycount >= 1, "got %u\n", entrycount);
5035 exists = FALSE;
5036 hr = IDWriteFontFace2_TryGetFontTable(fontface2, MS_CPAL_TAG, (const void**)&cpal_header, &size, &ctxt, &exists);
5037 ok(hr == S_OK, "got 0x%08x\n", hr);
5038 ok(exists, "got %d\n", exists);
5039 colorrecords = GET_BE_WORD(cpal_header->numColorRecords);
5040 ok(colorrecords >= 1, "got %u\n", colorrecords);
5042 /* invalid palette index */
5043 color.r = color.g = color.b = color.a = 123.0;
5044 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, palettecount, 0, 1, &color);
5045 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
5046 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
5047 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
5049 /* invalid entry index */
5050 color.r = color.g = color.b = color.a = 123.0;
5051 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount, 1, &color);
5052 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5053 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
5054 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
5056 color.r = color.g = color.b = color.a = 123.0;
5057 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, entrycount - 1, 1, &color);
5058 ok(hr == S_OK, "got 0x%08x\n", hr);
5059 ok(color.r != 123.0 && color.g != 123.0 && color.b != 123.0 && color.a != 123.0,
5060 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
5062 /* zero return length */
5063 color.r = color.g = color.b = color.a = 123.0;
5064 hr = IDWriteFontFace2_GetPaletteEntries(fontface2, 0, 0, 0, &color);
5065 ok(hr == S_OK, "got 0x%08x\n", hr);
5066 ok(color.r == 123.0 && color.g == 123.0 && color.b == 123.0 && color.a == 123.0,
5067 "got wrong color %.2fx%.2fx%.2fx%.2f\n", color.r, color.g, color.b, color.a);
5069 IDWriteFontFace2_Release(fontface2);
5070 IDWriteFactory_Release(factory);
5073 static void test_TranslateColorGlyphRun(void)
5075 IDWriteColorGlyphRunEnumerator *layers;
5076 const DWRITE_COLOR_GLYPH_RUN *colorrun;
5077 IDWriteFontFace *fontface;
5078 IDWriteFactory2 *factory2;
5079 IDWriteFactory *factory;
5080 DWRITE_GLYPH_RUN run;
5081 UINT32 codepoints[2];
5082 IDWriteFont *font;
5083 UINT16 glyphs[2];
5084 BOOL hasrun;
5085 HRESULT hr;
5087 factory = create_factory();
5089 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
5090 IDWriteFactory_Release(factory);
5091 if (hr != S_OK) {
5092 win_skip("TranslateColorGlyphRun() is not supported.\n");
5093 return;
5096 /* Tahoma, no color support */
5097 fontface = create_fontface((IDWriteFactory*)factory2);
5099 codepoints[0] = 'A';
5100 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
5101 ok(hr == S_OK, "got 0x%08x\n", hr);
5103 run.fontFace = fontface;
5104 run.fontEmSize = 20.0f;
5105 run.glyphCount = 1;
5106 run.glyphIndices = glyphs;
5107 run.glyphAdvances = NULL;
5108 run.glyphOffsets = NULL;
5109 run.isSideways = FALSE;
5110 run.bidiLevel = 0;
5112 layers = (void*)0xdeadbeef;
5113 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
5114 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
5115 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
5116 ok(layers == NULL, "got %p\n", layers);
5117 IDWriteFontFace_Release(fontface);
5119 /* Segoe UI Emoji, with color support */
5120 font = get_font((IDWriteFactory*)factory2, emojiW, DWRITE_FONT_STYLE_NORMAL);
5121 if (!font) {
5122 IDWriteFactory2_Release(factory2);
5123 skip("Segoe UI Emoji font not found.\n");
5124 return;
5127 hr = IDWriteFont_CreateFontFace(font, &fontface);
5128 ok(hr == S_OK, "got 0x%08x\n", hr);
5129 IDWriteFont_Release(font);
5131 codepoints[0] = 0x26c4;
5132 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
5133 ok(hr == S_OK, "got 0x%08x\n", hr);
5135 run.fontFace = fontface;
5137 layers = NULL;
5138 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
5139 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
5140 ok(hr == S_OK, "got 0x%08x\n", hr);
5141 ok(layers != NULL, "got %p\n", layers);
5143 while (1) {
5144 hasrun = FALSE;
5145 hr = IDWriteColorGlyphRunEnumerator_MoveNext(layers, &hasrun);
5146 todo_wine
5147 ok(hr == S_OK, "got 0x%08x\n", hr);
5149 if (!hasrun)
5150 break;
5153 /* iterated all way through */
5154 hr = IDWriteColorGlyphRunEnumerator_GetCurrentRun(layers, &colorrun);
5155 todo_wine
5156 ok(hr == E_NOT_VALID_STATE, "got 0x%08x\n", hr);
5158 IDWriteColorGlyphRunEnumerator_Release(layers);
5160 /* color font, glyph without color info */
5161 codepoints[0] = 'A';
5162 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 1, glyphs);
5163 ok(hr == S_OK, "got 0x%08x\n", hr);
5165 layers = (void*)0xdeadbeef;
5166 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
5167 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
5168 todo_wine {
5169 ok(hr == DWRITE_E_NOCOLOR, "got 0x%08x\n", hr);
5170 ok(layers == NULL, "got %p\n", layers);
5172 /* one glyph with, one without */
5173 codepoints[0] = 'A';
5174 codepoints[1] = 0x26c4;
5176 hr = IDWriteFontFace_GetGlyphIndices(fontface, codepoints, 2, glyphs);
5177 ok(hr == S_OK, "got 0x%08x\n", hr);
5179 run.glyphCount = 2;
5181 layers = NULL;
5182 hr = IDWriteFactory2_TranslateColorGlyphRun(factory2, 0.0, 0.0, &run, NULL,
5183 DWRITE_MEASURING_MODE_NATURAL, NULL, 0, &layers);
5184 ok(hr == S_OK, "got 0x%08x\n", hr);
5185 ok(layers != NULL, "got %p\n", layers);
5186 IDWriteColorGlyphRunEnumerator_Release(layers);
5188 IDWriteFontFace_Release(fontface);
5189 IDWriteFactory2_Release(factory2);
5192 START_TEST(font)
5194 IDWriteFactory *factory;
5196 if (!(factory = create_factory())) {
5197 win_skip("failed to create factory\n");
5198 return;
5201 test_CreateFontFromLOGFONT();
5202 test_CreateBitmapRenderTarget();
5203 test_GetFontFamily();
5204 test_GetFamilyNames();
5205 test_CreateFontFace();
5206 test_GetMetrics();
5207 test_system_fontcollection();
5208 test_ConvertFontFaceToLOGFONT();
5209 test_CustomFontCollection();
5210 test_CreateCustomFontFileReference();
5211 test_CreateFontFileReference();
5212 test_shared_isolated();
5213 test_GetUnicodeRanges();
5214 test_GetFontFromFontFace();
5215 test_GetFirstMatchingFont();
5216 test_GetInformationalStrings();
5217 test_GetGdiInterop();
5218 test_CreateFontFaceFromHdc();
5219 test_GetSimulations();
5220 test_GetFaceNames();
5221 test_TryGetFontTable();
5222 test_ConvertFontToLOGFONT();
5223 test_CreateStreamFromKey();
5224 test_ReadFileFragment();
5225 test_GetDesignGlyphMetrics();
5226 test_GetDesignGlyphAdvances();
5227 test_IsMonospacedFont();
5228 test_GetGlyphRunOutline();
5229 test_GetEudcFontCollection();
5230 test_GetCaretMetrics();
5231 test_GetGlyphCount();
5232 test_GetKerningPairAdjustments();
5233 test_CreateRenderingParams();
5234 test_CreateGlyphRunAnalysis();
5235 test_GetGdiCompatibleMetrics();
5236 test_GetPanose();
5237 test_GetGdiCompatibleGlyphAdvances();
5238 test_GetRecommendedRenderingMode();
5239 test_GetAlphaBlendParams();
5240 test_CreateAlphaTexture();
5241 test_IsSymbolFont();
5242 test_GetPaletteEntries();
5243 test_TranslateColorGlyphRun();
5245 IDWriteFactory_Release(factory);