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