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