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