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