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