janitorial: Remove remaining NULL checks before free() (found by Smatch).
[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 #define CP1252_BIT    0x00000001
229 #define CP1250_BIT    0x00000002
230 #define CP1251_BIT    0x00000004
231 #define CP1253_BIT    0x00000008
232 #define CP1254_BIT    0x00000010
233 #define CP1255_BIT    0x00000020
234 #define CP1256_BIT    0x00000040
235 #define CP1257_BIT    0x00000080
236 #define CP1258_BIT    0x00000100
237 #define CP874_BIT     0x00010000
238 #define CP932_BIT     0x00020000
239 #define CP936_BIT     0x00040000
240 #define CP949_BIT     0x00080000
241 #define CP950_BIT     0x00100000
242
243 static void test_bitmap_font_metrics(void)
244 {
245     static const struct font_data
246     {
247         const char face_name[LF_FACESIZE];
248         int weight, height, ascent, descent, int_leading, ext_leading;
249         int ave_char_width, max_char_width;
250         DWORD ansi_bitfield;
251     } fd[] =
252     {
253         { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT | CP1250_BIT | CP1251_BIT },
254         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT | CP1250_BIT | CP1251_BIT },
255         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, CP1252_BIT | CP1251_BIT },
256         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, CP1250_BIT },
257         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, CP1252_BIT },
258         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, CP1250_BIT },
259         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, CP1251_BIT },
260         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, CP1252_BIT },
261         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, CP1250_BIT },
262         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, CP1251_BIT },
263         { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, CP1252_BIT | CP1250_BIT | CP1251_BIT },
264         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
265         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
266         { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
267         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT },
268         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, CP1250_BIT | CP1251_BIT },
269         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, CP1252_BIT | CP1250_BIT },
270         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, CP1251_BIT },
271         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, CP1252_BIT | CP1250_BIT },
272         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, CP1251_BIT },
273         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, CP1252_BIT },
274         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, CP1250_BIT },
275         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, CP1251_BIT },
276         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, CP1252_BIT },
277         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, CP1250_BIT },
278         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, CP1251_BIT },
279         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, CP1252_BIT | CP1250_BIT },
280         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, CP1251_BIT },
281         { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, CP1252_BIT | CP1250_BIT | CP1251_BIT },
282         { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
283         { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, CP1252_BIT | CP1250_BIT | CP1251_BIT },
284         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT },
285         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, CP1250_BIT | CP1251_BIT },
286         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT},
287         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT | CP1251_BIT },
288         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT },
289         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT | CP1251_BIT },
290         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT },
291         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT | CP1251_BIT },
292         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT },
293         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT | CP1251_BIT },
294         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
295         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
296         { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
297         { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT | CP1250_BIT },
298         { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT }
299
300         /* FIXME: add "Terminal" */
301     };
302     HDC hdc;
303     LOGFONT lf;
304     HFONT hfont, old_hfont;
305     TEXTMETRIC tm;
306     INT ret, i;
307
308     hdc = CreateCompatibleDC(0);
309     assert(hdc);
310
311     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
312     {
313         int bit;
314
315         memset(&lf, 0, sizeof(lf));
316
317         lf.lfHeight = fd[i].height;
318         strcpy(lf.lfFaceName, fd[i].face_name);
319
320         for(bit = 0; bit < 32; bit++)
321         {
322             DWORD fs[2];
323             CHARSETINFO csi;
324
325             fs[0] = 1L << bit;
326             fs[1] = 0;
327             if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
328             if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
329
330             lf.lfCharSet = csi.ciCharset;
331             ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
332             if (ret) continue;
333
334             trace("found font %s, height %ld charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
335
336             hfont = create_font(lf.lfFaceName, &lf);
337             old_hfont = SelectObject(hdc, hfont);
338             ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %ld\n", GetLastError());
339
340             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);
341             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);
342             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);
343             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);
344             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);
345             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);
346             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);
347
348             /* Don't run the max char width test on System/ANSI_CHARSET.  We have extra characters in our font
349                that make the max width bigger */
350             if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
351                 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);
352
353             SelectObject(hdc, old_hfont);
354             DeleteObject(hfont);
355         }
356     }
357
358     DeleteDC(hdc);
359 }
360
361 static void test_GdiGetCharDimensions(void)
362 {
363     HDC hdc;
364     TEXTMETRICW tm;
365     LONG ret;
366     SIZE size;
367     LONG avgwidth, height;
368     static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
369     typedef LONG (WINAPI *fnGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
370     fnGdiGetCharDimensions GdiGetCharDimensions = (fnGdiGetCharDimensions)GetProcAddress(LoadLibrary("gdi32"), "GdiGetCharDimensions");
371     if (!GdiGetCharDimensions) return;
372
373     hdc = CreateCompatibleDC(NULL);
374
375     GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
376     avgwidth = ((size.cx / 26) + 1) / 2;
377
378     ret = GdiGetCharDimensions(hdc, &tm, &height);
379     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
380     ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm.tmHeight, height);
381
382     ret = GdiGetCharDimensions(hdc, &tm, NULL);
383     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
384
385     ret = GdiGetCharDimensions(hdc, NULL, NULL);
386     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
387
388     height = 0;
389     ret = GdiGetCharDimensions(hdc, NULL, &height);
390     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
391     ok(height == size.cy, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size.cy, height);
392
393     DeleteDC(hdc);
394 }
395
396 static void test_GetCharABCWidthsW(void)
397 {
398     BOOL ret;
399     ABC abc[1];
400     typedef BOOL (WINAPI *fnGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
401     fnGetCharABCWidthsW GetCharABCWidthsW = (fnGetCharABCWidthsW)GetProcAddress(LoadLibrary("gdi32"), "GetCharABCWidthsW");
402     if (!GetCharABCWidthsW) return;
403
404     ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
405     ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
406 }
407
408 static void test_text_extents(void)
409 {
410     static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
411     LPINT extents;
412     INT i, len, fit1, fit2;
413     LOGFONTA lf;
414     TEXTMETRICA tm;
415     HDC hdc;
416     HFONT hfont;
417     SIZE sz;
418     SIZE sz1, sz2;
419
420     memset(&lf, 0, sizeof(lf));
421     strcpy(lf.lfFaceName, "Arial");
422     lf.lfHeight = 20;
423
424     hfont = CreateFontIndirectA(&lf);
425     hdc = GetDC(0);
426     hfont = SelectObject(hdc, hfont);
427     GetTextMetricsA(hdc, &tm);
428     GetTextExtentPointA(hdc, "o", 1, &sz);
429     ok(sz.cy == tm.tmHeight, "cy %ld tmHeight %ld\n", sz.cy, tm.tmHeight);
430
431     SetLastError(0xdeadbeef);
432     GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
433     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
434     {
435         trace("Skipping remainder of text extents test on a Win9x platform\n");
436         hfont = SelectObject(hdc, hfont);
437         DeleteObject(hfont);
438         ReleaseDC(0, hdc);
439         return;
440     }
441
442     len = lstrlenW(wt);
443     extents = HeapAlloc(GetProcessHeap(), 0, len * sizeof extents[0]);
444     memset(extents, 0, len * sizeof extents[0]);
445     extents[0] = 1;         /* So that the increasing sequence test will fail
446                                if the extents array is untouched.  */
447     GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
448     GetTextExtentPointW(hdc, wt, len, &sz2);
449     ok(sz1.cy == sz2.cy,
450        "cy from GetTextExtentExPointW (%ld) and GetTextExtentPointW (%ld) differ\n", sz1.cy, sz2.cy);
451     /* Because of the '\n' in the string GetTextExtentExPoint and
452        GetTextExtentPoint return different widths under Win2k, but
453        under WinXP they return the same width.  So we don't test that
454        here. */
455
456     for (i = 1; i < len; ++i)
457         ok(extents[i-1] <= extents[i],
458            "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
459            i);
460     ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
461     ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
462     ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
463     GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
464     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
465     ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
466     GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
467     ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
468     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
469     ok(extents[0] == extents[2] && extents[1] == extents[3],
470        "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
471     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
472     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
473        "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
474     HeapFree(GetProcessHeap(), 0, extents);
475
476     hfont = SelectObject(hdc, hfont);
477     DeleteObject(hfont);
478     ReleaseDC(NULL, hdc);
479 }
480
481 static void test_GetGlyphIndices()
482 {
483     HDC      hdc;
484     HFONT    hfont;
485     DWORD    charcount;
486     LOGFONTA lf;
487     DWORD    flags = 0;
488     WCHAR    testtext[] = {'T','e','s','t',0xffff,0};
489     WORD     glyphs[(sizeof(testtext)/2)-1];
490     TEXTMETRIC textm;
491
492     typedef BOOL (WINAPI *fnGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
493     fnGetGlyphIndicesW GetGlyphIndicesW = (fnGetGlyphIndicesW)GetProcAddress(LoadLibrary("gdi32"), 
494                                            "GetGlyphIndicesW");
495     if (!GetGlyphIndicesW) {
496         trace("GetGlyphIndices not available on platform\n");
497         return;
498     }
499
500     if(!is_font_installed("Symbol"))
501     {
502         trace("Symbol is not installed so skipping this test\n");
503         return;
504     }
505
506     memset(&lf, 0, sizeof(lf));
507     strcpy(lf.lfFaceName, "Symbol");
508     lf.lfHeight = 20;
509
510     hfont = CreateFontIndirectA(&lf);
511     hdc = GetDC(0);
512
513     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
514     flags |= GGI_MARK_NONEXISTING_GLYPHS;
515     charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
516     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
517     ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
518     flags = 0;
519     charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
520     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
521     ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n", 
522                     textm.tmDefaultChar, glyphs[4]);
523 }
524
525 static void test_GetKerningPairs(void)
526 {
527     static const struct kerning_data
528     {
529         const char face_name[LF_FACESIZE];
530         LONG height;
531         /* some interesting fields from OUTLINETEXTMETRIC */
532         LONG tmHeight, tmAscent, tmDescent;
533         UINT otmEMSquare;
534         INT  otmAscent;
535         INT  otmDescent;
536         UINT otmLineGap;
537         UINT otmsCapEmHeight;
538         UINT otmsXHeight;
539         INT  otmMacAscent;
540         INT  otmMacDescent;
541         UINT otmMacLineGap;
542         UINT otmusMinimumPPEM;
543         /* small subset of kerning pairs to test */
544         DWORD total_kern_pairs;
545         const KERNINGPAIR kern_pair[26];
546     } kd[] =
547     {
548         {"Arial", 12, 12, 9, 3,
549                   2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
550                   26,
551             {
552                 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
553                 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
554                 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
555                 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
556                 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
557                 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
558                 {933,970,+1},{933,972,-1}
559                 }
560         },
561         {"Arial", -34, 39, 32, 7,
562                   2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
563                   26,
564             {
565                 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
566                 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
567                 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
568                 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
569                 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
570                 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
571                 {933,970,+2},{933,972,-3}
572             }
573         },
574         { "Arial", 120, 120, 97, 23,
575                    2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
576                    26,
577             {
578                 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
579                 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
580                 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
581                 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
582                 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
583                 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
584                 {933,970,+6},{933,972,-10}
585             }
586         },
587 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
588         { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
589                    2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
590                    26,
591             {
592                 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
593                 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
594                 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
595                 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
596                 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
597                 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
598                 {933,970,+54},{933,972,-83}
599             }
600         }
601 #endif
602     };
603     LOGFONT lf;
604     HFONT hfont, hfont_old;
605     KERNINGPAIR *kern_pair;
606     HDC hdc;
607     DWORD total_kern_pairs, ret, i, n, matches;
608
609     hdc = GetDC(0);
610
611     /* GetKerningPairsA maps unicode set of kerning pairs to current code page
612      * which may render this test unusable, so we're trying to avoid that.
613      */
614     SetLastError(0xdeadbeef);
615     GetKerningPairsW(hdc, 0, NULL);
616     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
617     {
618         trace("Skipping the GetKerningPairs test on a Win9x platform\n");
619         ReleaseDC(0, hdc);
620         return;
621     }
622
623     for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
624     {
625         OUTLINETEXTMETRICW otm;
626
627         if (!is_font_installed(kd[i].face_name))
628         {
629             trace("%s is not installed so skipping this test\n", kd[i].face_name);
630             continue;
631         }
632
633         trace("testing font %s, height %ld\n", kd[i].face_name, kd[i].height);
634
635         memset(&lf, 0, sizeof(lf));
636         strcpy(lf.lfFaceName, kd[i].face_name);
637         lf.lfHeight = kd[i].height;
638         hfont = CreateFontIndirect(&lf);
639         assert(hfont != 0);
640
641         hfont_old = SelectObject(hdc, hfont);
642
643         SetLastError(0xdeadbeef);
644         otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
645         ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %ld\n", GetLastError());
646
647         ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %ld, got %ld\n",
648            kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
649         ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %ld, got %ld\n",
650            kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
651         ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %ld, got %ld\n",
652            kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
653
654         ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
655            kd[i].otmEMSquare, otm.otmEMSquare);
656         ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
657            kd[i].otmAscent, otm.otmAscent);
658         ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
659            kd[i].otmDescent, otm.otmDescent);
660         ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
661            kd[i].otmLineGap, otm.otmLineGap);
662 todo_wine {
663         ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
664            kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
665         ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
666            kd[i].otmsXHeight, otm.otmsXHeight);
667         ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
668            kd[i].otmMacAscent, otm.otmMacAscent);
669         ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
670            kd[i].otmMacDescent, otm.otmMacDescent);
671 #if 0 /* this one succeeds due to expected 0, enable it when removing todo */
672         ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
673            kd[i].otmMacLineGap, otm.otmMacLineGap);
674 #endif
675         ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
676            kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
677 }
678
679         total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
680         trace("total_kern_pairs %lu\n", total_kern_pairs);
681         kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
682
683 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
684         SetLastError(0xdeadbeef);
685         ret = GetKerningPairsW(hdc, 0, kern_pair);
686         ok(GetLastError() == ERROR_INVALID_PARAMETER,
687            "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
688         ok(ret == 0, "got %lu, expected 0\n", ret);
689 #endif
690
691         ret = GetKerningPairsW(hdc, 100, NULL);
692         ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
693
694         ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
695         ok(ret == total_kern_pairs/2, "got %lu, expected %lu\n", ret, total_kern_pairs/2);
696
697         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
698         ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
699
700         matches = 0;
701
702         for (n = 0; n < ret; n++)
703         {
704             DWORD j;
705 #if 0
706             if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
707                 trace("{'%c','%c',%d},\n",
708                       kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
709 #endif
710             for (j = 0; j < kd[i].total_kern_pairs; j++)
711             {
712                 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
713                     kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
714                 {
715                     ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
716                        "pair %d:%d got %d, expected %d\n",
717                        kern_pair[n].wFirst, kern_pair[n].wSecond,
718                        kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
719                     matches++;
720                 }
721             }
722         }
723
724         ok(matches == kd[i].total_kern_pairs, "got matches %lu, expected %lu\n",
725            matches, kd[i].total_kern_pairs);
726
727         HeapFree(GetProcessHeap(), 0, kern_pair);
728
729         SelectObject(hdc, hfont_old);
730         DeleteObject(hfont);
731     }
732
733     ReleaseDC(0, hdc);
734 }
735
736 START_TEST(font)
737 {
738     test_logfont();
739     test_bitmap_font();
740     test_bitmap_font_metrics();
741     test_GdiGetCharDimensions();
742     test_GetCharABCWidthsW();
743     test_text_extents();
744     test_GetGlyphIndices();
745     test_GetKerningPairs();
746 }