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