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