wintrust: Use helper function for setting confidence in SoftpubCheckCert.
[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 near_match(a, b) (abs((a) - (b)) <= 6)
34 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
35
36 LONG  (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
37 BOOL  (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
38 BOOL  (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
39 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
40 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
41 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
42 BOOL  (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
43
44 static HMODULE hgdi32 = 0;
45
46 static void init(void)
47 {
48     hgdi32 = GetModuleHandleA("gdi32.dll");
49
50     pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
51     pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
52     pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
53     pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
54     pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
55     pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
56     pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
57 }
58
59 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
60 {
61     if (type != TRUETYPE_FONTTYPE) return 1;
62
63     return 0;
64 }
65
66 static BOOL is_truetype_font_installed(const char *name)
67 {
68     HDC hdc = GetDC(0);
69     BOOL ret = FALSE;
70
71     if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
72         ret = TRUE;
73
74     ReleaseDC(0, hdc);
75     return ret;
76 }
77
78 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
79 {
80     return 0;
81 }
82
83 static BOOL is_font_installed(const char *name)
84 {
85     HDC hdc = GetDC(0);
86     BOOL ret = FALSE;
87
88     if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
89         ret = TRUE;
90
91     ReleaseDC(0, hdc);
92     return ret;
93 }
94
95 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
96 {
97     LOGFONTA getobj_lf;
98     int ret, minlen = 0;
99
100     if (!hfont)
101         return;
102
103     ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
104     /* NT4 tries to be clever and only returns the minimum length */
105     while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
106         minlen++;
107     minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
108     ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
109     ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
110     ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
111        "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
112 }
113
114 static HFONT create_font(const char* test, const LOGFONTA* lf)
115 {
116     HFONT hfont = CreateFontIndirectA(lf);
117     ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
118     if (hfont)
119         check_font(test, lf, hfont);
120     return hfont;
121 }
122
123 static void test_logfont(void)
124 {
125     LOGFONTA lf;
126     HFONT hfont;
127
128     memset(&lf, 0, sizeof lf);
129
130     lf.lfCharSet = ANSI_CHARSET;
131     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
132     lf.lfWeight = FW_DONTCARE;
133     lf.lfHeight = 16;
134     lf.lfWidth = 16;
135     lf.lfQuality = DEFAULT_QUALITY;
136
137     lstrcpyA(lf.lfFaceName, "Arial");
138     hfont = create_font("Arial", &lf);
139     DeleteObject(hfont);
140
141     memset(&lf, 'A', sizeof(lf));
142     hfont = CreateFontIndirectA(&lf);
143     ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
144     
145     lf.lfFaceName[LF_FACESIZE - 1] = 0;
146     check_font("AAA...", &lf, hfont);
147     DeleteObject(hfont);
148 }
149
150 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
151 {
152     if (type & RASTER_FONTTYPE)
153     {
154         LOGFONT *lf = (LOGFONT *)lParam;
155         *lf = *elf;
156         return 0; /* stop enumeration */
157     }
158
159     return 1; /* continue enumeration */
160 }
161
162 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
163 {
164     ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
165     ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
166     ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
167     ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
168     ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
169     ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
170     ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
171     ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
172     ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
173     ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
174     ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
175     ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
176     ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
177     ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
178     ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
179     ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
180     ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
181     ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
182     ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
183     ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
184 }
185
186 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
187                               LONG lfWidth, const char *test_str,
188                               INT test_str_len, const TEXTMETRICA *tm_orig,
189                               const SIZE *size_orig, INT width_of_A_orig,
190                               INT scale_x, INT scale_y)
191 {
192     HFONT old_hfont;
193     LOGFONTA lf;
194     OUTLINETEXTMETRIC otm;
195     TEXTMETRICA tm;
196     SIZE size;
197     INT width_of_A, cx, cy;
198     UINT ret;
199
200     if (!hfont)
201         return;
202
203     GetObjectA(hfont, sizeof(lf), &lf);
204
205     old_hfont = SelectObject(hdc, hfont);
206
207     if (GetOutlineTextMetricsA(hdc, 0, NULL))
208     {
209         otm.otmSize = sizeof(otm) / 2;
210         ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
211         ok(ret == sizeof(otm)/2 /* XP */ ||
212            ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
213
214         memset(&otm, 0x1, sizeof(otm));
215         otm.otmSize = sizeof(otm);
216         ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
217         ok(ret == sizeof(otm) /* XP */ ||
218            ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
219
220         memset(&tm, 0x2, sizeof(tm));
221         ret = GetTextMetricsA(hdc, &tm);
222         ok(ret, "GetTextMetricsA failed\n");
223         /* the structure size is aligned */
224         if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
225         {
226             ok(0, "tm != otm\n");
227             compare_tm(&tm, &otm.otmTextMetrics);
228         }
229
230         tm = otm.otmTextMetrics;
231 if (0) /* these metrics are scaled too, but with rounding errors */
232 {
233         ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
234         ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
235 }
236         ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
237         ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
238         ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
239         ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
240         ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
241         ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
242     }
243     else
244     {
245         ret = GetTextMetricsA(hdc, &tm);
246         ok(ret, "GetTextMetricsA failed\n");
247     }
248
249     cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
250     cy = tm.tmHeight / tm_orig->tmHeight;
251     ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
252        scale_x, scale_y, cx, cy);
253     ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
254     ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
255     ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
256     ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
257     ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
258
259     ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
260     if (lf.lfHeight)
261     {
262         if (lf.lfWidth)
263             ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
264     }
265     else
266         ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
267
268     GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
269
270     ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
271     ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
272
273     GetCharWidthA(hdc, 'A', 'A', &width_of_A);
274
275     ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
276
277     SelectObject(hdc, old_hfont);
278 }
279
280 /* Test how GDI scales bitmap font metrics */
281 static void test_bitmap_font(void)
282 {
283     static const char test_str[11] = "Test String";
284     HDC hdc;
285     LOGFONTA bitmap_lf;
286     HFONT hfont, old_hfont;
287     TEXTMETRICA tm_orig;
288     SIZE size_orig;
289     INT ret, i, width_orig, height_orig, scale, lfWidth;
290
291     hdc = GetDC(0);
292
293     /* "System" has only 1 pixel size defined, otherwise the test breaks */
294     ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
295     if (ret)
296     {
297         ReleaseDC(0, hdc);
298         trace("no bitmap fonts were found, skipping the test\n");
299         return;
300     }
301
302     trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
303
304     height_orig = bitmap_lf.lfHeight;
305     lfWidth = bitmap_lf.lfWidth;
306
307     hfont = create_font("bitmap", &bitmap_lf);
308     old_hfont = SelectObject(hdc, hfont);
309     ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
310     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
311     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
312     SelectObject(hdc, old_hfont);
313     DeleteObject(hfont);
314
315     bitmap_lf.lfHeight = 0;
316     bitmap_lf.lfWidth = 4;
317     hfont = create_font("bitmap", &bitmap_lf);
318     test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
319     DeleteObject(hfont);
320
321     bitmap_lf.lfHeight = height_orig;
322     bitmap_lf.lfWidth = lfWidth;
323
324     /* test fractional scaling */
325     for (i = 1; i <= height_orig * 3; i++)
326     {
327         INT nearest_height;
328
329         bitmap_lf.lfHeight = i;
330         hfont = create_font("fractional", &bitmap_lf);
331         scale = (i + height_orig - 1) / height_orig;
332         nearest_height = scale * height_orig;
333         /* XP allows not more than 10% deviation */
334         if (scale > 1 && nearest_height - i > nearest_height / 10) scale--;
335         test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
336         DeleteObject(hfont);
337     }
338
339     /* test integer scaling 3x2 */
340     bitmap_lf.lfHeight = height_orig * 2;
341     bitmap_lf.lfWidth *= 3;
342     hfont = create_font("3x2", &bitmap_lf);
343     test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
344     DeleteObject(hfont);
345
346     /* test integer scaling 3x3 */
347     bitmap_lf.lfHeight = height_orig * 3;
348     bitmap_lf.lfWidth = 0;
349     hfont = create_font("3x3", &bitmap_lf);
350     test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
351     DeleteObject(hfont);
352
353     ReleaseDC(0, hdc);
354 }
355
356 /* Test how GDI scales outline font metrics */
357 static void test_outline_font(void)
358 {
359     static const char test_str[11] = "Test String";
360     HDC hdc;
361     LOGFONTA lf;
362     HFONT hfont, old_hfont;
363     OUTLINETEXTMETRICA otm;
364     SIZE size_orig;
365     INT width_orig, height_orig, lfWidth;
366     XFORM xform;
367     GLYPHMETRICS gm;
368     MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
369     MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
370     POINT pt;
371     INT ret;
372
373     if (!is_truetype_font_installed("Arial"))
374     {
375         skip("Arial is not installed\n");
376         return;
377     }
378
379     hdc = CreateCompatibleDC(0);
380
381     memset(&lf, 0, sizeof(lf));
382     strcpy(lf.lfFaceName, "Arial");
383     lf.lfHeight = 72;
384     hfont = create_font("outline", &lf);
385     old_hfont = SelectObject(hdc, hfont);
386     otm.otmSize = sizeof(otm);
387     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
388     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
389     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
390     SelectObject(hdc, old_hfont);
391
392     test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
393     DeleteObject(hfont);
394
395     /* font of otmEMSquare height helps to avoid a lot of rounding errors */
396     lf.lfHeight = otm.otmEMSquare;
397     lf.lfHeight = -lf.lfHeight;
398     hfont = create_font("outline", &lf);
399     old_hfont = SelectObject(hdc, hfont);
400     otm.otmSize = sizeof(otm);
401     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
402     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
403     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
404     SelectObject(hdc, old_hfont);
405     DeleteObject(hfont);
406
407     height_orig = otm.otmTextMetrics.tmHeight;
408     lfWidth = otm.otmTextMetrics.tmAveCharWidth;
409
410     /* test integer scaling 3x2 */
411     lf.lfHeight = height_orig * 2;
412     lf.lfWidth = lfWidth * 3;
413     hfont = create_font("3x2", &lf);
414     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
415     DeleteObject(hfont);
416
417     /* test integer scaling 3x3 */
418     lf.lfHeight = height_orig * 3;
419     lf.lfWidth = lfWidth * 3;
420     hfont = create_font("3x3", &lf);
421     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
422     DeleteObject(hfont);
423
424     /* test integer scaling 1x1 */
425     lf.lfHeight = height_orig * 1;
426     lf.lfWidth = lfWidth * 1;
427     hfont = create_font("1x1", &lf);
428     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
429     DeleteObject(hfont);
430
431     /* test integer scaling 1x1 */
432     lf.lfHeight = height_orig;
433     lf.lfWidth = 0;
434     hfont = create_font("1x1", &lf);
435     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
436
437     old_hfont = SelectObject(hdc, hfont);
438     /* with an identity matrix */
439     memset(&gm, 0, sizeof(gm));
440     SetLastError(0xdeadbeef);
441     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
442     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
443     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
444     ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
445     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
446     /* with a custom matrix */
447     memset(&gm, 0, sizeof(gm));
448     SetLastError(0xdeadbeef);
449     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
450     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
451     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
452     ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
453     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
454     SelectObject(hdc, old_hfont);
455
456     SetMapMode(hdc, MM_ANISOTROPIC);
457     /* test restrictions of compatibility mode GM_COMPATIBLE */
458     /*  part 1: rescaling only X should not change font scaling on screen.
459                 So compressing the X axis by 2 is not done, and this
460                 appears as X scaling of 2 that no one requested. */
461     SetWindowExtEx(hdc, 100, 100, NULL);
462     SetViewportExtEx(hdc, 50, 100, NULL);
463     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
464
465     /*  part 2: rescaling only Y should change font scaling.
466                 As also X is scaled by a factor of 2, but this is not
467                 requested by the DC transformation, we get a scaling factor
468                 of 2 in the X coordinate. */
469     SetViewportExtEx(hdc, 100, 200, NULL);
470     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
471
472     /* restore scaling */
473     SetMapMode(hdc, MM_TEXT);
474
475     if (!SetGraphicsMode(hdc, GM_ADVANCED))
476     {
477         DeleteObject(hfont);
478         DeleteDC(hdc);
479         skip("GM_ADVANCED is not supported on this platform\n");
480         return;
481     }
482
483     xform.eM11 = 20.0f;
484     xform.eM12 = 0.0f;
485     xform.eM21 = 0.0f;
486     xform.eM22 = 20.0f;
487     xform.eDx = 0.0f;
488     xform.eDy = 0.0f;
489
490     SetLastError(0xdeadbeef);
491     ret = SetWorldTransform(hdc, &xform);
492     ok(ret, "SetWorldTransform error %u\n", GetLastError());
493
494     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
495
496     old_hfont = SelectObject(hdc, hfont);
497     /* with an identity matrix */
498     memset(&gm, 0, sizeof(gm));
499     SetLastError(0xdeadbeef);
500     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
501     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
502     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
503     pt.x = width_orig; pt.y = 0;
504     LPtoDP(hdc, &pt, 1);
505     ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
506     ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
507     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
508     /* with a custom matrix */
509     memset(&gm, 0, sizeof(gm));
510     SetLastError(0xdeadbeef);
511     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
512     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
513     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
514     pt.x = width_orig; pt.y = 0;
515     LPtoDP(hdc, &pt, 1);
516     ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
517     ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
518     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
519     SelectObject(hdc, old_hfont);
520
521     SetLastError(0xdeadbeef);
522     ret = SetMapMode(hdc, MM_LOMETRIC);
523     ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
524
525     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
526
527     old_hfont = SelectObject(hdc, hfont);
528     /* with an identity matrix */
529     memset(&gm, 0, sizeof(gm));
530     SetLastError(0xdeadbeef);
531     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
532     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
533     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
534     pt.x = width_orig; pt.y = 0;
535     LPtoDP(hdc, &pt, 1);
536     ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
537     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
538     /* with a custom matrix */
539     memset(&gm, 0, sizeof(gm));
540     SetLastError(0xdeadbeef);
541     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
542     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
543     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
544     pt.x = width_orig; pt.y = 0;
545     LPtoDP(hdc, &pt, 1);
546     ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
547     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
548     SelectObject(hdc, old_hfont);
549
550     SetLastError(0xdeadbeef);
551     ret = SetMapMode(hdc, MM_TEXT);
552     ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
553
554     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
555
556     old_hfont = SelectObject(hdc, hfont);
557     /* with an identity matrix */
558     memset(&gm, 0, sizeof(gm));
559     SetLastError(0xdeadbeef);
560     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
561     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
562     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
563     pt.x = width_orig; pt.y = 0;
564     LPtoDP(hdc, &pt, 1);
565     ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
566     ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
567     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
568     /* with a custom matrix */
569     memset(&gm, 0, sizeof(gm));
570     SetLastError(0xdeadbeef);
571     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
572     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
573     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
574     pt.x = width_orig; pt.y = 0;
575     LPtoDP(hdc, &pt, 1);
576     ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
577     ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
578     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
579     SelectObject(hdc, old_hfont);
580
581     DeleteObject(hfont);
582     DeleteDC(hdc);
583 }
584
585 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
586 {
587     LOGFONT *lf = (LOGFONT *)lParam;
588
589     if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
590     {
591         *lf = *elf;
592         return 0; /* stop enumeration */
593     }
594     return 1; /* continue enumeration */
595 }
596
597 static void test_bitmap_font_metrics(void)
598 {
599     static const struct font_data
600     {
601         const char face_name[LF_FACESIZE];
602         int weight, height, ascent, descent, int_leading, ext_leading;
603         int ave_char_width, max_char_width;
604         DWORD ansi_bitfield;
605     } fd[] =
606     {
607         { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
608         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
609         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
610         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
611         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
612         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
613         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
614         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
615         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
616         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
617         { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
618         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
619         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
620         { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
621         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
622         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
623         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
624         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
625         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
626         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
627         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
628         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
629         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
630         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
631         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
632         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
633         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
634         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
635         { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
636         { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
637         { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
638         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
639         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
640 /*
641  * TODO:  the system for CP932 should be NORMAL, not BOLD.  However that would
642  *        require a new system.sfd for that font
643  */
644         { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
645         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
646         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
647         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
648         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
649         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
650         { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
651         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
652         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
653         { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
654         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
655         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
656         { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
657         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
658         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
659         { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
660         { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
661         { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
662         { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
663         { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
664         { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
665
666         /* FIXME: add "Terminal" */
667     };
668     HDC hdc;
669     LOGFONT lf;
670     HFONT hfont, old_hfont;
671     TEXTMETRIC tm;
672     INT ret, i;
673
674     hdc = CreateCompatibleDC(0);
675     assert(hdc);
676
677     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
678     {
679         int bit;
680
681         memset(&lf, 0, sizeof(lf));
682
683         lf.lfHeight = fd[i].height;
684         strcpy(lf.lfFaceName, fd[i].face_name);
685
686         for(bit = 0; bit < 32; bit++)
687         {
688             DWORD fs[2];
689             CHARSETINFO csi;
690
691             fs[0] = 1L << bit;
692             fs[1] = 0;
693             if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
694             if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
695
696             lf.lfCharSet = csi.ciCharset;
697             ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
698             if (ret) continue;
699
700             trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
701
702             hfont = create_font(lf.lfFaceName, &lf);
703             old_hfont = SelectObject(hdc, hfont);
704             ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
705
706             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);
707             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);
708             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);
709             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);
710             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);
711             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);
712             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);
713
714             /* Don't run the max char width test on System/ANSI_CHARSET.  We have extra characters in our font
715                that make the max width bigger */
716             if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
717                 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);
718
719             SelectObject(hdc, old_hfont);
720             DeleteObject(hfont);
721         }
722     }
723
724     DeleteDC(hdc);
725 }
726
727 static void test_GdiGetCharDimensions(void)
728 {
729     HDC hdc;
730     TEXTMETRICW tm;
731     LONG ret;
732     SIZE size;
733     LONG avgwidth, height;
734     static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
735
736     if (!pGdiGetCharDimensions)
737     {
738         skip("GdiGetCharDimensions not available on this platform\n");
739         return;
740     }
741
742     hdc = CreateCompatibleDC(NULL);
743
744     GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
745     avgwidth = ((size.cx / 26) + 1) / 2;
746
747     ret = pGdiGetCharDimensions(hdc, &tm, &height);
748     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
749     ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
750
751     ret = pGdiGetCharDimensions(hdc, &tm, NULL);
752     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
753
754     ret = pGdiGetCharDimensions(hdc, NULL, NULL);
755     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
756
757     height = 0;
758     ret = pGdiGetCharDimensions(hdc, NULL, &height);
759     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
760     ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
761
762     DeleteDC(hdc);
763 }
764
765 static void test_GetCharABCWidths(void)
766 {
767     static const WCHAR str[] = {'a',0};
768     BOOL ret;
769     HDC hdc;
770     LOGFONTA lf;
771     HFONT hfont;
772     ABC abc[1];
773     WORD glyphs[1];
774     DWORD nb;
775
776     if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
777     {
778         skip("GetCharABCWidthsW/I not available on this platform\n");
779         return;
780     }
781
782     memset(&lf, 0, sizeof(lf));
783     strcpy(lf.lfFaceName, "System");
784     lf.lfHeight = 20;
785
786     hfont = CreateFontIndirectA(&lf);
787     hdc = GetDC(0);
788     hfont = SelectObject(hdc, hfont);
789
790     nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
791     ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
792
793     ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
794     ok(!ret, "GetCharABCWidthsI should have failed\n");
795
796     ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
797     ok(!ret, "GetCharABCWidthsI should have failed\n");
798
799     ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
800     ok(ret, "GetCharABCWidthsI should have succeeded\n");
801
802     ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
803     ok(!ret, "GetCharABCWidthsW should have failed\n");
804
805     ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
806     ok(!ret, "GetCharABCWidthsW should have failed\n");
807
808     ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
809     ok(!ret, "GetCharABCWidthsW should have failed\n");
810
811     hfont = SelectObject(hdc, hfont);
812     DeleteObject(hfont);
813     ReleaseDC(NULL, hdc);
814 }
815
816 static void test_text_extents(void)
817 {
818     static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
819     LPINT extents;
820     INT i, len, fit1, fit2;
821     LOGFONTA lf;
822     TEXTMETRICA tm;
823     HDC hdc;
824     HFONT hfont;
825     SIZE sz;
826     SIZE sz1, sz2;
827
828     memset(&lf, 0, sizeof(lf));
829     strcpy(lf.lfFaceName, "Arial");
830     lf.lfHeight = 20;
831
832     hfont = CreateFontIndirectA(&lf);
833     hdc = GetDC(0);
834     hfont = SelectObject(hdc, hfont);
835     GetTextMetricsA(hdc, &tm);
836     GetTextExtentPointA(hdc, "o", 1, &sz);
837     ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
838
839     SetLastError(0xdeadbeef);
840     GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
841     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
842     {
843         skip("Skipping remainder of text extents test on a Win9x platform\n");
844         hfont = SelectObject(hdc, hfont);
845         DeleteObject(hfont);
846         ReleaseDC(0, hdc);
847         return;
848     }
849
850     len = lstrlenW(wt);
851     extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
852     extents[0] = 1;         /* So that the increasing sequence test will fail
853                                if the extents array is untouched.  */
854     GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
855     GetTextExtentPointW(hdc, wt, len, &sz2);
856     ok(sz1.cy == sz2.cy,
857        "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
858     /* Because of the '\n' in the string GetTextExtentExPoint and
859        GetTextExtentPoint return different widths under Win2k, but
860        under WinXP they return the same width.  So we don't test that
861        here. */
862
863     for (i = 1; i < len; ++i)
864         ok(extents[i-1] <= extents[i],
865            "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
866            i);
867     ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
868     ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
869     ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
870     GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
871     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
872     ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
873     GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
874     ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
875     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
876     ok(extents[0] == extents[2] && extents[1] == extents[3],
877        "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
878     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
879     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
880        "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
881     HeapFree(GetProcessHeap(), 0, extents);
882
883     hfont = SelectObject(hdc, hfont);
884     DeleteObject(hfont);
885     ReleaseDC(NULL, hdc);
886 }
887
888 static void test_GetGlyphIndices(void)
889 {
890     HDC      hdc;
891     HFONT    hfont;
892     DWORD    charcount;
893     LOGFONTA lf;
894     DWORD    flags = 0;
895     WCHAR    testtext[] = {'T','e','s','t',0xffff,0};
896     WORD     glyphs[(sizeof(testtext)/2)-1];
897     TEXTMETRIC textm;
898     HFONT hOldFont;
899
900     if (!pGetGlyphIndicesW) {
901         skip("GetGlyphIndicesW not available on platform\n");
902         return;
903     }
904
905     hdc = GetDC(0);
906
907     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
908     flags |= GGI_MARK_NONEXISTING_GLYPHS;
909     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
910     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
911     ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
912     flags = 0;
913     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
914     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
915     ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
916                     textm.tmDefaultChar, glyphs[4]);
917
918     if(!is_font_installed("Tahoma"))
919     {
920         skip("Tahoma is not installed so skipping this test\n");
921         return;
922     }
923     memset(&lf, 0, sizeof(lf));
924     strcpy(lf.lfFaceName, "Tahoma");
925     lf.lfHeight = 20;
926
927     hfont = CreateFontIndirectA(&lf);
928     hOldFont = SelectObject(hdc, hfont);
929     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
930     flags |= GGI_MARK_NONEXISTING_GLYPHS;
931     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
932     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
933     ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
934     flags = 0;
935     testtext[0] = textm.tmDefaultChar;
936     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
937     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
938     todo_wine ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
939     ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
940     DeleteObject(SelectObject(hdc, hOldFont));
941 }
942
943 static void test_GetKerningPairs(void)
944 {
945     static const struct kerning_data
946     {
947         const char face_name[LF_FACESIZE];
948         LONG height;
949         /* some interesting fields from OUTLINETEXTMETRIC */
950         LONG tmHeight, tmAscent, tmDescent;
951         UINT otmEMSquare;
952         INT  otmAscent;
953         INT  otmDescent;
954         UINT otmLineGap;
955         UINT otmsCapEmHeight;
956         UINT otmsXHeight;
957         INT  otmMacAscent;
958         INT  otmMacDescent;
959         UINT otmMacLineGap;
960         UINT otmusMinimumPPEM;
961         /* small subset of kerning pairs to test */
962         DWORD total_kern_pairs;
963         const KERNINGPAIR kern_pair[26];
964     } kd[] =
965     {
966         {"Arial", 12, 12, 9, 3,
967                   2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
968                   26,
969             {
970                 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
971                 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
972                 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
973                 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
974                 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
975                 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
976                 {933,970,+1},{933,972,-1}
977                 }
978         },
979         {"Arial", -34, 39, 32, 7,
980                   2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
981                   26,
982             {
983                 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
984                 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
985                 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
986                 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
987                 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
988                 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
989                 {933,970,+2},{933,972,-3}
990             }
991         },
992         { "Arial", 120, 120, 97, 23,
993                    2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
994                    26,
995             {
996                 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
997                 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
998                 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
999                 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1000                 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1001                 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1002                 {933,970,+6},{933,972,-10}
1003             }
1004         },
1005 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1006         { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1007                    2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1008                    26,
1009             {
1010                 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1011                 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1012                 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1013                 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1014                 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1015                 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1016                 {933,970,+54},{933,972,-83}
1017             }
1018         }
1019 #endif
1020     };
1021     LOGFONT lf;
1022     HFONT hfont, hfont_old;
1023     KERNINGPAIR *kern_pair;
1024     HDC hdc;
1025     DWORD total_kern_pairs, ret, i, n, matches;
1026
1027     hdc = GetDC(0);
1028
1029     /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1030      * which may render this test unusable, so we're trying to avoid that.
1031      */
1032     SetLastError(0xdeadbeef);
1033     GetKerningPairsW(hdc, 0, NULL);
1034     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1035     {
1036         skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1037         ReleaseDC(0, hdc);
1038         return;
1039     }
1040
1041     for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1042     {
1043         OUTLINETEXTMETRICW otm;
1044
1045         if (!is_font_installed(kd[i].face_name))
1046         {
1047             trace("%s is not installed so skipping this test\n", kd[i].face_name);
1048             continue;
1049         }
1050
1051         trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1052
1053         memset(&lf, 0, sizeof(lf));
1054         strcpy(lf.lfFaceName, kd[i].face_name);
1055         lf.lfHeight = kd[i].height;
1056         hfont = CreateFontIndirect(&lf);
1057         assert(hfont != 0);
1058
1059         hfont_old = SelectObject(hdc, hfont);
1060
1061         SetLastError(0xdeadbeef);
1062         otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1063         ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1064
1065         ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1066            kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1067         ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1068            kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1069         ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1070            kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1071
1072         ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1073            kd[i].otmEMSquare, otm.otmEMSquare);
1074         ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1075            kd[i].otmAscent, otm.otmAscent);
1076         ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1077            kd[i].otmDescent, otm.otmDescent);
1078         ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1079            kd[i].otmLineGap, otm.otmLineGap);
1080         ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1081            kd[i].otmMacDescent, otm.otmMacDescent);
1082 todo_wine {
1083         ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1084            kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1085         ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1086            kd[i].otmsXHeight, otm.otmsXHeight);
1087         ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1088            kd[i].otmMacAscent, otm.otmMacAscent);
1089         /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1090         if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1091            kd[i].otmMacLineGap, otm.otmMacLineGap);
1092         ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1093            kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1094 }
1095
1096         total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1097         trace("total_kern_pairs %u\n", total_kern_pairs);
1098         kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1099
1100 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1101         SetLastError(0xdeadbeef);
1102         ret = GetKerningPairsW(hdc, 0, kern_pair);
1103         ok(GetLastError() == ERROR_INVALID_PARAMETER,
1104            "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1105         ok(ret == 0, "got %lu, expected 0\n", ret);
1106 #endif
1107
1108         ret = GetKerningPairsW(hdc, 100, NULL);
1109         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1110
1111         ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1112         ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1113
1114         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1115         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1116
1117         matches = 0;
1118
1119         for (n = 0; n < ret; n++)
1120         {
1121             DWORD j;
1122 #if 0
1123             if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1124                 trace("{'%c','%c',%d},\n",
1125                       kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1126 #endif
1127             for (j = 0; j < kd[i].total_kern_pairs; j++)
1128             {
1129                 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1130                     kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1131                 {
1132                     ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1133                        "pair %d:%d got %d, expected %d\n",
1134                        kern_pair[n].wFirst, kern_pair[n].wSecond,
1135                        kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1136                     matches++;
1137                 }
1138             }
1139         }
1140
1141         ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1142            matches, kd[i].total_kern_pairs);
1143
1144         HeapFree(GetProcessHeap(), 0, kern_pair);
1145
1146         SelectObject(hdc, hfont_old);
1147         DeleteObject(hfont);
1148     }
1149
1150     ReleaseDC(0, hdc);
1151 }
1152
1153 static void test_GetOutlineTextMetrics(void)
1154 {
1155     OUTLINETEXTMETRIC *otm;
1156     LOGFONT lf;
1157     HFONT hfont, hfont_old;
1158     HDC hdc;
1159     DWORD ret, otm_size;
1160
1161     if (!is_font_installed("Arial"))
1162     {
1163         skip("Arial is not installed\n");
1164         return;
1165     }
1166
1167     hdc = GetDC(0);
1168
1169     memset(&lf, 0, sizeof(lf));
1170     strcpy(lf.lfFaceName, "Arial");
1171     lf.lfHeight = -13;
1172     lf.lfWeight = FW_NORMAL;
1173     lf.lfPitchAndFamily = DEFAULT_PITCH;
1174     lf.lfQuality = PROOF_QUALITY;
1175     hfont = CreateFontIndirect(&lf);
1176     assert(hfont != 0);
1177
1178     hfont_old = SelectObject(hdc, hfont);
1179     otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1180     trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1181
1182     otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1183
1184     memset(otm, 0xAA, otm_size);
1185     SetLastError(0xdeadbeef);
1186     otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1187     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1188     ok(ret == 1 /* Win9x */ ||
1189        ret == otm->otmSize /* XP*/,
1190        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1191     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1192     {
1193         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1194         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1195         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1196         ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1197     }
1198
1199     memset(otm, 0xAA, otm_size);
1200     SetLastError(0xdeadbeef);
1201     otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1202     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1203     ok(ret == 1 /* Win9x */ ||
1204        ret == otm->otmSize /* XP*/,
1205        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1206     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1207     {
1208         ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1209         ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1210         ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1211         ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1212     }
1213
1214     /* ask about truncated data */
1215     memset(otm, 0xAA, otm_size);
1216     SetLastError(0xdeadbeef);
1217     otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1218     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1219     ok(ret == 1 /* Win9x */ ||
1220        ret == otm->otmSize /* XP*/,
1221        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1222     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1223     {
1224         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1225         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1226         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1227     }
1228     ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
1229
1230     HeapFree(GetProcessHeap(), 0, otm);
1231
1232     SelectObject(hdc, hfont_old);
1233     DeleteObject(hfont);
1234
1235     ReleaseDC(0, hdc);
1236 }
1237
1238 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1239 {
1240     INT         x, y,
1241                 breakCount,
1242                 outputWidth = 0,    /* to test TabbedTextOut() */
1243                 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1244                 areaWidth = clientArea->right - clientArea->left,
1245                 nErrors = 0, e;
1246     BOOL        lastExtent = FALSE;
1247     PSTR        pFirstChar, pLastChar;
1248     SIZE        size;
1249     TEXTMETRICA tm;
1250     struct err
1251     {
1252         char extent[100];
1253         int  GetTextExtentExPointWWidth;
1254         int  TabbedTextOutWidth;
1255     } error[10];
1256
1257     GetTextMetricsA(hdc, &tm);
1258     y = clientArea->top;
1259     do {
1260         breakCount = 0;
1261         while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1262         pFirstChar = str;
1263
1264         do {
1265             pLastChar = str;
1266
1267             /* if not at the end of the string, ... */
1268             if (*str == '\0') break;
1269             /* ... add the next word to the current extent */
1270             while (*str != '\0' && *str++ != tm.tmBreakChar);
1271             breakCount++;
1272             SetTextJustification(hdc, 0, 0);
1273             GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1274         } while ((int) size.cx < areaWidth);
1275
1276         /* ignore trailing break chars */
1277         breakCount--;
1278         while (*(pLastChar - 1) == tm.tmBreakChar)
1279         {
1280             pLastChar--;
1281             breakCount--;
1282         }
1283
1284         if (*str == '\0' || breakCount <= 0) pLastChar = str;
1285
1286         SetTextJustification(hdc, 0, 0);
1287         GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1288
1289         /* do not justify the last extent */
1290         if (*str != '\0' && breakCount > 0)
1291         {
1292             SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1293             GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1294             justifiedWidth = size.cx;
1295         }
1296         else lastExtent = TRUE;
1297
1298         x = clientArea->left;
1299
1300         outputWidth = LOWORD(TabbedTextOut(
1301                              hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1302                              0, NULL, 0));
1303         /* catch errors and report them */
1304         if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1305         {
1306             memset(error[nErrors].extent, 0, 100);
1307             memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1308             error[nErrors].TabbedTextOutWidth = outputWidth;
1309             error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1310             nErrors++;
1311         }
1312
1313         y += size.cy;
1314         str = pLastChar;
1315     } while (*str && y < clientArea->bottom);
1316
1317     for (e = 0; e < nErrors; e++)
1318     {
1319         ok(error[e].TabbedTextOutWidth == areaWidth,
1320             "The output text (\"%s\") width should be %d, not %d.\n",
1321             error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1322         /* The width returned by GetTextExtentPoint32() is exactly the same
1323            returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1324         ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1325             "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1326             error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1327     }
1328 }
1329
1330 static void test_SetTextJustification(void)
1331 {
1332     HDC hdc;
1333     RECT clientArea;
1334     LOGFONTA lf;
1335     HFONT hfont;
1336     HWND hwnd;
1337     static char testText[] =
1338             "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1339             "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1340             "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1341             "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1342             "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1343             "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1344             "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1345
1346     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1347     GetClientRect( hwnd, &clientArea );
1348     hdc = GetDC( hwnd );
1349
1350     memset(&lf, 0, sizeof lf);
1351     lf.lfCharSet = ANSI_CHARSET;
1352     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1353     lf.lfWeight = FW_DONTCARE;
1354     lf.lfHeight = 20;
1355     lf.lfQuality = DEFAULT_QUALITY;
1356     lstrcpyA(lf.lfFaceName, "Times New Roman");
1357     hfont = create_font("Times New Roman", &lf);
1358     SelectObject(hdc, hfont);
1359
1360     testJustification(hdc, testText, &clientArea);
1361
1362     DeleteObject(hfont);
1363     ReleaseDC(hwnd, hdc);
1364     DestroyWindow(hwnd);
1365 }
1366
1367 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1368 {
1369     HDC hdc;
1370     LOGFONTA lf;
1371     HFONT hfont, hfont_old;
1372     CHARSETINFO csi;
1373     FONTSIGNATURE fs;
1374     INT cs;
1375     DWORD i, ret;
1376     char name[64];
1377
1378     assert(count <= 128);
1379
1380     memset(&lf, 0, sizeof(lf));
1381
1382     lf.lfCharSet = charset;
1383     lf.lfHeight = 10;
1384     lstrcpyA(lf.lfFaceName, "Arial");
1385     SetLastError(0xdeadbeef);
1386     hfont = CreateFontIndirectA(&lf);
1387     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1388
1389     hdc = GetDC(0);
1390     hfont_old = SelectObject(hdc, hfont);
1391
1392     cs = GetTextCharsetInfo(hdc, &fs, 0);
1393     ok(cs == charset, "expected %d, got %d\n", charset, cs);
1394
1395     SetLastError(0xdeadbeef);
1396     ret = GetTextFaceA(hdc, sizeof(name), name);
1397     ok(ret, "GetTextFaceA error %u\n", GetLastError());
1398
1399     if (charset == SYMBOL_CHARSET)
1400     {
1401         ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1402         ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1403     }
1404     else
1405     {
1406         ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1407         ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1408     }
1409
1410     if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1411     {
1412         trace("Can't find codepage for charset %d\n", cs);
1413         ReleaseDC(0, hdc);
1414         return FALSE;
1415     }
1416     ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1417
1418     if (unicode)
1419     {
1420         char ansi_buf[128];
1421         WCHAR unicode_buf[128];
1422
1423         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1424
1425         MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1426
1427         SetLastError(0xdeadbeef);
1428         ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1429         ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1430     }
1431     else
1432     {
1433         char ansi_buf[128];
1434
1435         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1436
1437         SetLastError(0xdeadbeef);
1438         ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1439         ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1440     }
1441
1442     SelectObject(hdc, hfont_old);
1443     DeleteObject(hfont);
1444
1445     ReleaseDC(0, hdc);
1446
1447     return TRUE;
1448 }
1449
1450 static void test_font_charset(void)
1451 {
1452     static struct charset_data
1453     {
1454         INT charset;
1455         UINT code_page;
1456         WORD font_idxA[128], font_idxW[128];
1457     } cd[] =
1458     {
1459         { ANSI_CHARSET, 1252 },
1460         { RUSSIAN_CHARSET, 1251 },
1461         { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1462     };
1463     int i;
1464
1465     if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1466     {
1467         skip("Skipping the font charset test on a Win9x platform\n");
1468         return;
1469     }
1470
1471     if (!is_font_installed("Arial"))
1472     {
1473         skip("Arial is not installed\n");
1474         return;
1475     }
1476
1477     for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1478     {
1479         if (cd[i].charset == SYMBOL_CHARSET)
1480         {
1481             if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1482             {
1483                 skip("Symbol or Wingdings is not installed\n");
1484                 break;
1485             }
1486         }
1487         get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1488         get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1489         ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1490     }
1491
1492     ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1493     if (i > 2)
1494     {
1495         ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1496         ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1497     }
1498     else
1499         skip("Symbol or Wingdings is not installed\n");
1500 }
1501
1502 static void test_GetFontUnicodeRanges(void)
1503 {
1504     LOGFONTA lf;
1505     HDC hdc;
1506     HFONT hfont, hfont_old;
1507     DWORD size;
1508     GLYPHSET *gs;
1509
1510     if (!pGetFontUnicodeRanges)
1511     {
1512         skip("GetFontUnicodeRanges not available before W2K\n");
1513         return;
1514     }
1515
1516     memset(&lf, 0, sizeof(lf));
1517     lstrcpyA(lf.lfFaceName, "Arial");
1518     hfont = create_font("Arial", &lf);
1519
1520     hdc = GetDC(0);
1521     hfont_old = SelectObject(hdc, hfont);
1522
1523     size = pGetFontUnicodeRanges(NULL, NULL);
1524     ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1525
1526     size = pGetFontUnicodeRanges(hdc, NULL);
1527     ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1528
1529     gs = HeapAlloc(GetProcessHeap(), 0, size);
1530
1531     size = pGetFontUnicodeRanges(hdc, gs);
1532     ok(size, "GetFontUnicodeRanges failed\n");
1533 #if 0
1534     for (i = 0; i < gs->cRanges; i++)
1535         trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1536 #endif
1537     trace("found %u ranges\n", gs->cRanges);
1538
1539     HeapFree(GetProcessHeap(), 0, gs);
1540
1541     SelectObject(hdc, hfont_old);
1542     DeleteObject(hfont);
1543     ReleaseDC(NULL, hdc);
1544 }
1545
1546 #define MAX_ENUM_FONTS 256
1547
1548 struct enum_font_data
1549 {
1550     int total;
1551     LOGFONT lf[MAX_ENUM_FONTS];
1552 };
1553
1554 struct enum_font_dataW
1555 {
1556     int total;
1557     LOGFONTW lf[MAX_ENUM_FONTS];
1558 };
1559
1560 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1561 {
1562     struct enum_font_data *efd = (struct enum_font_data *)lParam;
1563
1564     if (type != TRUETYPE_FONTTYPE) return 1;
1565 #if 0
1566     trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1567           lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1568 #endif
1569     if (efd->total < MAX_ENUM_FONTS)
1570         efd->lf[efd->total++] = *lf;
1571
1572     return 1;
1573 }
1574
1575 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1576 {
1577     struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1578
1579     if (type != TRUETYPE_FONTTYPE) return 1;
1580
1581     if (efd->total < MAX_ENUM_FONTS)
1582         efd->lf[efd->total++] = *lf;
1583
1584     return 1;
1585 }
1586
1587 static void get_charset_stats(struct enum_font_data *efd,
1588                               int *ansi_charset, int *symbol_charset,
1589                               int *russian_charset)
1590 {
1591     int i;
1592
1593     *ansi_charset = 0;
1594     *symbol_charset = 0;
1595     *russian_charset = 0;
1596
1597     for (i = 0; i < efd->total; i++)
1598     {
1599         switch (efd->lf[i].lfCharSet)
1600         {
1601         case ANSI_CHARSET:
1602             (*ansi_charset)++;
1603             break;
1604         case SYMBOL_CHARSET:
1605             (*symbol_charset)++;
1606             break;
1607         case RUSSIAN_CHARSET:
1608             (*russian_charset)++;
1609             break;
1610         }
1611     }
1612 }
1613
1614 static void get_charset_statsW(struct enum_font_dataW *efd,
1615                               int *ansi_charset, int *symbol_charset,
1616                               int *russian_charset)
1617 {
1618     int i;
1619
1620     *ansi_charset = 0;
1621     *symbol_charset = 0;
1622     *russian_charset = 0;
1623
1624     for (i = 0; i < efd->total; i++)
1625     {
1626         switch (efd->lf[i].lfCharSet)
1627         {
1628         case ANSI_CHARSET:
1629             (*ansi_charset)++;
1630             break;
1631         case SYMBOL_CHARSET:
1632             (*symbol_charset)++;
1633             break;
1634         case RUSSIAN_CHARSET:
1635             (*russian_charset)++;
1636             break;
1637         }
1638     }
1639 }
1640
1641 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1642 {
1643     struct enum_font_data efd;
1644     struct enum_font_dataW efdw;
1645     LOGFONT lf;
1646     HDC hdc;
1647     int i, ret, ansi_charset, symbol_charset, russian_charset;
1648
1649     trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1650
1651     if (*font_name && !is_truetype_font_installed(font_name))
1652     {
1653         skip("%s is not installed\n", font_name);
1654         return;
1655     }
1656
1657     hdc = GetDC(0);
1658
1659     /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1660      * while EnumFontFamiliesEx doesn't.
1661      */
1662     if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1663     {
1664         /*
1665          * Use EnumFontFamiliesW since win98 crashes when the
1666          *    second parameter is NULL using EnumFontFamilies
1667          */
1668         efd.total = 0;
1669         SetLastError(0xdeadbeef);
1670         ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1671         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1672         if(ret)
1673         {
1674             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1675             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1676                   ansi_charset, symbol_charset, russian_charset);
1677             ok(efd.total == 0, "fonts enumerated: NULL\n");
1678             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1679             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1680             ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1681         }
1682
1683         efd.total = 0;
1684         SetLastError(0xdeadbeef);
1685         ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1686         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1687         if(ret)
1688         {
1689             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1690             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1691                   ansi_charset, symbol_charset, russian_charset);
1692             ok(efd.total == 0, "fonts enumerated: NULL\n");
1693             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1694             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1695             ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1696         }
1697     }
1698
1699     efd.total = 0;
1700     SetLastError(0xdeadbeef);
1701     ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1702     ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1703     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1704     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1705           ansi_charset, symbol_charset, russian_charset,
1706           *font_name ? font_name : "<empty>");
1707     if (*font_name)
1708         ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1709     else
1710         ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1711     for (i = 0; i < efd.total; i++)
1712     {
1713 /* FIXME: remove completely once Wine is fixed */
1714 if (efd.lf[i].lfCharSet != font_charset)
1715 {
1716 todo_wine
1717     ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1718 }
1719 else
1720         ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1721         ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1722            font_name, efd.lf[i].lfFaceName);
1723     }
1724
1725     memset(&lf, 0, sizeof(lf));
1726     lf.lfCharSet = ANSI_CHARSET;
1727     lstrcpy(lf.lfFaceName, font_name);
1728     efd.total = 0;
1729     SetLastError(0xdeadbeef);
1730     ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1731     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1732     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1733     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1734           ansi_charset, symbol_charset, russian_charset,
1735           *font_name ? font_name : "<empty>");
1736     if (font_charset == SYMBOL_CHARSET)
1737     {
1738         if (*font_name)
1739             ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1740         else
1741             ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1742     }
1743     else
1744     {
1745         ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1746         for (i = 0; i < efd.total; i++)
1747         {
1748             ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1749             if (*font_name)
1750                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1751                    font_name, efd.lf[i].lfFaceName);
1752         }
1753     }
1754
1755     /* DEFAULT_CHARSET should enumerate all available charsets */
1756     memset(&lf, 0, sizeof(lf));
1757     lf.lfCharSet = DEFAULT_CHARSET;
1758     lstrcpy(lf.lfFaceName, font_name);
1759     efd.total = 0;
1760     SetLastError(0xdeadbeef);
1761     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1762     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1763     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1764     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1765           ansi_charset, symbol_charset, russian_charset,
1766           *font_name ? font_name : "<empty>");
1767     ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1768     for (i = 0; i < efd.total; i++)
1769     {
1770         if (*font_name)
1771             ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1772                font_name, efd.lf[i].lfFaceName);
1773     }
1774     if (*font_name)
1775     {
1776         switch (font_charset)
1777         {
1778         case ANSI_CHARSET:
1779             ok(ansi_charset > 0,
1780                "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1781             ok(!symbol_charset,
1782                "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1783             ok(russian_charset > 0,
1784                "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1785             break;
1786         case SYMBOL_CHARSET:
1787             ok(!ansi_charset,
1788                "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1789             ok(symbol_charset,
1790                "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1791             ok(!russian_charset,
1792                "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1793             break;
1794         case DEFAULT_CHARSET:
1795             ok(ansi_charset > 0,
1796                "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1797             ok(symbol_charset > 0,
1798                "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1799             ok(russian_charset > 0,
1800                "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1801             break;
1802         }
1803     }
1804     else
1805     {
1806         ok(ansi_charset > 0,
1807            "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1808         ok(symbol_charset > 0,
1809            "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1810         ok(russian_charset > 0,
1811            "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1812     }
1813
1814     memset(&lf, 0, sizeof(lf));
1815     lf.lfCharSet = SYMBOL_CHARSET;
1816     lstrcpy(lf.lfFaceName, font_name);
1817     efd.total = 0;
1818     SetLastError(0xdeadbeef);
1819     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1820     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1821     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1822     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1823           ansi_charset, symbol_charset, russian_charset,
1824           *font_name ? font_name : "<empty>");
1825     if (*font_name && font_charset == ANSI_CHARSET)
1826         ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1827     else
1828     {
1829         ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1830         for (i = 0; i < efd.total; i++)
1831         {
1832             ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1833             if (*font_name)
1834                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1835                    font_name, efd.lf[i].lfFaceName);
1836         }
1837
1838         ok(!ansi_charset,
1839            "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1840         ok(symbol_charset > 0,
1841            "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1842         ok(!russian_charset,
1843            "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1844     }
1845
1846     ReleaseDC(0, hdc);
1847 }
1848
1849 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1850 {
1851     HFONT hfont, hfont_prev;
1852     DWORD ret;
1853     GLYPHMETRICS gm1, gm2;
1854     LOGFONTA lf2 = *lf;
1855     WORD idx;
1856     MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1857
1858     if(!pGetGlyphIndicesA)
1859     {
1860         skip("GetGlyphIndicesA is unavailable\n");
1861         return;
1862     }
1863
1864     /* negative widths are handled just as positive ones */
1865     lf2.lfWidth = -lf->lfWidth;
1866
1867     SetLastError(0xdeadbeef);
1868     hfont = CreateFontIndirectA(lf);
1869     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1870     check_font("original", lf, hfont);
1871
1872     hfont_prev = SelectObject(hdc, hfont);
1873
1874     ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1875     if (ret == GDI_ERROR || idx == 0xffff)
1876     {
1877         SelectObject(hdc, hfont_prev);
1878         DeleteObject(hfont);
1879         skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1880         return;
1881     }
1882
1883     /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1884     memset(&gm1, 0xab, sizeof(gm1));
1885     SetLastError(0xdeadbeef);
1886     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1887     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1888
1889     SelectObject(hdc, hfont_prev);
1890     DeleteObject(hfont);
1891
1892     SetLastError(0xdeadbeef);
1893     hfont = CreateFontIndirectA(&lf2);
1894     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1895     check_font("negative width", &lf2, hfont);
1896
1897     hfont_prev = SelectObject(hdc, hfont);
1898
1899     memset(&gm2, 0xbb, sizeof(gm2));
1900     SetLastError(0xdeadbeef);
1901     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1902     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1903
1904     SelectObject(hdc, hfont_prev);
1905     DeleteObject(hfont);
1906
1907     ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1908        gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1909        gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1910        gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1911        gm1.gmCellIncX == gm2.gmCellIncX &&
1912        gm1.gmCellIncY == gm2.gmCellIncY,
1913        "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1914        gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1915        gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1916        gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1917        gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1918 }
1919
1920 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1921 #include "pshpack2.h"
1922 typedef struct
1923 {
1924     USHORT version;
1925     SHORT xAvgCharWidth;
1926     USHORT usWeightClass;
1927     USHORT usWidthClass;
1928     SHORT fsType;
1929     SHORT ySubscriptXSize;
1930     SHORT ySubscriptYSize;
1931     SHORT ySubscriptXOffset;
1932     SHORT ySubscriptYOffset;
1933     SHORT ySuperscriptXSize;
1934     SHORT ySuperscriptYSize;
1935     SHORT ySuperscriptXOffset;
1936     SHORT ySuperscriptYOffset;
1937     SHORT yStrikeoutSize;
1938     SHORT yStrikeoutPosition;
1939     SHORT sFamilyClass;
1940     PANOSE panose;
1941     ULONG ulUnicodeRange1;
1942     ULONG ulUnicodeRange2;
1943     ULONG ulUnicodeRange3;
1944     ULONG ulUnicodeRange4;
1945     CHAR achVendID[4];
1946     USHORT fsSelection;
1947     USHORT usFirstCharIndex;
1948     USHORT usLastCharIndex;
1949     /* According to the Apple spec, original version didn't have the below fields,
1950      * version numbers were taked from the OpenType spec.
1951      */
1952     /* version 0 (TrueType 1.5) */
1953     USHORT sTypoAscender;
1954     USHORT sTypoDescender;
1955     USHORT sTypoLineGap;
1956     USHORT usWinAscent;
1957     USHORT usWinDescent;
1958     /* version 1 (TrueType 1.66) */
1959     ULONG ulCodePageRange1;
1960     ULONG ulCodePageRange2;
1961     /* version 2 (OpenType 1.2) */
1962     SHORT sxHeight;
1963     SHORT sCapHeight;
1964     USHORT usDefaultChar;
1965     USHORT usBreakChar;
1966     USHORT usMaxContext;
1967 } TT_OS2_V2;
1968 #include "poppack.h"
1969
1970 #ifdef WORDS_BIGENDIAN
1971 #define GET_BE_WORD(x) (x)
1972 #else
1973 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1974 #endif
1975
1976 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1977                     ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1978                     ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1979 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1980
1981 static void test_text_metrics(const LOGFONTA *lf)
1982 {
1983     HDC hdc;
1984     HFONT hfont, hfont_old;
1985     TEXTMETRICA tmA;
1986     TEXTMETRICW tmW;
1987     UINT first_unicode_char, last_unicode_char, default_char, break_char;
1988     INT test_char;
1989     TT_OS2_V2 tt_os2;
1990     USHORT version;
1991     LONG size, ret;
1992     const char *font_name = lf->lfFaceName;
1993
1994     hdc = GetDC(0);
1995
1996     SetLastError(0xdeadbeef);
1997     hfont = CreateFontIndirectA(lf);
1998     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1999
2000     hfont_old = SelectObject(hdc, hfont);
2001
2002     size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2003     if (size == GDI_ERROR)
2004     {
2005         trace("OS/2 chunk was not found\n");
2006         goto end_of_test;
2007     }
2008     if (size > sizeof(tt_os2))
2009     {
2010         trace("got too large OS/2 chunk of size %u\n", size);
2011         size = sizeof(tt_os2);
2012     }
2013
2014     memset(&tt_os2, 0, sizeof(tt_os2));
2015     ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2016     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2017
2018     version = GET_BE_WORD(tt_os2.version);
2019
2020     first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2021     last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2022     default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2023     break_char = GET_BE_WORD(tt_os2.usBreakChar);
2024
2025     trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
2026           font_name, lf->lfCharSet, first_unicode_char, last_unicode_char, default_char, break_char,
2027           version, (LPCSTR)&tt_os2.achVendID);
2028
2029     SetLastError(0xdeadbeef);
2030     ret = GetTextMetricsA(hdc, &tmA);
2031     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2032
2033 #if 0 /* FIXME: This doesn't appear to be what Windows does */
2034     test_char = min(first_unicode_char - 1, 255);
2035     ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
2036        font_name, tmA.tmFirstChar, test_char);
2037 #endif
2038     if (lf->lfCharSet == SYMBOL_CHARSET)
2039     {
2040         test_char = min(last_unicode_char - 0xf000, 255);
2041         ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2042            font_name, tmA.tmLastChar, test_char);
2043     }
2044     else
2045     {
2046         test_char = min(last_unicode_char, 255);
2047         ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2048            font_name, tmA.tmLastChar, test_char);
2049     }
2050
2051     SetLastError(0xdeadbeef);
2052     ret = GetTextMetricsW(hdc, &tmW);
2053     ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2054        "GetTextMetricsW error %u\n", GetLastError());
2055     if (ret)
2056     {
2057         trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
2058               tmW.tmFirstChar, tmW.tmLastChar, tmA.tmFirstChar, tmA.tmLastChar,
2059               tmW.tmDefaultChar, tmA.tmDefaultChar, tmW.tmBreakChar, tmA.tmBreakChar);
2060
2061         if (lf->lfCharSet == SYMBOL_CHARSET)
2062         {
2063             /* It appears that for fonts with SYMBOL_CHARSET Windows always
2064              * sets symbol range to 0 - f0ff
2065              */
2066             ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
2067                font_name, tmW.tmFirstChar);
2068             /* FIXME: Windows returns f0ff here, while Wine f0xx */
2069             ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
2070                font_name, tmW.tmLastChar);
2071
2072             ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
2073                font_name, tmW.tmDefaultChar);
2074             ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
2075                font_name, tmW.tmBreakChar);
2076         }
2077         else
2078         {
2079             ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
2080                font_name, tmW.tmFirstChar, first_unicode_char);
2081             ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
2082                font_name, tmW.tmLastChar, last_unicode_char);
2083         }
2084         ret = GetDeviceCaps(hdc, LOGPIXELSX);
2085         ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2086            tmW.tmDigitizedAspectX, ret);
2087         ret = GetDeviceCaps(hdc, LOGPIXELSY);
2088         ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2089            tmW.tmDigitizedAspectX, ret);
2090     }
2091
2092     test_negative_width(hdc, lf);
2093
2094 end_of_test:
2095     SelectObject(hdc, hfont_old);
2096     DeleteObject(hfont);
2097
2098     ReleaseDC(0, hdc);
2099 }
2100
2101 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2102 {
2103     INT *enumed = (INT *)lParam;
2104
2105     if (type == TRUETYPE_FONTTYPE)
2106     {
2107         (*enumed)++;
2108         test_text_metrics(lf);
2109     }
2110     return 1;
2111 }
2112
2113 static void test_GetTextMetrics(void)
2114 {
2115     LOGFONTA lf;
2116     HDC hdc;
2117     INT enumed;
2118
2119     hdc = GetDC(0);
2120
2121     memset(&lf, 0, sizeof(lf));
2122     lf.lfCharSet = DEFAULT_CHARSET;
2123     enumed = 0;
2124     EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2125     trace("Tested metrics of %d truetype fonts\n", enumed);
2126
2127     ReleaseDC(0, hdc);
2128 }
2129
2130 static void test_nonexistent_font(void)
2131 {
2132     static const struct
2133     {
2134         const char *name;
2135         int charset;
2136     } font_subst[] =
2137     {
2138         { "Times New Roman Baltic", 186 },
2139         { "Times New Roman CE", 238 },
2140         { "Times New Roman CYR", 204 },
2141         { "Times New Roman Greek", 161 },
2142         { "Times New Roman TUR", 162 }
2143     };
2144     LOGFONTA lf;
2145     HDC hdc;
2146     HFONT hfont;
2147     CHARSETINFO csi;
2148     INT cs, expected_cs, i;
2149     char buf[LF_FACESIZE];
2150
2151     if (!is_truetype_font_installed("Arial") ||
2152         !is_truetype_font_installed("Times New Roman"))
2153     {
2154         skip("Arial or Times New Roman not installed\n");
2155         return;
2156     }
2157
2158     expected_cs = GetACP();
2159     if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2160     {
2161         skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2162         return;
2163     }
2164     expected_cs = csi.ciCharset;
2165     trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2166
2167     hdc = GetDC(0);
2168
2169     memset(&lf, 0, sizeof(lf));
2170     lf.lfHeight = 100;
2171     lf.lfWeight = FW_REGULAR;
2172     lf.lfCharSet = ANSI_CHARSET;
2173     lf.lfPitchAndFamily = FF_SWISS;
2174     strcpy(lf.lfFaceName, "Nonexistent font");
2175     hfont = CreateFontIndirectA(&lf);
2176     hfont = SelectObject(hdc, hfont);
2177     GetTextFaceA(hdc, sizeof(buf), buf);
2178     ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2179     cs = GetTextCharset(hdc);
2180     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2181     DeleteObject(SelectObject(hdc, hfont));
2182
2183     memset(&lf, 0, sizeof(lf));
2184     lf.lfHeight = -13;
2185     lf.lfWeight = FW_DONTCARE;
2186     strcpy(lf.lfFaceName, "Nonexistent font");
2187     hfont = CreateFontIndirectA(&lf);
2188     hfont = SelectObject(hdc, hfont);
2189     GetTextFaceA(hdc, sizeof(buf), buf);
2190 todo_wine /* Wine uses Arial for all substitutions */
2191     ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2192        !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2193        !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2194        "Got %s\n", buf);
2195     cs = GetTextCharset(hdc);
2196     ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2197     DeleteObject(SelectObject(hdc, hfont));
2198
2199     memset(&lf, 0, sizeof(lf));
2200     lf.lfHeight = -13;
2201     lf.lfWeight = FW_REGULAR;
2202     strcpy(lf.lfFaceName, "Nonexistent font");
2203     hfont = CreateFontIndirectA(&lf);
2204     hfont = SelectObject(hdc, hfont);
2205     GetTextFaceA(hdc, sizeof(buf), buf);
2206     ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2207        !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2208     cs = GetTextCharset(hdc);
2209     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2210     DeleteObject(SelectObject(hdc, hfont));
2211
2212     memset(&lf, 0, sizeof(lf));
2213     lf.lfHeight = -13;
2214     lf.lfWeight = FW_DONTCARE;
2215     strcpy(lf.lfFaceName, "Times New Roman");
2216     hfont = CreateFontIndirectA(&lf);
2217     hfont = SelectObject(hdc, hfont);
2218     GetTextFaceA(hdc, sizeof(buf), buf);
2219     ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2220     cs = GetTextCharset(hdc);
2221     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2222     DeleteObject(SelectObject(hdc, hfont));
2223
2224     for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2225     {
2226         memset(&lf, 0, sizeof(lf));
2227         lf.lfHeight = -13;
2228         lf.lfWeight = FW_REGULAR;
2229         strcpy(lf.lfFaceName, font_subst[i].name);
2230         hfont = CreateFontIndirectA(&lf);
2231         hfont = SelectObject(hdc, hfont);
2232         cs = GetTextCharset(hdc);
2233         if (font_subst[i].charset == expected_cs)
2234         {
2235             ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2236             GetTextFaceA(hdc, sizeof(buf), buf);
2237             ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2238         }
2239         else
2240         {
2241             ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2242             GetTextFaceA(hdc, sizeof(buf), buf);
2243             ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2244                !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2245         }
2246         DeleteObject(SelectObject(hdc, hfont));
2247
2248         memset(&lf, 0, sizeof(lf));
2249         lf.lfHeight = -13;
2250         lf.lfWeight = FW_DONTCARE;
2251         strcpy(lf.lfFaceName, font_subst[i].name);
2252         hfont = CreateFontIndirectA(&lf);
2253         hfont = SelectObject(hdc, hfont);
2254         GetTextFaceA(hdc, sizeof(buf), buf);
2255         ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2256            !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2257            !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2258            !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2259            "got %s\n", buf);
2260         cs = GetTextCharset(hdc);
2261         ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2262         DeleteObject(SelectObject(hdc, hfont));
2263     }
2264
2265     ReleaseDC(0, hdc);
2266 }
2267
2268 static void test_GdiRealizationInfo(void)
2269 {
2270     HDC hdc;
2271     DWORD info[4];
2272     BOOL r;
2273     HFONT hfont, hfont_old;
2274     LOGFONTA lf;
2275
2276     if(!pGdiRealizationInfo)
2277     {
2278         skip("GdiRealizationInfo not available\n");
2279         return;
2280     }
2281
2282     hdc = GetDC(0);
2283
2284     memset(info, 0xcc, sizeof(info));
2285     r = pGdiRealizationInfo(hdc, info);
2286     ok(r != 0, "ret 0\n");
2287     ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
2288     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2289
2290     if (!is_truetype_font_installed("Arial"))
2291     {
2292         skip("skipping GdiRealizationInfo with truetype font\n");
2293         goto end;
2294     }
2295
2296     memset(&lf, 0, sizeof(lf));
2297     strcpy(lf.lfFaceName, "Arial");
2298     lf.lfHeight = 20;
2299     lf.lfWeight = FW_NORMAL;
2300     hfont = CreateFontIndirectA(&lf);
2301     hfont_old = SelectObject(hdc, hfont);
2302
2303     memset(info, 0xcc, sizeof(info));
2304     r = pGdiRealizationInfo(hdc, info);
2305     ok(r != 0, "ret 0\n");
2306     ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
2307     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2308
2309     DeleteObject(SelectObject(hdc, hfont_old));
2310
2311  end:
2312     ReleaseDC(0, hdc);
2313 }
2314
2315 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2316    the nul in the count of characters copied when the face name buffer is not
2317    NULL, whereas it does if the buffer is NULL.  Further, the Unicode version
2318    always includes it.  */
2319 static void test_GetTextFace(void)
2320 {
2321     static const char faceA[] = "Tahoma";
2322     static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2323     LOGFONTA fA = {0};
2324     LOGFONTW fW = {0};
2325     char bufA[LF_FACESIZE];
2326     WCHAR bufW[LF_FACESIZE];
2327     HFONT f, g;
2328     HDC dc;
2329     int n;
2330
2331     if(!is_font_installed("Tahoma"))
2332     {
2333         skip("Tahoma is not installed so skipping this test\n");
2334         return;
2335     }
2336
2337     /* 'A' case.  */
2338     memcpy(fA.lfFaceName, faceA, sizeof faceA);
2339     f = CreateFontIndirectA(&fA);
2340     ok(f != NULL, "CreateFontIndirectA failed\n");
2341
2342     dc = GetDC(NULL);
2343     g = SelectObject(dc, f);
2344     n = GetTextFaceA(dc, sizeof bufA, bufA);
2345     ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2346     ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2347
2348     /* Play with the count arg.  */
2349     bufA[0] = 'x';
2350     n = GetTextFaceA(dc, 0, bufA);
2351     ok(n == 0, "GetTextFaceA returned %d\n", n);
2352     ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2353
2354     bufA[0] = 'x';
2355     n = GetTextFaceA(dc, 1, bufA);
2356     ok(n == 0, "GetTextFaceA returned %d\n", n);
2357     ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2358
2359     bufA[0] = 'x'; bufA[1] = 'y';
2360     n = GetTextFaceA(dc, 2, bufA);
2361     ok(n == 1, "GetTextFaceA returned %d\n", n);
2362     ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2363
2364     n = GetTextFaceA(dc, 0, NULL);
2365     ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
2366
2367     DeleteObject(SelectObject(dc, g));
2368     ReleaseDC(NULL, dc);
2369
2370     /* 'W' case.  */
2371     memcpy(fW.lfFaceName, faceW, sizeof faceW);
2372     SetLastError(0xdeadbeef);
2373     f = CreateFontIndirectW(&fW);
2374     if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2375     {
2376         win_skip("CreateFontIndirectW is not implemented\n");
2377         return;
2378     }
2379     ok(f != NULL, "CreateFontIndirectW failed\n");
2380
2381     dc = GetDC(NULL);
2382     g = SelectObject(dc, f);
2383     n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2384     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2385     ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2386
2387     /* Play with the count arg.  */
2388     bufW[0] = 'x';
2389     n = GetTextFaceW(dc, 0, bufW);
2390     ok(n == 0, "GetTextFaceW returned %d\n", n);
2391     ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2392
2393     bufW[0] = 'x';
2394     n = GetTextFaceW(dc, 1, bufW);
2395     ok(n == 1, "GetTextFaceW returned %d\n", n);
2396     ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2397
2398     bufW[0] = 'x'; bufW[1] = 'y';
2399     n = GetTextFaceW(dc, 2, bufW);
2400     ok(n == 2, "GetTextFaceW returned %d\n", n);
2401     ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2402
2403     n = GetTextFaceW(dc, 0, NULL);
2404     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2405
2406     DeleteObject(SelectObject(dc, g));
2407     ReleaseDC(NULL, dc);
2408 }
2409
2410 static void test_orientation(void)
2411 {
2412     static const char test_str[11] = "Test String";
2413     HDC hdc;
2414     LOGFONTA lf;
2415     HFONT hfont, old_hfont;
2416     SIZE size;
2417
2418     if (!is_truetype_font_installed("Arial"))
2419     {
2420         skip("Arial is not installed\n");
2421         return;
2422     }
2423
2424     hdc = CreateCompatibleDC(0);
2425     memset(&lf, 0, sizeof(lf));
2426     lstrcpyA(lf.lfFaceName, "Arial");
2427     lf.lfHeight = 72;
2428     lf.lfOrientation = lf.lfEscapement = 900;
2429     hfont = create_font("orientation", &lf);
2430     old_hfont = SelectObject(hdc, hfont);
2431     ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2432     ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2433     ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2434     SelectObject(hdc, old_hfont);
2435     DeleteObject(hfont);
2436     DeleteDC(hdc);
2437 }
2438
2439 START_TEST(font)
2440 {
2441     init();
2442
2443     test_logfont();
2444     test_bitmap_font();
2445     test_outline_font();
2446     test_bitmap_font_metrics();
2447     test_GdiGetCharDimensions();
2448     test_GetCharABCWidths();
2449     test_text_extents();
2450     test_GetGlyphIndices();
2451     test_GetKerningPairs();
2452     test_GetOutlineTextMetrics();
2453     test_SetTextJustification();
2454     test_font_charset();
2455     test_GetFontUnicodeRanges();
2456     test_nonexistent_font();
2457     test_orientation();
2458
2459     /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2460      * I'd like to avoid them in this test.
2461      */
2462     test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2463     test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2464     if (is_truetype_font_installed("Arial Black") &&
2465         (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2466     {
2467         test_EnumFontFamilies("", ANSI_CHARSET);
2468         test_EnumFontFamilies("", SYMBOL_CHARSET);
2469         test_EnumFontFamilies("", DEFAULT_CHARSET);
2470     }
2471     else
2472         skip("Arial Black or Symbol/Wingdings is not installed\n");
2473     test_GetTextMetrics();
2474     test_GdiRealizationInfo();
2475     test_GetTextFace();
2476 }