comctl32: Update Polish translation.
[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         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     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         /* small subset of kerning pairs to test */
532         DWORD total_kern_pairs;
533         const KERNINGPAIR kern_pair[20];
534     } kd[] =
535     {
536         {"Arial", -34, 20,
537             {
538                 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
539                 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
540                 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
541                 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
542                 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3}
543             }
544         },
545         { "Arial", 120, 20,
546             {
547                 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
548                 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
549                 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
550                 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
551                 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8}
552             }
553         }
554     };
555     LOGFONT lf;
556     HFONT hfont, hfont_old;
557     KERNINGPAIR *kern_pair;
558     HDC hdc;
559     DWORD total_kern_pairs, ret, i, n, matches;
560
561     hdc = GetDC(0);
562
563     /* GetKerningPairsA maps unicode set of kerning pairs to current code page
564      * which may render this test unusable, so we're trying to avoid that.
565      */
566     SetLastError(0xdeadbeef);
567     GetKerningPairsW(hdc, 0, NULL);
568     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
569     {
570         trace("Skipping the GetKerningPairs test on a Win9x platform\n");
571         ReleaseDC(0, hdc);
572         return;
573     }
574
575     for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
576     {
577         if (!is_font_installed(kd[i].face_name))
578         {
579             trace("%s is not installed so skipping this test\n", kd[i].face_name);
580             continue;
581         }
582
583         memset(&lf, 0, sizeof(lf));
584         strcpy(lf.lfFaceName, kd[i].face_name);
585         lf.lfHeight = kd[i].height;
586         hfont = CreateFontIndirect(&lf);
587         assert(hfont != 0);
588
589         hfont_old = SelectObject(hdc, hfont);
590
591         total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
592         trace("font %s, height %ld, total_kern_pairs %lu\n",
593               kd[i].face_name, kd[i].height, total_kern_pairs);
594         kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
595
596 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
597         SetLastError(0xdeadbeef);
598         ret = GetKerningPairsW(hdc, 0, kern_pair);
599         ok(GetLastError() == ERROR_INVALID_PARAMETER,
600            "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
601         ok(ret == 0, "got %lu, expected 0\n", ret);
602 #endif
603
604         ret = GetKerningPairsW(hdc, 100, NULL);
605         ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
606
607         ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
608         ok(ret == total_kern_pairs/2, "got %lu, expected %lu\n", ret, total_kern_pairs/2);
609
610         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
611         ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
612
613         matches = 0;
614
615         for (n = 0; n < ret; n++)
616         {
617             DWORD j;
618 #if 0
619             if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
620                 trace("wFirst '%c', wSecond '%c', iKernAmount %d\n",
621                       kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
622 #endif
623             for (j = 0; j < kd[i].total_kern_pairs; j++)
624             {
625                 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
626                     kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond &&
627                     kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount)
628                 {
629                     /*trace("match\n");*/
630                     matches++;
631                 }
632             }
633         }
634
635         ok(matches == kd[i].total_kern_pairs, "got matches %lu, expected %lu\n",
636            matches, kd[i].total_kern_pairs);
637
638         HeapFree(GetProcessHeap(), 0, kern_pair);
639
640         SelectObject(hdc, hfont_old);
641         DeleteObject(hfont);
642     }
643
644     ReleaseDC(0, hdc);
645 }
646
647 START_TEST(font)
648 {
649     test_logfont();
650     test_bitmap_font();
651     test_bitmap_font_metrics();
652     test_GdiGetCharDimensions();
653     test_GetCharABCWidthsW();
654     test_text_extents();
655     test_GetGlyphIndices();
656     test_GetKerningPairs();
657 }