crypt32: Test decoding a big CRL.
[wine] / dlls / gdi / tests / font.c
1 /*
2  * Unit test suite for fonts
3  *
4  * Copyright 2002 Mike McCormack
5  * Copyright 2004 Dmitry Timoshkov
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23 #include <assert.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29
30 #include "wine/test.h"
31
32 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
33 {
34     return 0;
35 }
36
37 static BOOL is_font_installed(const char *name)
38 {
39     HDC hdc = GetDC(0);
40     BOOL ret = FALSE;
41
42     if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
43         ret = TRUE;
44
45     ReleaseDC(0, hdc);
46     return ret;
47 }
48
49 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
50 {
51     LOGFONTA getobj_lf;
52     int ret, minlen = 0;
53
54     if (!hfont)
55         return;
56
57     ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
58     /* NT4 tries to be clever and only returns the minimum length */
59     while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
60         minlen++;
61     minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
62     ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
63     ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
64     ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
65        "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
66 }
67
68 static HFONT create_font(const char* test, const LOGFONTA* lf)
69 {
70     HFONT hfont = CreateFontIndirectA(lf);
71     ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
72     if (hfont)
73         check_font(test, lf, hfont);
74     return hfont;
75 }
76
77 static void test_logfont(void)
78 {
79     LOGFONTA lf;
80     HFONT hfont;
81
82     memset(&lf, 0, sizeof lf);
83
84     lf.lfCharSet = ANSI_CHARSET;
85     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
86     lf.lfWeight = FW_DONTCARE;
87     lf.lfHeight = 16;
88     lf.lfWidth = 16;
89     lf.lfQuality = DEFAULT_QUALITY;
90
91     lstrcpyA(lf.lfFaceName, "Arial");
92     hfont = create_font("Arial", &lf);
93     DeleteObject(hfont);
94
95     memset(&lf, 'A', sizeof(lf));
96     hfont = CreateFontIndirectA(&lf);
97     ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
98     
99     lf.lfFaceName[LF_FACESIZE - 1] = 0;
100     check_font("AAA...", &lf, hfont);
101     DeleteObject(hfont);
102 }
103
104 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
105 {
106     if (type & RASTER_FONTTYPE)
107     {
108         LOGFONT *lf = (LOGFONT *)lParam;
109         *lf = *elf;
110         return 0; /* stop enumeration */
111     }
112
113     return 1; /* continue enumeration */
114 }
115
116 static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
117                               INT test_str_len, const TEXTMETRICA *tm_orig,
118                               const SIZE *size_orig, INT width_orig,
119                               INT scale_x, INT scale_y)
120 {
121     HFONT old_hfont;
122     TEXTMETRICA tm;
123     SIZE size;
124     INT width;
125
126     if (!hfont)
127         return;
128
129     old_hfont = SelectObject(hdc, hfont);
130
131     GetTextMetricsA(hdc, &tm);
132
133     ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%ld != %ld\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
134     ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%ld != %ld\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
135     ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%ld != %ld\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
136     ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%ld != %ld\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
137
138     GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
139
140     ok(size.cx == size_orig->cx * scale_x, "%ld != %ld\n", size.cx, size_orig->cx * scale_x);
141     ok(size.cy == size_orig->cy * scale_y, "%ld != %ld\n", size.cy, size_orig->cy * scale_y);
142
143     GetCharWidthA(hdc, 'A', 'A', &width);
144
145     ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
146
147     SelectObject(hdc, old_hfont);
148 }
149
150 /* see whether GDI scales bitmap font metrics */
151 static void test_bitmap_font(void)
152 {
153     static const char test_str[11] = "Test String";
154     HDC hdc;
155     LOGFONTA bitmap_lf;
156     HFONT hfont, old_hfont;
157     TEXTMETRICA tm_orig;
158     SIZE size_orig;
159     INT ret, i, width_orig, height_orig;
160
161     hdc = GetDC(0);
162
163     /* "System" has only 1 pixel size defined, otherwise the test breaks */
164     ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
165     if (ret)
166     {
167         ReleaseDC(0, hdc);
168         trace("no bitmap fonts were found, skipping the test\n");
169         return;
170     }
171
172     trace("found bitmap font %s, height %ld\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
173
174     height_orig = bitmap_lf.lfHeight;
175     hfont = create_font("bitmap", &bitmap_lf);
176
177     old_hfont = SelectObject(hdc, hfont);
178     ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
179     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
180     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
181     SelectObject(hdc, old_hfont);
182     DeleteObject(hfont);
183
184     /* test fractional scaling */
185     for (i = 1; i < height_orig; i++)
186     {
187         hfont = create_font("fractional", &bitmap_lf);
188         test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
189         DeleteObject(hfont);
190     }
191
192     /* test integer scaling 3x2 */
193     bitmap_lf.lfHeight = height_orig * 2;
194     bitmap_lf.lfWidth *= 3;
195     hfont = create_font("3x2", &bitmap_lf);
196 todo_wine
197 {
198     test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
199 }
200     DeleteObject(hfont);
201
202     /* test integer scaling 3x3 */
203     bitmap_lf.lfHeight = height_orig * 3;
204     bitmap_lf.lfWidth = 0;
205     hfont = create_font("3x3", &bitmap_lf);
206
207 todo_wine
208 {
209     test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
210 }
211     DeleteObject(hfont);
212
213     ReleaseDC(0, hdc);
214 }
215
216 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
217 {
218     LOGFONT *lf = (LOGFONT *)lParam;
219
220     if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
221     {
222         *lf = *elf;
223         return 0; /* stop enumeration */
224     }
225     return 1; /* continue enumeration */
226 }
227
228 static void test_bitmap_font_metrics(void)
229 {
230     static const struct font_data
231     {
232         const char face_name[LF_FACESIZE];
233         int weight, height, ascent, descent, int_leading, ext_leading;
234         int ave_char_width, max_char_width;
235     } fd[] =
236     {
237         { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11 },
238         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14 },
239         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16 },
240         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20 },
241         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25 },
242         { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32 },
243         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8 },
244         { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9 },
245         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12 },
246         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16 },
247         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19 },
248         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23 },
249         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27 },
250         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34 },
251         { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8 },
252         { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9 },
253         { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12 },
254         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15 },
255         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2 },
256         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4 },
257         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13 },
258         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7 },
259         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8 },
260         { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9 }
261         /* FIXME: add "Fixedsys", "Terminal" */
262     };
263     HDC hdc;
264     LOGFONT lf;
265     HFONT hfont, old_hfont;
266     TEXTMETRIC tm;
267     INT ret, i;
268
269     hdc = CreateCompatibleDC(0);
270     assert(hdc);
271
272     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
273     {
274         memset(&lf, 0, sizeof(lf));
275
276         lf.lfHeight = fd[i].height;
277         strcpy(lf.lfFaceName, fd[i].face_name);
278         ret = EnumFontFamilies(hdc, fd[i].face_name, find_font_proc, (LPARAM)&lf);
279         if (ret)
280         {
281             trace("font %s height %d not found\n", fd[i].face_name, fd[i].height);
282             continue;
283         }
284
285         trace("found font %s, height %ld\n", lf.lfFaceName, lf.lfHeight);
286
287         hfont = create_font(lf.lfFaceName, &lf);
288         old_hfont = SelectObject(hdc, hfont);
289         ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %ld\n", GetLastError());
290
291         ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
292         ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
293         ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
294         ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
295         ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
296         ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
297         ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
298         ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
299
300         SelectObject(hdc, old_hfont);
301         DeleteObject(hfont);
302     }
303
304     DeleteDC(hdc);
305 }
306
307 static void test_GdiGetCharDimensions(void)
308 {
309     HDC hdc;
310     TEXTMETRICW tm;
311     LONG ret;
312     SIZE size;
313     LONG avgwidth, height;
314     static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
315     typedef LONG (WINAPI *fnGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
316     fnGdiGetCharDimensions GdiGetCharDimensions = (fnGdiGetCharDimensions)GetProcAddress(LoadLibrary("gdi32"), "GdiGetCharDimensions");
317     if (!GdiGetCharDimensions) return;
318
319     hdc = CreateCompatibleDC(NULL);
320
321     GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
322     avgwidth = ((size.cx / 26) + 1) / 2;
323
324     ret = GdiGetCharDimensions(hdc, &tm, &height);
325     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
326     ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm.tmHeight, height);
327
328     ret = GdiGetCharDimensions(hdc, &tm, NULL);
329     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
330
331     ret = GdiGetCharDimensions(hdc, NULL, NULL);
332     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
333
334     height = 0;
335     ret = GdiGetCharDimensions(hdc, NULL, &height);
336     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
337     ok(height == size.cy, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size.cy, height);
338
339     DeleteDC(hdc);
340 }
341
342 static void test_GetCharABCWidthsW(void)
343 {
344     BOOL ret;
345     ABC abc[1];
346     typedef BOOL (WINAPI *fnGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
347     fnGetCharABCWidthsW GetCharABCWidthsW = (fnGetCharABCWidthsW)GetProcAddress(LoadLibrary("gdi32"), "GetCharABCWidthsW");
348     if (!GetCharABCWidthsW) return;
349
350     ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
351     ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
352 }
353
354 static void test_text_extents(void)
355 {
356     static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
357     LPINT extents;
358     INT i, len, fit1, fit2;
359     LOGFONTA lf;
360     TEXTMETRICA tm;
361     HDC hdc;
362     HFONT hfont;
363     SIZE sz;
364     SIZE sz1, sz2;
365
366     memset(&lf, 0, sizeof(lf));
367     strcpy(lf.lfFaceName, "Arial");
368     lf.lfHeight = 20;
369
370     hfont = CreateFontIndirectA(&lf);
371     hdc = GetDC(0);
372     hfont = SelectObject(hdc, hfont);
373     GetTextMetricsA(hdc, &tm);
374     GetTextExtentPointA(hdc, "o", 1, &sz);
375     ok(sz.cy == tm.tmHeight, "cy %ld tmHeight %ld\n", sz.cy, tm.tmHeight);
376
377     len = lstrlenW(wt);
378     extents = HeapAlloc(GetProcessHeap(), 0, len * sizeof extents[0]);
379     memset(extents, 0, len * sizeof extents[0]);
380     extents[0] = 1;         /* So that the increasing sequence test will fail
381                                if the extents array is untouched.  */
382     GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
383     GetTextExtentPointW(hdc, wt, len, &sz2);
384     ok(sz1.cy == sz2.cy,
385        "cy from GetTextExtentExPointW (%ld) and GetTextExtentPointW (%ld) differ\n", sz1.cy, sz2.cy);
386 todo_wine {
387     /* The \n in the string is apparently handled differently in GetTextExtentPoint and GetTextExtentExPoint */
388     ok(sz1.cx != sz2.cx,
389        "cx from GetTextExtentExPointW (%ld) and GetTextExtentPointW (%ld) are the same\n", sz1.cx, sz2.cx);
390  }
391     for (i = 1; i < len; ++i)
392         ok(extents[i-1] <= extents[i],
393            "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
394            i);
395     ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
396     ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
397     ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
398     GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
399     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
400     ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
401     GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
402     ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
403     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
404     ok(extents[0] == extents[2] && extents[1] == extents[3],
405        "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
406     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
407     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
408        "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
409     HeapFree(GetProcessHeap(), 0, extents);
410
411     SelectObject(hdc, hfont);
412     DeleteObject(hfont);
413     ReleaseDC(NULL, hdc);
414 }
415
416 static void test_GetGlyphIndices()
417 {
418     HDC      hdc;
419     HFONT    hfont;
420     DWORD    charcount;
421     LOGFONTA lf;
422     DWORD    flags = 0;
423     WCHAR    testtext[] = {'T','e','s','t',0xffff,0};
424     WORD     glyphs[(sizeof(testtext)/2)-1];
425     TEXTMETRIC textm;
426
427     typedef BOOL (WINAPI *fnGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
428     fnGetGlyphIndicesW GetGlyphIndicesW = (fnGetGlyphIndicesW)GetProcAddress(LoadLibrary("gdi32"), 
429                                            "GetGlyphIndicesW");
430     if (!GetGlyphIndicesW) {
431         trace("GetGlyphIndices not available on platform\n");
432         return;
433     }
434
435     if(!is_font_installed("Symbol"))
436     {
437         trace("Symbol is not installed so skipping this test\n");
438         return;
439     }
440
441     memset(&lf, 0, sizeof(lf));
442     strcpy(lf.lfFaceName, "Symbol");
443     lf.lfHeight = 20;
444
445     hfont = CreateFontIndirectA(&lf);
446     hdc = GetDC(0);
447
448     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
449     flags |= GGI_MARK_NONEXISTING_GLYPHS;
450     charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
451     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
452     ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
453     flags = 0;
454     charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
455     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
456     ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n", 
457                     textm.tmDefaultChar, glyphs[4]);
458 }
459
460 START_TEST(font)
461 {
462     test_logfont();
463     test_bitmap_font();
464     test_bitmap_font_metrics();
465     test_GdiGetCharDimensions();
466     test_GetCharABCWidthsW();
467     test_text_extents();
468     test_GetGlyphIndices();
469 }