gdi32: Move negative lfWidth test into a separate body, skip the test if there is...
[wine] / dlls / gdi32 / 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 #include "winnls.h"
30
31 #include "wine/test.h"
32
33 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
34
35 LONG  (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
36 BOOL  (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
37 BOOL  (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
38 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
39 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
40 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
41 BOOL  (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
42
43 static HMODULE hgdi32 = 0;
44
45 static void init(void)
46 {
47     hgdi32 = GetModuleHandleA("gdi32.dll");
48
49     pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
50     pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
51     pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
52     pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
53     pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
54     pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
55     pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
56 }
57
58 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
59 {
60     if (type != TRUETYPE_FONTTYPE) return 1;
61
62     return 0;
63 }
64
65 static BOOL is_truetype_font_installed(const char *name)
66 {
67     HDC hdc = GetDC(0);
68     BOOL ret = FALSE;
69
70     if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
71         ret = TRUE;
72
73     ReleaseDC(0, hdc);
74     return ret;
75 }
76
77 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
78 {
79     return 0;
80 }
81
82 static BOOL is_font_installed(const char *name)
83 {
84     HDC hdc = GetDC(0);
85     BOOL ret = FALSE;
86
87     if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
88         ret = TRUE;
89
90     ReleaseDC(0, hdc);
91     return ret;
92 }
93
94 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
95 {
96     LOGFONTA getobj_lf;
97     int ret, minlen = 0;
98
99     if (!hfont)
100         return;
101
102     ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
103     /* NT4 tries to be clever and only returns the minimum length */
104     while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
105         minlen++;
106     minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
107     ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
108     ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
109     ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
110        "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
111 }
112
113 static HFONT create_font(const char* test, const LOGFONTA* lf)
114 {
115     HFONT hfont = CreateFontIndirectA(lf);
116     ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
117     if (hfont)
118         check_font(test, lf, hfont);
119     return hfont;
120 }
121
122 static void test_logfont(void)
123 {
124     LOGFONTA lf;
125     HFONT hfont;
126
127     memset(&lf, 0, sizeof lf);
128
129     lf.lfCharSet = ANSI_CHARSET;
130     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
131     lf.lfWeight = FW_DONTCARE;
132     lf.lfHeight = 16;
133     lf.lfWidth = 16;
134     lf.lfQuality = DEFAULT_QUALITY;
135
136     lstrcpyA(lf.lfFaceName, "Arial");
137     hfont = create_font("Arial", &lf);
138     DeleteObject(hfont);
139
140     memset(&lf, 'A', sizeof(lf));
141     hfont = CreateFontIndirectA(&lf);
142     ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
143     
144     lf.lfFaceName[LF_FACESIZE - 1] = 0;
145     check_font("AAA...", &lf, hfont);
146     DeleteObject(hfont);
147 }
148
149 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
150 {
151     if (type & RASTER_FONTTYPE)
152     {
153         LOGFONT *lf = (LOGFONT *)lParam;
154         *lf = *elf;
155         return 0; /* stop enumeration */
156     }
157
158     return 1; /* continue enumeration */
159 }
160
161 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
162                               LONG lfWidth, const char *test_str,
163                               INT test_str_len, const TEXTMETRICA *tm_orig,
164                               const SIZE *size_orig, INT width_of_A_orig,
165                               INT scale_x, INT scale_y)
166 {
167     HFONT old_hfont;
168     LOGFONTA lf;
169     TEXTMETRICA tm;
170     SIZE size;
171     INT width_of_A, cx, cy;
172
173     if (!hfont)
174         return;
175
176     GetObjectA(hfont, sizeof(lf), &lf);
177
178     old_hfont = SelectObject(hdc, hfont);
179
180     GetTextMetricsA(hdc, &tm);
181
182     cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
183     cy = tm.tmHeight / tm_orig->tmHeight;
184     ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
185        scale_x, scale_y, cx, cy);
186     ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
187     ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
188     ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
189     ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
190     ok(tm.tmMaxCharWidth == tm_orig->tmMaxCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmMaxCharWidth * scale_x);
191
192     ok(lf.lfHeight == lfHeight, "lf %d != %d\n", lf.lfHeight, lfHeight);
193     if (lf.lfHeight)
194     {
195         if (lf.lfWidth)
196             ok(lf.lfWidth == tm.tmAveCharWidth, "lf %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
197     }
198     else
199         ok(lf.lfWidth == lfWidth, "lf %d != %d\n", lf.lfWidth, lfWidth);
200
201     GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
202
203     ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x);
204     ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y);
205
206     GetCharWidthA(hdc, 'A', 'A', &width_of_A);
207
208     ok(width_of_A == width_of_A_orig * scale_x, "%d != %d\n", width_of_A, width_of_A_orig * scale_x);
209
210     SelectObject(hdc, old_hfont);
211 }
212
213 /* Test how GDI scales bitmap font metrics */
214 static void test_bitmap_font(void)
215 {
216     static const char test_str[11] = "Test String";
217     HDC hdc;
218     LOGFONTA bitmap_lf;
219     HFONT hfont, old_hfont;
220     TEXTMETRICA tm_orig;
221     SIZE size_orig;
222     INT ret, i, width_orig, height_orig, scale, lfWidth;
223
224     hdc = GetDC(0);
225
226     /* "System" has only 1 pixel size defined, otherwise the test breaks */
227     ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
228     if (ret)
229     {
230         ReleaseDC(0, hdc);
231         trace("no bitmap fonts were found, skipping the test\n");
232         return;
233     }
234
235     trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
236
237     height_orig = bitmap_lf.lfHeight;
238     lfWidth = bitmap_lf.lfWidth;
239
240     hfont = create_font("bitmap", &bitmap_lf);
241     old_hfont = SelectObject(hdc, hfont);
242     ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
243     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
244     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
245     SelectObject(hdc, old_hfont);
246     DeleteObject(hfont);
247
248     bitmap_lf.lfHeight = 0;
249     bitmap_lf.lfWidth = 4;
250     hfont = create_font("bitmap", &bitmap_lf);
251     test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
252     DeleteObject(hfont);
253
254     bitmap_lf.lfHeight = height_orig;
255     bitmap_lf.lfWidth = lfWidth;
256
257     /* test fractional scaling */
258     for (i = 1; i <= height_orig * 3; i++)
259     {
260         INT nearest_height;
261
262         bitmap_lf.lfHeight = i;
263         hfont = create_font("fractional", &bitmap_lf);
264         scale = (i + height_orig - 1) / height_orig;
265         nearest_height = scale * height_orig;
266         /* XP allows not more than 10% deviation */
267         if (scale > 1 && nearest_height - i > nearest_height / 10) scale--;
268         test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
269         DeleteObject(hfont);
270     }
271
272     /* test integer scaling 3x2 */
273     bitmap_lf.lfHeight = height_orig * 2;
274     bitmap_lf.lfWidth *= 3;
275     hfont = create_font("3x2", &bitmap_lf);
276     test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
277     DeleteObject(hfont);
278
279     /* test integer scaling 3x3 */
280     bitmap_lf.lfHeight = height_orig * 3;
281     bitmap_lf.lfWidth = 0;
282     hfont = create_font("3x3", &bitmap_lf);
283     test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
284     DeleteObject(hfont);
285
286     ReleaseDC(0, hdc);
287 }
288
289 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
290 {
291     LOGFONT *lf = (LOGFONT *)lParam;
292
293     if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
294     {
295         *lf = *elf;
296         return 0; /* stop enumeration */
297     }
298     return 1; /* continue enumeration */
299 }
300
301 static void test_bitmap_font_metrics(void)
302 {
303     static const struct font_data
304     {
305         const char face_name[LF_FACESIZE];
306         int weight, height, ascent, descent, int_leading, ext_leading;
307         int ave_char_width, max_char_width;
308         DWORD ansi_bitfield;
309     } fd[] =
310     {
311         { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
312         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
313         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
314         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
315         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
316         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
317         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
318         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
319         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
320         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
321         { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
322         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
323         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
324         { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
325         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
326         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
327         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
328         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
329         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
330         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
331         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
332         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
333         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
334         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
335         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
336         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
337         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
338         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
339         { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
340         { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
341         { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
342         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
343         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
344 /*
345  * TODO:  the system for CP932 should be NORMAL, not BOLD.  However that would
346  *        require a new system.sfd for that font
347  */
348         { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
349         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
350         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
351         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
352         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
353         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
354         { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
355         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
356         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
357         { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
358         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
359         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
360         { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
361         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
362         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
363         { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
364         { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
365         { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
366         { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
367         { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
368         { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
369
370         /* FIXME: add "Terminal" */
371     };
372     HDC hdc;
373     LOGFONT lf;
374     HFONT hfont, old_hfont;
375     TEXTMETRIC tm;
376     INT ret, i;
377
378     hdc = CreateCompatibleDC(0);
379     assert(hdc);
380
381     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
382     {
383         int bit;
384
385         memset(&lf, 0, sizeof(lf));
386
387         lf.lfHeight = fd[i].height;
388         strcpy(lf.lfFaceName, fd[i].face_name);
389
390         for(bit = 0; bit < 32; bit++)
391         {
392             DWORD fs[2];
393             CHARSETINFO csi;
394
395             fs[0] = 1L << bit;
396             fs[1] = 0;
397             if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
398             if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
399
400             lf.lfCharSet = csi.ciCharset;
401             ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
402             if (ret) continue;
403
404             trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
405
406             hfont = create_font(lf.lfFaceName, &lf);
407             old_hfont = SelectObject(hdc, hfont);
408             ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
409
410             ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
411             ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
412             ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
413             ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
414             ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
415             ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
416             ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
417
418             /* Don't run the max char width test on System/ANSI_CHARSET.  We have extra characters in our font
419                that make the max width bigger */
420             if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
421                 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
422
423             SelectObject(hdc, old_hfont);
424             DeleteObject(hfont);
425         }
426     }
427
428     DeleteDC(hdc);
429 }
430
431 static void test_GdiGetCharDimensions(void)
432 {
433     HDC hdc;
434     TEXTMETRICW tm;
435     LONG ret;
436     SIZE size;
437     LONG avgwidth, height;
438     static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
439
440     if (!pGdiGetCharDimensions)
441     {
442         skip("GdiGetCharDimensions not available on this platform\n");
443         return;
444     }
445
446     hdc = CreateCompatibleDC(NULL);
447
448     GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
449     avgwidth = ((size.cx / 26) + 1) / 2;
450
451     ret = pGdiGetCharDimensions(hdc, &tm, &height);
452     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
453     ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
454
455     ret = pGdiGetCharDimensions(hdc, &tm, NULL);
456     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
457
458     ret = pGdiGetCharDimensions(hdc, NULL, NULL);
459     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
460
461     height = 0;
462     ret = pGdiGetCharDimensions(hdc, NULL, &height);
463     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
464     ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
465
466     DeleteDC(hdc);
467 }
468
469 static void test_GetCharABCWidths(void)
470 {
471     static const WCHAR str[] = {'a',0};
472     BOOL ret;
473     HDC hdc;
474     LOGFONTA lf;
475     HFONT hfont;
476     ABC abc[1];
477     WORD glyphs[1];
478     DWORD nb;
479
480     if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
481     {
482         skip("GetCharABCWidthsW/I not available on this platform\n");
483         return;
484     }
485
486     memset(&lf, 0, sizeof(lf));
487     strcpy(lf.lfFaceName, "System");
488     lf.lfHeight = 20;
489
490     hfont = CreateFontIndirectA(&lf);
491     hdc = GetDC(0);
492     hfont = SelectObject(hdc, hfont);
493
494     nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
495     ok(nb == 1, "pGetGlyphIndicesW should have returned 1\n");
496
497     ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
498     ok(!ret, "GetCharABCWidthsI should have failed\n");
499
500     ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
501     ok(!ret, "GetCharABCWidthsI should have failed\n");
502
503     ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
504     ok(ret, "GetCharABCWidthsI should have succeeded\n");
505
506     ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
507     ok(!ret, "GetCharABCWidthsW should have failed\n");
508
509     ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
510     ok(!ret, "GetCharABCWidthsW should have failed\n");
511
512     ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
513     ok(!ret, "GetCharABCWidthsW should have failed\n");
514
515     hfont = SelectObject(hdc, hfont);
516     DeleteObject(hfont);
517     ReleaseDC(NULL, hdc);
518 }
519
520 static void test_text_extents(void)
521 {
522     static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
523     LPINT extents;
524     INT i, len, fit1, fit2;
525     LOGFONTA lf;
526     TEXTMETRICA tm;
527     HDC hdc;
528     HFONT hfont;
529     SIZE sz;
530     SIZE sz1, sz2;
531
532     memset(&lf, 0, sizeof(lf));
533     strcpy(lf.lfFaceName, "Arial");
534     lf.lfHeight = 20;
535
536     hfont = CreateFontIndirectA(&lf);
537     hdc = GetDC(0);
538     hfont = SelectObject(hdc, hfont);
539     GetTextMetricsA(hdc, &tm);
540     GetTextExtentPointA(hdc, "o", 1, &sz);
541     ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
542
543     SetLastError(0xdeadbeef);
544     GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
545     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
546     {
547         skip("Skipping remainder of text extents test on a Win9x platform\n");
548         hfont = SelectObject(hdc, hfont);
549         DeleteObject(hfont);
550         ReleaseDC(0, hdc);
551         return;
552     }
553
554     len = lstrlenW(wt);
555     extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
556     extents[0] = 1;         /* So that the increasing sequence test will fail
557                                if the extents array is untouched.  */
558     GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
559     GetTextExtentPointW(hdc, wt, len, &sz2);
560     ok(sz1.cy == sz2.cy,
561        "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
562     /* Because of the '\n' in the string GetTextExtentExPoint and
563        GetTextExtentPoint return different widths under Win2k, but
564        under WinXP they return the same width.  So we don't test that
565        here. */
566
567     for (i = 1; i < len; ++i)
568         ok(extents[i-1] <= extents[i],
569            "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
570            i);
571     ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
572     ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
573     ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
574     GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
575     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
576     ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
577     GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
578     ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
579     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
580     ok(extents[0] == extents[2] && extents[1] == extents[3],
581        "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
582     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
583     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
584        "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
585     HeapFree(GetProcessHeap(), 0, extents);
586
587     hfont = SelectObject(hdc, hfont);
588     DeleteObject(hfont);
589     ReleaseDC(NULL, hdc);
590 }
591
592 static void test_GetGlyphIndices(void)
593 {
594     HDC      hdc;
595     HFONT    hfont;
596     DWORD    charcount;
597     LOGFONTA lf;
598     DWORD    flags = 0;
599     WCHAR    testtext[] = {'T','e','s','t',0xffff,0};
600     WORD     glyphs[(sizeof(testtext)/2)-1];
601     TEXTMETRIC textm;
602     HFONT hOldFont;
603
604     if (!pGetGlyphIndicesW) {
605         skip("GetGlyphIndices not available on platform\n");
606         return;
607     }
608
609     hdc = GetDC(0);
610
611     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
612     flags |= GGI_MARK_NONEXISTING_GLYPHS;
613     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
614     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
615     ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
616     flags = 0;
617     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
618     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
619     ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
620                     textm.tmDefaultChar, glyphs[4]);
621
622     if(!is_font_installed("Tahoma"))
623     {
624         skip("Tahoma is not installed so skipping this test\n");
625         return;
626     }
627     memset(&lf, 0, sizeof(lf));
628     strcpy(lf.lfFaceName, "Tahoma");
629     lf.lfHeight = 20;
630
631     hfont = CreateFontIndirectA(&lf);
632     hOldFont = SelectObject(hdc, hfont);
633     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
634     flags |= GGI_MARK_NONEXISTING_GLYPHS;
635     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
636     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
637     ok(glyphs[4] == 0xffff, "GetGlyphIndices should have returned 0xffff char not %04x\n", glyphs[4]);
638     flags = 0;
639     testtext[0] = textm.tmDefaultChar;
640     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
641     ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
642     todo_wine ok(glyphs[0] == 0, "GetGlyphIndices for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
643     ok(glyphs[4] == 0, "GetGlyphIndices should have returned 0 not %04x\n", glyphs[4]);
644     DeleteObject(SelectObject(hdc, hOldFont));
645 }
646
647 static void test_GetKerningPairs(void)
648 {
649     static const struct kerning_data
650     {
651         const char face_name[LF_FACESIZE];
652         LONG height;
653         /* some interesting fields from OUTLINETEXTMETRIC */
654         LONG tmHeight, tmAscent, tmDescent;
655         UINT otmEMSquare;
656         INT  otmAscent;
657         INT  otmDescent;
658         UINT otmLineGap;
659         UINT otmsCapEmHeight;
660         UINT otmsXHeight;
661         INT  otmMacAscent;
662         INT  otmMacDescent;
663         UINT otmMacLineGap;
664         UINT otmusMinimumPPEM;
665         /* small subset of kerning pairs to test */
666         DWORD total_kern_pairs;
667         const KERNINGPAIR kern_pair[26];
668     } kd[] =
669     {
670         {"Arial", 12, 12, 9, 3,
671                   2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
672                   26,
673             {
674                 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
675                 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
676                 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
677                 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
678                 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
679                 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
680                 {933,970,+1},{933,972,-1}
681                 }
682         },
683         {"Arial", -34, 39, 32, 7,
684                   2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
685                   26,
686             {
687                 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
688                 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
689                 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
690                 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
691                 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
692                 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
693                 {933,970,+2},{933,972,-3}
694             }
695         },
696         { "Arial", 120, 120, 97, 23,
697                    2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
698                    26,
699             {
700                 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
701                 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
702                 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
703                 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
704                 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
705                 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
706                 {933,970,+6},{933,972,-10}
707             }
708         },
709 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
710         { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
711                    2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
712                    26,
713             {
714                 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
715                 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
716                 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
717                 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
718                 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
719                 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
720                 {933,970,+54},{933,972,-83}
721             }
722         }
723 #endif
724     };
725     LOGFONT lf;
726     HFONT hfont, hfont_old;
727     KERNINGPAIR *kern_pair;
728     HDC hdc;
729     DWORD total_kern_pairs, ret, i, n, matches;
730
731     hdc = GetDC(0);
732
733     /* GetKerningPairsA maps unicode set of kerning pairs to current code page
734      * which may render this test unusable, so we're trying to avoid that.
735      */
736     SetLastError(0xdeadbeef);
737     GetKerningPairsW(hdc, 0, NULL);
738     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
739     {
740         skip("Skipping the GetKerningPairs test on a Win9x platform\n");
741         ReleaseDC(0, hdc);
742         return;
743     }
744
745     for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
746     {
747         OUTLINETEXTMETRICW otm;
748
749         if (!is_font_installed(kd[i].face_name))
750         {
751             trace("%s is not installed so skipping this test\n", kd[i].face_name);
752             continue;
753         }
754
755         trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
756
757         memset(&lf, 0, sizeof(lf));
758         strcpy(lf.lfFaceName, kd[i].face_name);
759         lf.lfHeight = kd[i].height;
760         hfont = CreateFontIndirect(&lf);
761         assert(hfont != 0);
762
763         hfont_old = SelectObject(hdc, hfont);
764
765         SetLastError(0xdeadbeef);
766         otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
767         ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
768
769         ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
770            kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
771         ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
772            kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
773         ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
774            kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
775
776         ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
777            kd[i].otmEMSquare, otm.otmEMSquare);
778         ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
779            kd[i].otmAscent, otm.otmAscent);
780         ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
781            kd[i].otmDescent, otm.otmDescent);
782         ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
783            kd[i].otmLineGap, otm.otmLineGap);
784 todo_wine {
785         ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
786            kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
787         ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
788            kd[i].otmsXHeight, otm.otmsXHeight);
789         ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
790            kd[i].otmMacAscent, otm.otmMacAscent);
791         ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
792            kd[i].otmMacDescent, otm.otmMacDescent);
793         /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
794         if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
795            kd[i].otmMacLineGap, otm.otmMacLineGap);
796         ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
797            kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
798 }
799
800         total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
801         trace("total_kern_pairs %u\n", total_kern_pairs);
802         kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
803
804 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
805         SetLastError(0xdeadbeef);
806         ret = GetKerningPairsW(hdc, 0, kern_pair);
807         ok(GetLastError() == ERROR_INVALID_PARAMETER,
808            "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
809         ok(ret == 0, "got %lu, expected 0\n", ret);
810 #endif
811
812         ret = GetKerningPairsW(hdc, 100, NULL);
813         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
814
815         ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
816         ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
817
818         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
819         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
820
821         matches = 0;
822
823         for (n = 0; n < ret; n++)
824         {
825             DWORD j;
826 #if 0
827             if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
828                 trace("{'%c','%c',%d},\n",
829                       kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
830 #endif
831             for (j = 0; j < kd[i].total_kern_pairs; j++)
832             {
833                 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
834                     kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
835                 {
836                     ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
837                        "pair %d:%d got %d, expected %d\n",
838                        kern_pair[n].wFirst, kern_pair[n].wSecond,
839                        kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
840                     matches++;
841                 }
842             }
843         }
844
845         ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
846            matches, kd[i].total_kern_pairs);
847
848         HeapFree(GetProcessHeap(), 0, kern_pair);
849
850         SelectObject(hdc, hfont_old);
851         DeleteObject(hfont);
852     }
853
854     ReleaseDC(0, hdc);
855 }
856
857 static void test_GetOutlineTextMetrics(void)
858 {
859     OUTLINETEXTMETRIC *otm;
860     LOGFONT lf;
861     HFONT hfont, hfont_old;
862     HDC hdc;
863     DWORD ret, otm_size;
864
865     if (!is_font_installed("Arial"))
866     {
867         skip("Arial is not installed\n");
868         return;
869     }
870
871     hdc = GetDC(0);
872
873     memset(&lf, 0, sizeof(lf));
874     strcpy(lf.lfFaceName, "Arial");
875     lf.lfHeight = -13;
876     lf.lfWeight = FW_NORMAL;
877     lf.lfPitchAndFamily = DEFAULT_PITCH;
878     lf.lfQuality = PROOF_QUALITY;
879     hfont = CreateFontIndirect(&lf);
880     assert(hfont != 0);
881
882     hfont_old = SelectObject(hdc, hfont);
883     otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
884     trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
885
886     otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
887
888     memset(otm, 0xAA, otm_size);
889     SetLastError(0xdeadbeef);
890     otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
891     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
892     ok(ret == 1 /* Win9x */ ||
893        ret == otm->otmSize /* XP*/,
894        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
895     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
896     {
897         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
898         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
899         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
900         ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
901     }
902
903     memset(otm, 0xAA, otm_size);
904     SetLastError(0xdeadbeef);
905     otm->otmSize = otm_size; /* just in case for Win9x compatibility */
906     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
907     ok(ret == 1 /* Win9x */ ||
908        ret == otm->otmSize /* XP*/,
909        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
910     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
911     {
912         ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
913         ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
914         ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
915         ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
916     }
917
918     /* ask about truncated data */
919     memset(otm, 0xAA, otm_size);
920     SetLastError(0xdeadbeef);
921     otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
922     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
923     ok(ret == 1 /* Win9x */ ||
924        ret == otm->otmSize /* XP*/,
925        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
926     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
927     {
928         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
929         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
930         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
931     }
932     ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
933
934     HeapFree(GetProcessHeap(), 0, otm);
935
936     SelectObject(hdc, hfont_old);
937     DeleteObject(hfont);
938
939     ReleaseDC(0, hdc);
940 }
941
942 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
943 {
944     INT         x, y,
945                 breakCount,
946                 outputWidth = 0,    /* to test TabbedTextOut() */
947                 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
948                 areaWidth = clientArea->right - clientArea->left,
949                 nErrors = 0, e;
950     BOOL        lastExtent = FALSE;
951     PSTR        pFirstChar, pLastChar;
952     SIZE        size;
953     TEXTMETRICA tm;
954     struct err
955     {
956         char extent[100];
957         int  GetTextExtentExPointWWidth;
958         int  TabbedTextOutWidth;
959     } error[10];
960
961     GetTextMetricsA(hdc, &tm);
962     y = clientArea->top;
963     do {
964         breakCount = 0;
965         while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
966         pFirstChar = str;
967
968         do {
969             pLastChar = str;
970
971             /* if not at the end of the string, ... */
972             if (*str == '\0') break;
973             /* ... add the next word to the current extent */
974             while (*str != '\0' && *str++ != tm.tmBreakChar);
975             breakCount++;
976             SetTextJustification(hdc, 0, 0);
977             GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
978         } while ((int) size.cx < areaWidth);
979
980         /* ignore trailing break chars */
981         breakCount--;
982         while (*(pLastChar - 1) == tm.tmBreakChar)
983         {
984             pLastChar--;
985             breakCount--;
986         }
987
988         if (*str == '\0' || breakCount <= 0) pLastChar = str;
989
990         SetTextJustification(hdc, 0, 0);
991         GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
992
993         /* do not justify the last extent */
994         if (*str != '\0' && breakCount > 0)
995         {
996             SetTextJustification(hdc, areaWidth - size.cx, breakCount);
997             GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
998             justifiedWidth = size.cx;
999         }
1000         else lastExtent = TRUE;
1001
1002         x = clientArea->left;
1003
1004         outputWidth = LOWORD(TabbedTextOut(
1005                              hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1006                              0, NULL, 0));
1007         /* catch errors and report them */
1008         if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1009         {
1010             memset(error[nErrors].extent, 0, 100);
1011             memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1012             error[nErrors].TabbedTextOutWidth = outputWidth;
1013             error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1014             nErrors++;
1015         }
1016
1017         y += size.cy;
1018         str = pLastChar;
1019     } while (*str && y < clientArea->bottom);
1020
1021     for (e = 0; e < nErrors; e++)
1022     {
1023         ok(error[e].TabbedTextOutWidth == areaWidth,
1024             "The output text (\"%s\") width should be %d, not %d.\n",
1025             error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1026         /* The width returned by GetTextExtentPoint32() is exactly the same
1027            returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1028         ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1029             "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1030             error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1031     }
1032 }
1033
1034 static void test_SetTextJustification(void)
1035 {
1036     HDC hdc;
1037     RECT clientArea;
1038     LOGFONTA lf;
1039     HFONT hfont;
1040     HWND hwnd;
1041     static char testText[] =
1042             "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1043             "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1044             "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1045             "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1046             "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1047             "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1048             "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1049
1050     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1051     GetClientRect( hwnd, &clientArea );
1052     hdc = GetDC( hwnd );
1053
1054     memset(&lf, 0, sizeof lf);
1055     lf.lfCharSet = ANSI_CHARSET;
1056     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1057     lf.lfWeight = FW_DONTCARE;
1058     lf.lfHeight = 20;
1059     lf.lfQuality = DEFAULT_QUALITY;
1060     lstrcpyA(lf.lfFaceName, "Times New Roman");
1061     hfont = create_font("Times New Roman", &lf);
1062     SelectObject(hdc, hfont);
1063
1064     testJustification(hdc, testText, &clientArea);
1065
1066     DeleteObject(hfont);
1067     ReleaseDC(hwnd, hdc);
1068     DestroyWindow(hwnd);
1069 }
1070
1071 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1072 {
1073     HDC hdc;
1074     LOGFONTA lf;
1075     HFONT hfont, hfont_old;
1076     CHARSETINFO csi;
1077     FONTSIGNATURE fs;
1078     INT cs;
1079     DWORD i, ret;
1080     char name[64];
1081
1082     assert(count <= 128);
1083
1084     memset(&lf, 0, sizeof(lf));
1085
1086     lf.lfCharSet = charset;
1087     lf.lfHeight = 10;
1088     lstrcpyA(lf.lfFaceName, "Arial");
1089     SetLastError(0xdeadbeef);
1090     hfont = CreateFontIndirectA(&lf);
1091     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1092
1093     hdc = GetDC(0);
1094     hfont_old = SelectObject(hdc, hfont);
1095
1096     cs = GetTextCharsetInfo(hdc, &fs, 0);
1097     ok(cs == charset, "expected %d, got %d\n", charset, cs);
1098
1099     SetLastError(0xdeadbeef);
1100     ret = GetTextFace(hdc, sizeof(name), name);
1101     ok(ret, "GetTextFace error %u\n", GetLastError());
1102
1103     if (charset == SYMBOL_CHARSET)
1104     {
1105         ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1106         ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1107     }
1108     else
1109     {
1110         ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1111         ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1112     }
1113
1114     if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1115     {
1116         trace("Can't find codepage for charset %d\n", cs);
1117         ReleaseDC(0, hdc);
1118         return FALSE;
1119     }
1120     ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1121
1122     if (unicode)
1123     {
1124         char ansi_buf[128];
1125         WCHAR unicode_buf[128];
1126
1127         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1128
1129         MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1130
1131         SetLastError(0xdeadbeef);
1132         ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1133         ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1134     }
1135     else
1136     {
1137         char ansi_buf[128];
1138
1139         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1140
1141         SetLastError(0xdeadbeef);
1142         ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1143         ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1144     }
1145
1146     SelectObject(hdc, hfont_old);
1147     DeleteObject(hfont);
1148
1149     ReleaseDC(0, hdc);
1150
1151     return TRUE;
1152 }
1153
1154 static void test_font_charset(void)
1155 {
1156     static struct charset_data
1157     {
1158         INT charset;
1159         UINT code_page;
1160         WORD font_idxA[128], font_idxW[128];
1161     } cd[] =
1162     {
1163         { ANSI_CHARSET, 1252 },
1164         { RUSSIAN_CHARSET, 1251 },
1165         { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1166     };
1167     int i;
1168
1169     if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1170     {
1171         skip("Skipping the font charset test on a Win9x platform\n");
1172         return;
1173     }
1174
1175     if (!is_font_installed("Arial"))
1176     {
1177         skip("Arial is not installed\n");
1178         return;
1179     }
1180
1181     for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1182     {
1183         if (cd[i].charset == SYMBOL_CHARSET)
1184         {
1185             if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1186             {
1187                 skip("Symbol or Wingdings is not installed\n");
1188                 break;
1189             }
1190         }
1191         get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1192         get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1193         ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1194     }
1195
1196     ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1197     if (i > 2)
1198     {
1199         ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1200         ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1201     }
1202     else
1203         skip("Symbol or Wingdings is not installed\n");
1204 }
1205
1206 static void test_GetFontUnicodeRanges(void)
1207 {
1208     LOGFONTA lf;
1209     HDC hdc;
1210     HFONT hfont, hfont_old;
1211     DWORD size;
1212     GLYPHSET *gs;
1213
1214     if (!pGetFontUnicodeRanges)
1215     {
1216         skip("GetFontUnicodeRanges not available before W2K\n");
1217         return;
1218     }
1219
1220     memset(&lf, 0, sizeof(lf));
1221     lstrcpyA(lf.lfFaceName, "Arial");
1222     hfont = create_font("Arial", &lf);
1223
1224     hdc = GetDC(0);
1225     hfont_old = SelectObject(hdc, hfont);
1226
1227     size = pGetFontUnicodeRanges(NULL, NULL);
1228     ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1229
1230     size = pGetFontUnicodeRanges(hdc, NULL);
1231     ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1232
1233     gs = HeapAlloc(GetProcessHeap(), 0, size);
1234
1235     size = pGetFontUnicodeRanges(hdc, gs);
1236     ok(size, "GetFontUnicodeRanges failed\n");
1237 #if 0
1238     for (i = 0; i < gs->cRanges; i++)
1239         trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1240 #endif
1241     trace("found %u ranges\n", gs->cRanges);
1242
1243     HeapFree(GetProcessHeap(), 0, gs);
1244
1245     SelectObject(hdc, hfont_old);
1246     DeleteObject(hfont);
1247     ReleaseDC(NULL, hdc);
1248 }
1249
1250 #define MAX_ENUM_FONTS 256
1251
1252 struct enum_font_data
1253 {
1254     int total;
1255     LOGFONT lf[MAX_ENUM_FONTS];
1256 };
1257
1258 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1259 {
1260     struct enum_font_data *efd = (struct enum_font_data *)lParam;
1261
1262     if (type != TRUETYPE_FONTTYPE) return 1;
1263 #if 0
1264     trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1265           lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1266 #endif
1267     if (efd->total < MAX_ENUM_FONTS)
1268         efd->lf[efd->total++] = *lf;
1269
1270     return 1;
1271 }
1272
1273 static void get_charset_stats(struct enum_font_data *efd,
1274                               int *ansi_charset, int *symbol_charset,
1275                               int *russian_charset)
1276 {
1277     int i;
1278
1279     *ansi_charset = 0;
1280     *symbol_charset = 0;
1281     *russian_charset = 0;
1282
1283     for (i = 0; i < efd->total; i++)
1284     {
1285         switch (efd->lf[i].lfCharSet)
1286         {
1287         case ANSI_CHARSET:
1288             (*ansi_charset)++;
1289             break;
1290         case SYMBOL_CHARSET:
1291             (*symbol_charset)++;
1292             break;
1293         case RUSSIAN_CHARSET:
1294             (*russian_charset)++;
1295             break;
1296         }
1297     }
1298 }
1299
1300 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1301 {
1302     struct enum_font_data efd;
1303     LOGFONT lf;
1304     HDC hdc;
1305     int i, ret, ansi_charset, symbol_charset, russian_charset;
1306
1307     trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1308
1309     if (*font_name && !is_truetype_font_installed(font_name))
1310     {
1311         skip("%s is not installed\n", font_name);
1312         return;
1313     }
1314
1315     hdc = GetDC(0);
1316
1317     /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1318      * while EnumFontFamiliesEx doesn't.
1319      */
1320     if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1321     {
1322         efd.total = 0;
1323         SetLastError(0xdeadbeef);
1324         ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1325         ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1326         get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1327         trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1328               ansi_charset, symbol_charset, russian_charset);
1329         ok(efd.total > 0, "no fonts enumerated: NULL\n");
1330         ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1331         ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1332         ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1333
1334         efd.total = 0;
1335         SetLastError(0xdeadbeef);
1336         ret = EnumFontFamiliesEx(hdc, NULL, arial_enum_proc, (LPARAM)&efd, 0);
1337         ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1338         get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1339         trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1340               ansi_charset, symbol_charset, russian_charset);
1341         ok(efd.total > 0, "no fonts enumerated: NULL\n");
1342         ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1343         ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1344         ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1345     }
1346
1347     efd.total = 0;
1348     SetLastError(0xdeadbeef);
1349     ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1350     ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1351     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1352     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1353           ansi_charset, symbol_charset, russian_charset,
1354           *font_name ? font_name : "<empty>");
1355     if (*font_name)
1356         ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1357     else
1358         ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1359     for (i = 0; i < efd.total; i++)
1360     {
1361 /* FIXME: remove completely once Wine is fixed */
1362 if (efd.lf[i].lfCharSet != font_charset)
1363 {
1364 todo_wine
1365     ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1366 }
1367 else
1368         ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1369         ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1370            font_name, efd.lf[i].lfFaceName);
1371     }
1372
1373     memset(&lf, 0, sizeof(lf));
1374     lf.lfCharSet = ANSI_CHARSET;
1375     lstrcpy(lf.lfFaceName, font_name);
1376     efd.total = 0;
1377     SetLastError(0xdeadbeef);
1378     ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1379     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1380     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1381     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1382           ansi_charset, symbol_charset, russian_charset,
1383           *font_name ? font_name : "<empty>");
1384     if (font_charset == SYMBOL_CHARSET)
1385     {
1386         if (*font_name)
1387             ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1388         else
1389             ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1390     }
1391     else
1392     {
1393         ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1394         for (i = 0; i < efd.total; i++)
1395         {
1396             ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1397             if (*font_name)
1398                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1399                    font_name, efd.lf[i].lfFaceName);
1400         }
1401     }
1402
1403     /* DEFAULT_CHARSET should enumerate all available charsets */
1404     memset(&lf, 0, sizeof(lf));
1405     lf.lfCharSet = DEFAULT_CHARSET;
1406     lstrcpy(lf.lfFaceName, font_name);
1407     efd.total = 0;
1408     SetLastError(0xdeadbeef);
1409     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1410     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1411     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1412     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1413           ansi_charset, symbol_charset, russian_charset,
1414           *font_name ? font_name : "<empty>");
1415     ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1416     for (i = 0; i < efd.total; i++)
1417     {
1418         if (*font_name)
1419             ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1420                font_name, efd.lf[i].lfFaceName);
1421     }
1422     if (*font_name)
1423     {
1424         switch (font_charset)
1425         {
1426         case ANSI_CHARSET:
1427             ok(ansi_charset > 0,
1428                "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1429             ok(!symbol_charset,
1430                "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1431             ok(russian_charset > 0,
1432                "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1433             break;
1434         case SYMBOL_CHARSET:
1435             ok(!ansi_charset,
1436                "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1437             ok(symbol_charset,
1438                "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1439             ok(!russian_charset,
1440                "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1441             break;
1442         case DEFAULT_CHARSET:
1443             ok(ansi_charset > 0,
1444                "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1445             ok(symbol_charset > 0,
1446                "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1447             ok(russian_charset > 0,
1448                "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1449             break;
1450         }
1451     }
1452     else
1453     {
1454         ok(ansi_charset > 0,
1455            "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1456         ok(symbol_charset > 0,
1457            "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1458         ok(russian_charset > 0,
1459            "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1460     }
1461
1462     memset(&lf, 0, sizeof(lf));
1463     lf.lfCharSet = SYMBOL_CHARSET;
1464     lstrcpy(lf.lfFaceName, font_name);
1465     efd.total = 0;
1466     SetLastError(0xdeadbeef);
1467     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1468     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1469     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1470     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1471           ansi_charset, symbol_charset, russian_charset,
1472           *font_name ? font_name : "<empty>");
1473     if (*font_name && font_charset == ANSI_CHARSET)
1474         ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1475     else
1476     {
1477         ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1478         for (i = 0; i < efd.total; i++)
1479         {
1480             ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1481             if (*font_name)
1482                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1483                    font_name, efd.lf[i].lfFaceName);
1484         }
1485
1486         ok(!ansi_charset,
1487            "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1488         ok(symbol_charset > 0,
1489            "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1490         ok(!russian_charset,
1491            "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1492     }
1493
1494     ReleaseDC(0, hdc);
1495 }
1496
1497 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1498 {
1499     HFONT hfont, hfont_prev;
1500     DWORD ret;
1501     GLYPHMETRICS gm1, gm2;
1502     LOGFONTA lf2 = *lf;
1503     WORD idx;
1504     MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1505
1506     /* negative widths are handled just as positive ones */
1507     lf2.lfWidth = -lf->lfWidth;
1508
1509     SetLastError(0xdeadbeef);
1510     hfont = CreateFontIndirectA(lf);
1511     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1512     check_font("original", lf, hfont);
1513
1514     hfont_prev = SelectObject(hdc, hfont);
1515
1516     ret = GetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1517     if (ret == GDI_ERROR || idx == 0xffff)
1518     {
1519         SelectObject(hdc, hfont_prev);
1520         DeleteObject(hfont);
1521         skip("This font doesn't contain 'x', skipping the test\n");
1522         return;
1523     }
1524
1525     /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1526     memset(&gm1, 0xab, sizeof(gm1));
1527     SetLastError(0xdeadbeef);
1528     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1529     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1530
1531     SelectObject(hdc, hfont_prev);
1532     DeleteObject(hfont);
1533
1534     SetLastError(0xdeadbeef);
1535     hfont = CreateFontIndirectA(&lf2);
1536     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1537     check_font("negative width", &lf2, hfont);
1538
1539     hfont_prev = SelectObject(hdc, hfont);
1540
1541     memset(&gm2, 0xbb, sizeof(gm2));
1542     SetLastError(0xdeadbeef);
1543     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1544     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1545
1546     SelectObject(hdc, hfont_prev);
1547     DeleteObject(hfont);
1548
1549     ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1550        gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1551        gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1552        gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1553        gm1.gmCellIncX == gm2.gmCellIncX &&
1554        gm1.gmCellIncY == gm2.gmCellIncY,
1555        "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1556        gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1557        gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1558        gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1559        gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1560 }
1561
1562 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1563 #include "pshpack2.h"
1564 typedef struct
1565 {
1566     USHORT version;
1567     SHORT xAvgCharWidth;
1568     USHORT usWeightClass;
1569     USHORT usWidthClass;
1570     SHORT fsType;
1571     SHORT ySubscriptXSize;
1572     SHORT ySubscriptYSize;
1573     SHORT ySubscriptXOffset;
1574     SHORT ySubscriptYOffset;
1575     SHORT ySuperscriptXSize;
1576     SHORT ySuperscriptYSize;
1577     SHORT ySuperscriptXOffset;
1578     SHORT ySuperscriptYOffset;
1579     SHORT yStrikeoutSize;
1580     SHORT yStrikeoutPosition;
1581     SHORT sFamilyClass;
1582     PANOSE panose;
1583     ULONG ulUnicodeRange1;
1584     ULONG ulUnicodeRange2;
1585     ULONG ulUnicodeRange3;
1586     ULONG ulUnicodeRange4;
1587     CHAR achVendID[4];
1588     USHORT fsSelection;
1589     USHORT usFirstCharIndex;
1590     USHORT usLastCharIndex;
1591     /* According to the Apple spec, original version didn't have the below fields,
1592      * version numbers were taked from the OpenType spec.
1593      */
1594     /* version 0 (TrueType 1.5) */
1595     USHORT sTypoAscender;
1596     USHORT sTypoDescender;
1597     USHORT sTypoLineGap;
1598     USHORT usWinAscent;
1599     USHORT usWinDescent;
1600     /* version 1 (TrueType 1.66) */
1601     ULONG ulCodePageRange1;
1602     ULONG ulCodePageRange2;
1603     /* version 2 (OpenType 1.2) */
1604     SHORT sxHeight;
1605     SHORT sCapHeight;
1606     USHORT usDefaultChar;
1607     USHORT usBreakChar;
1608     USHORT usMaxContext;
1609 } TT_OS2_V2;
1610 #include "poppack.h"
1611
1612 #ifdef WORDS_BIGENDIAN
1613 #define GET_BE_WORD(x) (x)
1614 #else
1615 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1616 #endif
1617
1618 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1619                     ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1620                     ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1621 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1622
1623 static void test_text_metrics(const LOGFONTA *lf)
1624 {
1625     HDC hdc;
1626     HFONT hfont, hfont_old;
1627     TEXTMETRICA tmA;
1628     TEXTMETRICW tmW;
1629     UINT first_unicode_char, last_unicode_char, default_char, break_char;
1630     INT test_char;
1631     TT_OS2_V2 tt_os2;
1632     USHORT version;
1633     LONG size, ret;
1634     const char *font_name = lf->lfFaceName;
1635
1636     trace("Testing font metrics for %s, charset %d\n", font_name, lf->lfCharSet);
1637
1638     hdc = GetDC(0);
1639
1640     SetLastError(0xdeadbeef);
1641     hfont = CreateFontIndirectA(lf);
1642     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1643
1644     hfont_old = SelectObject(hdc, hfont);
1645
1646     size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1647     if (size == GDI_ERROR)
1648     {
1649         trace("OS/2 chunk was not found\n");
1650         goto end_of_test;
1651     }
1652     if (size > sizeof(tt_os2))
1653     {
1654         trace("got too large OS/2 chunk of size %u\n", size);
1655         size = sizeof(tt_os2);
1656     }
1657
1658     memset(&tt_os2, 0, sizeof(tt_os2));
1659     ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1660     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1661
1662     version = GET_BE_WORD(tt_os2.version);
1663     trace("OS/2 chunk version %u, vendor %4.4s\n", version, (LPCSTR)&tt_os2.achVendID);
1664
1665     first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
1666     last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
1667     default_char = GET_BE_WORD(tt_os2.usDefaultChar);
1668     break_char = GET_BE_WORD(tt_os2.usBreakChar);
1669
1670     trace("for %s first %x, last %x, default %x, break %x\n", font_name,
1671            first_unicode_char, last_unicode_char, default_char, break_char);
1672
1673     SetLastError(0xdeadbeef);
1674     ret = GetTextMetricsA(hdc, &tmA);
1675     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
1676     trace("A: first %x, last %x, default %x, break %x\n",
1677           tmA.tmFirstChar, tmA.tmLastChar, tmA.tmDefaultChar, tmA.tmBreakChar);
1678
1679 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1680     test_char = min(first_unicode_char - 1, 255);
1681     ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
1682        font_name, tmA.tmFirstChar, test_char);
1683 #endif
1684     if (lf->lfCharSet == SYMBOL_CHARSET)
1685     {
1686         test_char = min(last_unicode_char - 0xf000, 255);
1687         ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1688            font_name, tmA.tmLastChar, test_char);
1689     }
1690     else
1691     {
1692         test_char = min(last_unicode_char, 255);
1693         ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1694            font_name, tmA.tmLastChar, test_char);
1695     }
1696
1697     SetLastError(0xdeadbeef);
1698     ret = GetTextMetricsW(hdc, &tmW);
1699     ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
1700        "GetTextMetricsW error %u\n", GetLastError());
1701     if (ret)
1702     {
1703         trace("W: first %x, last %x, default %x, break %x\n",
1704               tmW.tmFirstChar, tmW.tmLastChar, tmW.tmDefaultChar,
1705               tmW.tmBreakChar);
1706
1707         if (lf->lfCharSet == SYMBOL_CHARSET)
1708         {
1709             /* It appears that for fonts with SYMBOL_CHARSET Windows always
1710              * sets symbol range to 0 - f0ff
1711              */
1712             ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
1713                font_name, tmW.tmFirstChar);
1714             /* FIXME: Windows returns f0ff here, while Wine f0xx */
1715             ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1716                font_name, tmW.tmLastChar);
1717
1718             ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1719                font_name, tmW.tmDefaultChar);
1720             ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1721                font_name, tmW.tmBreakChar);
1722         }
1723         else
1724         {
1725             ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
1726                font_name, tmW.tmFirstChar, first_unicode_char);
1727             ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
1728                font_name, tmW.tmLastChar, last_unicode_char);
1729         }
1730         ret = GetDeviceCaps(hdc, LOGPIXELSX);
1731         ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
1732            tmW.tmDigitizedAspectX, ret);
1733         ret = GetDeviceCaps(hdc, LOGPIXELSY);
1734         ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
1735            tmW.tmDigitizedAspectX, ret);
1736     }
1737
1738     test_negative_width(hdc, lf);
1739
1740 end_of_test:
1741     SelectObject(hdc, hfont_old);
1742     DeleteObject(hfont);
1743
1744     ReleaseDC(0, hdc);
1745 }
1746
1747 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
1748 {
1749     INT *enumed = (INT *)lParam;
1750
1751     if (type == TRUETYPE_FONTTYPE)
1752     {
1753         (*enumed)++;
1754         test_text_metrics(lf);
1755     }
1756     return 1;
1757 }
1758
1759 static void test_GetTextMetrics(void)
1760 {
1761     LOGFONTA lf;
1762     HDC hdc;
1763     INT enumed;
1764
1765     hdc = GetDC(0);
1766
1767     memset(&lf, 0, sizeof(lf));
1768     lf.lfCharSet = DEFAULT_CHARSET;
1769     enumed = 0;
1770     EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
1771     trace("Tested metrics of %d truetype fonts\n", enumed);
1772
1773     ReleaseDC(0, hdc);
1774 }
1775
1776 static void test_nonexistent_font(void)
1777 {
1778     LOGFONTA lf;
1779     HDC hdc;
1780     HFONT hfont;
1781     char buf[LF_FACESIZE];
1782
1783     if (!is_truetype_font_installed("Arial Black"))
1784     {
1785         skip("Arial not installed\n");
1786         return;
1787     }
1788
1789     hdc = GetDC(0);
1790
1791     memset(&lf, 0, sizeof(lf));
1792     lf.lfHeight = 100;
1793     lf.lfWeight = FW_REGULAR;
1794     lf.lfCharSet = ANSI_CHARSET;
1795     lf.lfPitchAndFamily = FF_SWISS;
1796     strcpy(lf.lfFaceName, "Nonexistent font");
1797
1798     hfont = CreateFontIndirectA(&lf);
1799     hfont = SelectObject(hdc, hfont);
1800     GetTextFaceA(hdc, sizeof(buf), buf);
1801     ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
1802     DeleteObject(SelectObject(hdc, hfont));
1803     ReleaseDC(0, hdc);
1804 }
1805
1806 static void test_GdiRealizationInfo(void)
1807 {
1808     HDC hdc;
1809     DWORD info[4];
1810     BOOL r;
1811     HFONT hfont, hfont_old;
1812     LOGFONTA lf;
1813
1814     if(!pGdiRealizationInfo)
1815     {
1816         skip("GdiRealizationInfo not available\n");
1817         return;
1818     }
1819
1820     hdc = GetDC(0);
1821
1822     memset(info, 0xcc, sizeof(info));
1823     r = pGdiRealizationInfo(hdc, info);
1824     ok(r != 0, "ret 0\n");
1825     ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
1826     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
1827
1828     if (!is_truetype_font_installed("Arial"))
1829     {
1830         skip("skipping GdiRealizationInfo with truetype font\n");
1831         goto end;
1832     }
1833
1834     memset(&lf, 0, sizeof(lf));
1835     strcpy(lf.lfFaceName, "Arial");
1836     lf.lfHeight = 20;
1837     lf.lfWeight = FW_NORMAL;
1838     hfont = CreateFontIndirectA(&lf);
1839     hfont_old = SelectObject(hdc, hfont);
1840
1841     memset(info, 0xcc, sizeof(info));
1842     r = pGdiRealizationInfo(hdc, info);
1843     ok(r != 0, "ret 0\n");
1844     ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
1845     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
1846
1847     DeleteObject(SelectObject(hdc, hfont_old));
1848
1849  end:
1850     ReleaseDC(0, hdc);
1851 }
1852
1853 START_TEST(font)
1854 {
1855     init();
1856
1857     test_logfont();
1858     test_bitmap_font();
1859     test_bitmap_font_metrics();
1860     test_GdiGetCharDimensions();
1861     test_GetCharABCWidths();
1862     test_text_extents();
1863     test_GetGlyphIndices();
1864     test_GetKerningPairs();
1865     test_GetOutlineTextMetrics();
1866     test_SetTextJustification();
1867     test_font_charset();
1868     test_GetFontUnicodeRanges();
1869     test_nonexistent_font();
1870
1871     /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1872      * I'd like to avoid them in this test.
1873      */
1874     test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
1875     test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
1876     if (is_truetype_font_installed("Arial Black") &&
1877         (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1878     {
1879         test_EnumFontFamilies("", ANSI_CHARSET);
1880         test_EnumFontFamilies("", SYMBOL_CHARSET);
1881         test_EnumFontFamilies("", DEFAULT_CHARSET);
1882     }
1883     else
1884         skip("Arial Black or Symbol/Wingdings is not installed\n");
1885     test_GetTextMetrics();
1886     test_GdiRealizationInfo();
1887 }