d3drm: Fix normals computation and add according tests.
[wine] / dlls / dwrite / tests / font.c
1 /*
2  *    Font related tests
3  *
4  * Copyright 2012 Nikolay Sivov for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include "windows.h"
24
25 #include "initguid.h"
26 #include "dwrite.h"
27
28 #include "wine/test.h"
29
30 #define EXPECT_HR(hr,hr_exp) \
31     ok(hr == hr_exp, "got 0x%08x, expected 0x%08x\n", hr, hr_exp)
32
33 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
34 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
35 {
36     ULONG rc = IUnknown_AddRef(obj);
37     IUnknown_Release(obj);
38     ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
39 }
40
41 static IDWriteFactory *factory;
42
43 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
44
45 static void test_CreateFontFromLOGFONT(void)
46 {
47     static const WCHAR tahomaspW[] = {'T','a','h','o','m','a',' ',0};
48     static const WCHAR blahW[]  = {'B','l','a','h','!',0};
49     IDWriteGdiInterop *interop;
50     DWRITE_FONT_WEIGHT weight;
51     DWRITE_FONT_STYLE style;
52     IDWriteFont *font;
53     LOGFONTW logfont;
54     LONG weights[][2] = {
55         {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL},
56         {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD},
57         {  0, DWRITE_FONT_WEIGHT_NORMAL},
58         { 50, DWRITE_FONT_WEIGHT_NORMAL},
59         {150, DWRITE_FONT_WEIGHT_NORMAL},
60         {250, DWRITE_FONT_WEIGHT_NORMAL},
61         {350, DWRITE_FONT_WEIGHT_NORMAL},
62         {450, DWRITE_FONT_WEIGHT_NORMAL},
63         {650, DWRITE_FONT_WEIGHT_BOLD},
64         {750, DWRITE_FONT_WEIGHT_BOLD},
65         {850, DWRITE_FONT_WEIGHT_BOLD},
66         {950, DWRITE_FONT_WEIGHT_BOLD},
67         {960, DWRITE_FONT_WEIGHT_BOLD},
68     };
69     OUTLINETEXTMETRICW otm;
70     HRESULT hr;
71     BOOL ret;
72     HDC hdc;
73     HFONT hfont;
74     int i;
75     UINT r;
76
77     hr = IDWriteFactory_GetGdiInterop(factory, &interop);
78     EXPECT_HR(hr, S_OK);
79
80 if (0)
81     /* null out parameter crashes this call */
82     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL);
83
84     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font);
85     EXPECT_HR(hr, E_INVALIDARG);
86
87     memset(&logfont, 0, sizeof(logfont));
88     logfont.lfHeight = 12;
89     logfont.lfWidth  = 12;
90     logfont.lfWeight = FW_NORMAL;
91     logfont.lfItalic = 1;
92     lstrcpyW(logfont.lfFaceName, tahomaW);
93
94     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
95     EXPECT_HR(hr, S_OK);
96
97     hfont = CreateFontIndirectW(&logfont);
98     hdc = CreateCompatibleDC(0);
99     SelectObject(hdc, hfont);
100
101     otm.otmSize = sizeof(otm);
102     r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
103     ok(r, "got %d\n", r);
104     DeleteDC(hdc);
105     DeleteObject(hfont);
106
107     /* now check properties */
108     weight = IDWriteFont_GetWeight(font);
109     ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
110
111     style = IDWriteFont_GetStyle(font);
112 todo_wine {
113     ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
114     ok(otm.otmfsSelection == 1, "got 0x%08x\n", otm.otmfsSelection);
115 }
116     ret = IDWriteFont_IsSymbolFont(font);
117     ok(!ret, "got %d\n", ret);
118
119     IDWriteFont_Release(font);
120
121     /* weight values */
122     for (i = 0; i < sizeof(weights)/(2*sizeof(LONG)); i++)
123     {
124         memset(&logfont, 0, sizeof(logfont));
125         logfont.lfHeight = 12;
126         logfont.lfWidth  = 12;
127         logfont.lfWeight = weights[i][0];
128         lstrcpyW(logfont.lfFaceName, tahomaW);
129
130         hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
131         EXPECT_HR(hr, S_OK);
132
133         weight = IDWriteFont_GetWeight(font);
134         ok(weight == weights[i][1],
135             "%d: got %d, expected %d\n", i, weight, weights[i][1]);
136         IDWriteFont_Release(font);
137     }
138
139     /* weight not from enum */
140     memset(&logfont, 0, sizeof(logfont));
141     logfont.lfHeight = 12;
142     logfont.lfWidth  = 12;
143     logfont.lfWeight = 550;
144     lstrcpyW(logfont.lfFaceName, tahomaW);
145
146     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
147     EXPECT_HR(hr, S_OK);
148
149     weight = IDWriteFont_GetWeight(font);
150     ok(weight == DWRITE_FONT_WEIGHT_NORMAL || broken(weight == DWRITE_FONT_WEIGHT_BOLD) /* win7 w/o SP */,
151         "got %d\n", weight);
152     IDWriteFont_Release(font);
153
154     /* empty or nonexistent face name */
155     memset(&logfont, 0, sizeof(logfont));
156     logfont.lfHeight = 12;
157     logfont.lfWidth  = 12;
158     logfont.lfWeight = FW_NORMAL;
159     lstrcpyW(logfont.lfFaceName, blahW);
160
161     font = (void*)0xdeadbeef;
162     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
163 todo_wine {
164     EXPECT_HR(hr, DWRITE_E_NOFONT);
165     ok(font == NULL, "got %p\n", font);
166     if(font) IDWriteFont_Release(font);
167 }
168
169     memset(&logfont, 0, sizeof(logfont));
170     logfont.lfHeight = 12;
171     logfont.lfWidth  = 12;
172     logfont.lfWeight = FW_NORMAL;
173     lstrcpyW(logfont.lfFaceName, tahomaspW);
174
175     font = (void*)0xdeadbeef;
176     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
177 todo_wine {
178     EXPECT_HR(hr, DWRITE_E_NOFONT);
179     ok(font == NULL, "got %p\n", font);
180     if(font) IDWriteFont_Release(font);
181 }
182
183     memset(&logfont, 0, sizeof(logfont));
184     logfont.lfHeight = 12;
185     logfont.lfWidth  = 12;
186     logfont.lfWeight = FW_NORMAL;
187
188     font = (void*)0xdeadbeef;
189     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
190 todo_wine {
191     EXPECT_HR(hr, DWRITE_E_NOFONT);
192     ok(font == NULL, "got %p\n", font);
193     if(font) IDWriteFont_Release(font);
194 }
195
196     IDWriteGdiInterop_Release(interop);
197 }
198
199 static void test_CreateBitmapRenderTarget(void)
200 {
201     IDWriteBitmapRenderTarget *target, *target2;
202     IDWriteGdiInterop *interop;
203     DIBSECTION ds;
204     HBITMAP hbm;
205     HRESULT hr;
206     SIZE size;
207     HDC hdc;
208     int ret;
209
210     hr = IDWriteFactory_GetGdiInterop(factory, &interop);
211     EXPECT_HR(hr, S_OK);
212
213     target = NULL;
214     hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target);
215     EXPECT_HR(hr, S_OK);
216
217 if (0) /* crashes on native */
218     hr = IDWriteBitmapRenderTarget_GetSize(target, NULL);
219
220     size.cx = size.cy = -1;
221     hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
222     EXPECT_HR(hr, S_OK);
223     ok(size.cx == 0, "got %d\n", size.cx);
224     ok(size.cy == 0, "got %d\n", size.cy);
225
226     target2 = NULL;
227     hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 0, 0, &target2);
228     EXPECT_HR(hr, S_OK);
229     ok(target != target2, "got %p, %p\n", target2, target);
230     IDWriteBitmapRenderTarget_Release(target2);
231
232     hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
233     ok(hdc != NULL, "got %p\n", hdc);
234
235     hbm = GetCurrentObject(hdc, OBJ_BITMAP);
236     ok(hbm != NULL, "got %p\n", hbm);
237
238     /* check DIB properties */
239     ret = GetObjectW(hbm, sizeof(ds), &ds);
240     ok(ret == sizeof(BITMAP), "got %d\n", ret);
241     ok(ds.dsBm.bmWidth == 1, "got %d\n", ds.dsBm.bmWidth);
242     ok(ds.dsBm.bmHeight == 1, "got %d\n", ds.dsBm.bmHeight);
243     ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
244     ok(ds.dsBm.bmBitsPixel == 1, "got %d\n", ds.dsBm.bmBitsPixel);
245     ok(!ds.dsBm.bmBits, "got %p\n", ds.dsBm.bmBits);
246
247     IDWriteBitmapRenderTarget_Release(target);
248
249     hbm = GetCurrentObject(hdc, OBJ_BITMAP);
250     ok(!hbm, "got %p\n", hbm);
251
252     target = NULL;
253     hr = IDWriteGdiInterop_CreateBitmapRenderTarget(interop, NULL, 10, 5, &target);
254     EXPECT_HR(hr, S_OK);
255
256     hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target);
257     ok(hdc != NULL, "got %p\n", hdc);
258
259     hbm = GetCurrentObject(hdc, OBJ_BITMAP);
260     ok(hbm != NULL, "got %p\n", hbm);
261
262     /* check DIB properties */
263     ret = GetObjectW(hbm, sizeof(ds), &ds);
264     ok(ret == sizeof(ds), "got %d\n", ret);
265     ok(ds.dsBm.bmWidth == 10, "got %d\n", ds.dsBm.bmWidth);
266     ok(ds.dsBm.bmHeight == 5, "got %d\n", ds.dsBm.bmHeight);
267     ok(ds.dsBm.bmPlanes == 1, "got %d\n", ds.dsBm.bmPlanes);
268     ok(ds.dsBm.bmBitsPixel == 32, "got %d\n", ds.dsBm.bmBitsPixel);
269     ok(ds.dsBm.bmBits != NULL, "got %p\n", ds.dsBm.bmBits);
270
271     size.cx = size.cy = -1;
272     hr = IDWriteBitmapRenderTarget_GetSize(target, &size);
273     EXPECT_HR(hr, S_OK);
274     ok(size.cx == 10, "got %d\n", size.cx);
275     ok(size.cy == 5, "got %d\n", size.cy);
276
277     IDWriteBitmapRenderTarget_Release(target);
278
279     IDWriteGdiInterop_Release(interop);
280 }
281
282 static void test_GetFontFamily(void)
283 {
284     IDWriteFontFamily *family, *family2;
285     IDWriteGdiInterop *interop;
286     IDWriteFont *font;
287     LOGFONTW logfont;
288     HRESULT hr;
289
290     hr = IDWriteFactory_GetGdiInterop(factory, &interop);
291     EXPECT_HR(hr, S_OK);
292
293     memset(&logfont, 0, sizeof(logfont));
294     logfont.lfHeight = 12;
295     logfont.lfWidth  = 12;
296     logfont.lfWeight = FW_NORMAL;
297     logfont.lfItalic = 1;
298     lstrcpyW(logfont.lfFaceName, tahomaW);
299
300     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
301     EXPECT_HR(hr, S_OK);
302
303 if (0) /* crashes on native */
304     hr = IDWriteFont_GetFontFamily(font, NULL);
305
306     EXPECT_REF(font, 1);
307     hr = IDWriteFont_GetFontFamily(font, &family);
308     EXPECT_HR(hr, S_OK);
309     EXPECT_REF(font, 1);
310     EXPECT_REF(family, 2);
311
312     hr = IDWriteFont_GetFontFamily(font, &family2);
313     EXPECT_HR(hr, S_OK);
314     ok(family2 == family, "got %p, previous %p\n", family2, family);
315     EXPECT_REF(font, 1);
316     EXPECT_REF(family, 3);
317     IDWriteFontFamily_Release(family2);
318
319     hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFamily, (void**)&family2);
320     EXPECT_HR(hr, E_NOINTERFACE);
321     ok(family2 == NULL, "got %p\n", family2);
322
323     IDWriteFontFamily_Release(family);
324     IDWriteFont_Release(font);
325     IDWriteGdiInterop_Release(interop);
326 }
327
328 static void test_GetFamilyNames(void)
329 {
330     IDWriteFontFamily *family;
331     IDWriteLocalizedStrings *names, *names2;
332     IDWriteGdiInterop *interop;
333     IDWriteFont *font;
334     LOGFONTW logfont;
335     WCHAR buffer[100];
336     HRESULT hr;
337     UINT32 len;
338
339     hr = IDWriteFactory_GetGdiInterop(factory, &interop);
340     EXPECT_HR(hr, S_OK);
341
342     memset(&logfont, 0, sizeof(logfont));
343     logfont.lfHeight = 12;
344     logfont.lfWidth  = 12;
345     logfont.lfWeight = FW_NORMAL;
346     logfont.lfItalic = 1;
347     lstrcpyW(logfont.lfFaceName, tahomaW);
348
349     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
350     EXPECT_HR(hr, S_OK);
351
352     hr = IDWriteFont_GetFontFamily(font, &family);
353     EXPECT_HR(hr, S_OK);
354
355 if (0) /* crashes on native */
356     hr = IDWriteFontFamily_GetFamilyNames(family, NULL);
357
358     hr = IDWriteFontFamily_GetFamilyNames(family, &names);
359     ok(hr == S_OK, "got 0x%08x\n", hr);
360     EXPECT_REF(names, 1);
361
362     hr = IDWriteFontFamily_GetFamilyNames(family, &names2);
363     ok(hr == S_OK, "got 0x%08x\n", hr);
364     EXPECT_REF(names2, 1);
365     ok(names != names2, "got %p, was %p\n", names2, names);
366
367     IDWriteLocalizedStrings_Release(names2);
368
369     /* GetStringLength */
370 if (0) /* crashes on native */
371     hr = IDWriteLocalizedStrings_GetStringLength(names, 0, NULL);
372
373     len = 100;
374     hr = IDWriteLocalizedStrings_GetStringLength(names, 10, &len);
375     ok(hr == E_FAIL, "got 0x%08x\n", hr);
376     ok(len == (UINT32)-1, "got %u\n", len);
377
378     len = 0;
379     hr = IDWriteLocalizedStrings_GetStringLength(names, 0, &len);
380     ok(hr == S_OK, "got 0x%08x\n", hr);
381     ok(len > 0, "got %u\n", len);
382
383     /* GetString */
384     hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 0);
385     ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
386
387     hr = IDWriteLocalizedStrings_GetString(names, 10, NULL, 0);
388     ok(hr == E_FAIL, "got 0x%08x\n", hr);
389
390 if (0)
391     hr = IDWriteLocalizedStrings_GetString(names, 0, NULL, 100);
392
393     buffer[0] = 1;
394     hr = IDWriteLocalizedStrings_GetString(names, 10, buffer, 100);
395     ok(hr == E_FAIL, "got 0x%08x\n", hr);
396     ok(buffer[0] == 0, "got %x\n", buffer[0]);
397
398     buffer[0] = 1;
399     hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len-1);
400     ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
401     ok(buffer[0] == 0, "got %x\n", buffer[0]);
402
403     buffer[0] = 1;
404     hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len);
405     ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
406     ok(buffer[0] == 0, "got %x\n", buffer[0]);
407
408     buffer[0] = 0;
409     hr = IDWriteLocalizedStrings_GetString(names, 0, buffer, len+1);
410     ok(hr == S_OK, "got 0x%08x\n", hr);
411     ok(buffer[0] != 0, "got %x\n", buffer[0]);
412
413     IDWriteLocalizedStrings_Release(names);
414
415     IDWriteFontFamily_Release(family);
416     IDWriteFont_Release(font);
417     IDWriteGdiInterop_Release(interop);
418 }
419
420 static void test_CreateFontFace(void)
421 {
422     IDWriteFontFace *fontface, *fontface2;
423     IDWriteGdiInterop *interop;
424     IDWriteFont *font;
425     LOGFONTW logfont;
426     HRESULT hr;
427
428     hr = IDWriteFactory_GetGdiInterop(factory, &interop);
429     EXPECT_HR(hr, S_OK);
430
431     memset(&logfont, 0, sizeof(logfont));
432     logfont.lfHeight = 12;
433     logfont.lfWidth  = 12;
434     logfont.lfWeight = FW_NORMAL;
435     logfont.lfItalic = 1;
436     lstrcpyW(logfont.lfFaceName, tahomaW);
437
438     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
439     ok(hr == S_OK, "got 0x%08x\n", hr);
440
441     hr = IDWriteFont_QueryInterface(font, &IID_IDWriteFontFace, (void**)&fontface);
442     ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
443
444 if (0) /* crashes on native */
445     hr = IDWriteFont_CreateFontFace(font, NULL);
446
447     hr = IDWriteFont_CreateFontFace(font, &fontface);
448     ok(hr == S_OK, "got 0x%08x\n", hr);
449     EXPECT_REF(font, 1);
450     EXPECT_REF(fontface, 2);
451
452     hr = IDWriteFont_CreateFontFace(font, &fontface2);
453     ok(hr == S_OK, "got 0x%08x\n", hr);
454     ok(fontface == fontface2, "got %p, was %p\n", fontface2, fontface);
455     EXPECT_REF(fontface, 3);
456     EXPECT_REF(font, 1);
457
458     IDWriteFontFace_AddRef(fontface);
459     EXPECT_REF(font, 1);
460     EXPECT_REF(fontface, 4);
461     IDWriteFontFace_Release(fontface);
462     IDWriteFontFace_Release(fontface);
463
464     IDWriteFontFace_Release(fontface);
465     IDWriteFont_Release(font);
466     IDWriteGdiInterop_Release(interop);
467 }
468
469 static void test_GetMetrics(void)
470 {
471     IDWriteGdiInterop *interop;
472     DWRITE_FONT_METRICS metrics;
473     OUTLINETEXTMETRICW otm;
474     IDWriteFont *font;
475     LOGFONTW logfont;
476     HRESULT hr;
477     HDC hdc;
478     HFONT hfont;
479     int ret;
480
481     hr = IDWriteFactory_GetGdiInterop(factory, &interop);
482     EXPECT_HR(hr, S_OK);
483
484     memset(&logfont, 0, sizeof(logfont));
485     logfont.lfHeight = 12;
486     logfont.lfWidth  = 12;
487     logfont.lfWeight = FW_NORMAL;
488     logfont.lfItalic = 1;
489     lstrcpyW(logfont.lfFaceName, tahomaW);
490
491     hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
492     ok(hr == S_OK, "got 0x%08x\n", hr);
493
494     hfont = CreateFontIndirectW(&logfont);
495     hdc = CreateCompatibleDC(0);
496     SelectObject(hdc, hfont);
497
498     otm.otmSize = sizeof(otm);
499     ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm);
500     ok(ret, "got %d\n", ret);
501     DeleteDC(hdc);
502     DeleteObject(hfont);
503
504 if (0) /* crashes on native */
505     IDWriteFont_GetMetrics(font, NULL);
506
507     memset(&metrics, 0, sizeof(metrics));
508     IDWriteFont_GetMetrics(font, &metrics);
509
510     ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm);
511     ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent);
512     ok(metrics.descent != 0, "descent %u\n", metrics.descent);
513 todo_wine
514     ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap);
515     ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight);
516     ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight);
517     ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition);
518     ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness);
519     ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition);
520     ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness);
521
522     IDWriteFont_Release(font);
523     IDWriteGdiInterop_Release(interop);
524 }
525
526 START_TEST(font)
527 {
528     HRESULT hr;
529
530     hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
531     ok(hr == S_OK, "got 0x%08x\n", hr);
532     if (hr != S_OK)
533     {
534         win_skip("failed to create factory\n");
535         return;
536     }
537
538     test_CreateFontFromLOGFONT();
539     test_CreateBitmapRenderTarget();
540     test_GetFontFamily();
541     test_GetFamilyNames();
542     test_CreateFontFace();
543     test_GetMetrics();
544
545     IDWriteFactory_Release(factory);
546 }