gdi32/tests: Added tests for vertical fonts.
[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 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
35
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
38
39 static LONG  (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 static DWORD (WINAPI *pGdiGetCodePage)(HDC hdc);
41 static BOOL  (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
42 static BOOL  (WINAPI *pGetCharABCWidthsA)(HDC hdc, UINT first, UINT last, LPABC abc);
43 static BOOL  (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
44 static BOOL  (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, LPABCFLOAT abc);
45 static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
46 static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
47 static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
48 static BOOL  (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
49 static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *);
50 static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
51 static BOOL  (WINAPI *pRemoveFontMemResourceEx)(HANDLE);
52 static INT   (WINAPI *pAddFontResourceExA)(LPCSTR, DWORD, PVOID);
53 static BOOL  (WINAPI *pRemoveFontResourceExA)(LPCSTR, DWORD, PVOID);
54
55 static HMODULE hgdi32 = 0;
56 static const MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
57
58 static void init(void)
59 {
60     hgdi32 = GetModuleHandleA("gdi32.dll");
61
62     pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
63     pGdiGetCodePage = (void *) GetProcAddress(hgdi32,"GdiGetCodePage");
64     pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
65     pGetCharABCWidthsA = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsA");
66     pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
67     pGetCharABCWidthsFloatW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsFloatW");
68     pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
69     pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
70     pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
71     pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
72     pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA");
73     pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx");
74     pRemoveFontMemResourceEx = (void *)GetProcAddress(hgdi32, "RemoveFontMemResourceEx");
75     pAddFontResourceExA = (void *)GetProcAddress(hgdi32, "AddFontResourceExA");
76     pRemoveFontResourceExA = (void *)GetProcAddress(hgdi32, "RemoveFontResourceExA");
77 }
78
79 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
80 {
81     if (type != TRUETYPE_FONTTYPE) return 1;
82
83     return 0;
84 }
85
86 static BOOL is_truetype_font_installed(const char *name)
87 {
88     HDC hdc = GetDC(0);
89     BOOL ret = FALSE;
90
91     if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
92         ret = TRUE;
93
94     ReleaseDC(0, hdc);
95     return ret;
96 }
97
98 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
99 {
100     return 0;
101 }
102
103 static BOOL is_font_installed(const char *name)
104 {
105     HDC hdc = GetDC(0);
106     BOOL ret = FALSE;
107
108     if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
109         ret = TRUE;
110
111     ReleaseDC(0, hdc);
112     return ret;
113 }
114
115 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
116 {
117     LOGFONTA getobj_lf;
118     int ret, minlen = 0;
119
120     if (!hfont)
121         return;
122
123     ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
124     /* NT4 tries to be clever and only returns the minimum length */
125     while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
126         minlen++;
127     minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
128     ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
129     ok(lf->lfHeight == getobj_lf.lfHeight ||
130        broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
131        "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
132     ok(lf->lfWidth == getobj_lf.lfWidth ||
133        broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
134        "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
135     ok(lf->lfEscapement == getobj_lf.lfEscapement ||
136        broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
137        "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
138     ok(lf->lfOrientation == getobj_lf.lfOrientation ||
139        broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
140        "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
141     ok(lf->lfWeight == getobj_lf.lfWeight ||
142        broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
143        "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
144     ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
145     ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
146     ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
147     ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
148     ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
149     ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
150     ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
151     ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
152     ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
153        broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
154        "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
155 }
156
157 static HFONT create_font(const char* test, const LOGFONTA* lf)
158 {
159     HFONT hfont = CreateFontIndirectA(lf);
160     ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
161     if (hfont)
162         check_font(test, lf, hfont);
163     return hfont;
164 }
165
166 static void test_logfont(void)
167 {
168     LOGFONTA lf;
169     HFONT hfont;
170
171     memset(&lf, 0, sizeof lf);
172
173     lf.lfCharSet = ANSI_CHARSET;
174     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
175     lf.lfWeight = FW_DONTCARE;
176     lf.lfHeight = 16;
177     lf.lfWidth = 16;
178     lf.lfQuality = DEFAULT_QUALITY;
179
180     lstrcpyA(lf.lfFaceName, "Arial");
181     hfont = create_font("Arial", &lf);
182     DeleteObject(hfont);
183
184     memset(&lf, 'A', sizeof(lf));
185     hfont = CreateFontIndirectA(&lf);
186     ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
187     
188     lf.lfFaceName[LF_FACESIZE - 1] = 0;
189     check_font("AAA...", &lf, hfont);
190     DeleteObject(hfont);
191 }
192
193 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
194 {
195     if (type & RASTER_FONTTYPE)
196     {
197         LOGFONT *lf = (LOGFONT *)lParam;
198         *lf = *elf;
199         return 0; /* stop enumeration */
200     }
201
202     return 1; /* continue enumeration */
203 }
204
205 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
206 {
207     ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
208     ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
209     ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
210     ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
211     ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
212     ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
213     ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
214     ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
215     ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
216     ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
217     ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
218     ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
219     ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
220     ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
221     ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
222     ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
223     ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
224     ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
225     ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
226     ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
227 }
228
229 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
230                               LONG lfWidth, const char *test_str,
231                               INT test_str_len, const TEXTMETRICA *tm_orig,
232                               const SIZE *size_orig, INT width_of_A_orig,
233                               INT scale_x, INT scale_y)
234 {
235     LOGFONTA lf;
236     OUTLINETEXTMETRIC otm;
237     TEXTMETRICA tm;
238     SIZE size;
239     INT width_of_A, cx, cy;
240     UINT ret;
241
242     if (!hfont)
243         return;
244
245     ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
246
247     GetObjectA(hfont, sizeof(lf), &lf);
248
249     if (GetOutlineTextMetricsA(hdc, 0, NULL))
250     {
251         otm.otmSize = sizeof(otm) / 2;
252         ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
253         ok(ret == sizeof(otm)/2 /* XP */ ||
254            ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
255
256         memset(&otm, 0x1, sizeof(otm));
257         otm.otmSize = sizeof(otm);
258         ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
259         ok(ret == sizeof(otm) /* XP */ ||
260            ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
261
262         memset(&tm, 0x2, sizeof(tm));
263         ret = GetTextMetricsA(hdc, &tm);
264         ok(ret, "GetTextMetricsA failed\n");
265         /* the structure size is aligned */
266         if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
267         {
268             ok(0, "tm != otm\n");
269             compare_tm(&tm, &otm.otmTextMetrics);
270         }
271
272         tm = otm.otmTextMetrics;
273 if (0) /* these metrics are scaled too, but with rounding errors */
274 {
275         ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
276         ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
277 }
278         ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
279         ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
280         ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
281         ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
282         ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
283         ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
284     }
285     else
286     {
287         ret = GetTextMetricsA(hdc, &tm);
288         ok(ret, "GetTextMetricsA failed\n");
289     }
290
291     cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
292     cy = tm.tmHeight / tm_orig->tmHeight;
293     ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
294        lfHeight, scale_x, scale_y, cx, cy);
295     ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
296     ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
297     ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
298     ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
299     ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
300
301     ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
302     if (lf.lfHeight)
303     {
304         if (lf.lfWidth)
305             ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
306     }
307     else
308         ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
309
310     GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
311
312     ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
313     ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
314
315     GetCharWidthA(hdc, 'A', 'A', &width_of_A);
316
317     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);
318 }
319
320 /* Test how GDI scales bitmap font metrics */
321 static void test_bitmap_font(void)
322 {
323     static const char test_str[11] = "Test String";
324     HDC hdc;
325     LOGFONTA bitmap_lf;
326     HFONT hfont, old_hfont;
327     TEXTMETRICA tm_orig;
328     SIZE size_orig;
329     INT ret, i, width_orig, height_orig, scale, lfWidth;
330
331     hdc = CreateCompatibleDC(0);
332
333     /* "System" has only 1 pixel size defined, otherwise the test breaks */
334     ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
335     if (ret)
336     {
337         ReleaseDC(0, hdc);
338         trace("no bitmap fonts were found, skipping the test\n");
339         return;
340     }
341
342     trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
343
344     height_orig = bitmap_lf.lfHeight;
345     lfWidth = bitmap_lf.lfWidth;
346
347     hfont = create_font("bitmap", &bitmap_lf);
348     old_hfont = SelectObject(hdc, hfont);
349     ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
350     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
351     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
352     SelectObject(hdc, old_hfont);
353     DeleteObject(hfont);
354
355     bitmap_lf.lfHeight = 0;
356     bitmap_lf.lfWidth = 4;
357     hfont = create_font("bitmap", &bitmap_lf);
358     old_hfont = SelectObject(hdc, hfont);
359     test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
360     SelectObject(hdc, old_hfont);
361     DeleteObject(hfont);
362
363     bitmap_lf.lfHeight = height_orig;
364     bitmap_lf.lfWidth = lfWidth;
365
366     /* test fractional scaling */
367     for (i = 1; i <= height_orig * 6; i++)
368     {
369         INT nearest_height;
370
371         bitmap_lf.lfHeight = i;
372         hfont = create_font("fractional", &bitmap_lf);
373         scale = (i + height_orig - 1) / height_orig;
374         nearest_height = scale * height_orig;
375         /* Only jump to the next height if the difference <= 25% original height */
376         if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
377         /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
378            so we'll not test this particular height. */
379         else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
380         else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
381         old_hfont = SelectObject(hdc, hfont);
382         test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
383         SelectObject(hdc, old_hfont);
384         DeleteObject(hfont);
385     }
386
387     /* test integer scaling 3x2 */
388     bitmap_lf.lfHeight = height_orig * 2;
389     bitmap_lf.lfWidth *= 3;
390     hfont = create_font("3x2", &bitmap_lf);
391     old_hfont = SelectObject(hdc, hfont);
392     test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
393     SelectObject(hdc, old_hfont);
394     DeleteObject(hfont);
395
396     /* test integer scaling 3x3 */
397     bitmap_lf.lfHeight = height_orig * 3;
398     bitmap_lf.lfWidth = 0;
399     hfont = create_font("3x3", &bitmap_lf);
400     old_hfont = SelectObject(hdc, hfont);
401     test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
402     SelectObject(hdc, old_hfont);
403     DeleteObject(hfont);
404
405     DeleteDC(hdc);
406 }
407
408 /* Test how GDI scales outline font metrics */
409 static void test_outline_font(void)
410 {
411     static const char test_str[11] = "Test String";
412     HDC hdc, hdc_2;
413     LOGFONTA lf;
414     HFONT hfont, old_hfont, old_hfont_2;
415     OUTLINETEXTMETRICA otm;
416     SIZE size_orig;
417     INT width_orig, height_orig, lfWidth;
418     XFORM xform;
419     GLYPHMETRICS gm;
420     MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
421     POINT pt;
422     INT ret;
423
424     if (!is_truetype_font_installed("Arial"))
425     {
426         skip("Arial is not installed\n");
427         return;
428     }
429
430     hdc = CreateCompatibleDC(0);
431
432     memset(&lf, 0, sizeof(lf));
433     strcpy(lf.lfFaceName, "Arial");
434     lf.lfHeight = 72;
435     hfont = create_font("outline", &lf);
436     old_hfont = SelectObject(hdc, hfont);
437     otm.otmSize = sizeof(otm);
438     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
439     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
440     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
441
442     test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
443     SelectObject(hdc, old_hfont);
444     DeleteObject(hfont);
445
446     /* font of otmEMSquare height helps to avoid a lot of rounding errors */
447     lf.lfHeight = otm.otmEMSquare;
448     lf.lfHeight = -lf.lfHeight;
449     hfont = create_font("outline", &lf);
450     old_hfont = SelectObject(hdc, hfont);
451     otm.otmSize = sizeof(otm);
452     ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
453     ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
454     ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
455     SelectObject(hdc, old_hfont);
456     DeleteObject(hfont);
457
458     height_orig = otm.otmTextMetrics.tmHeight;
459     lfWidth = otm.otmTextMetrics.tmAveCharWidth;
460
461     /* test integer scaling 3x2 */
462     lf.lfHeight = height_orig * 2;
463     lf.lfWidth = lfWidth * 3;
464     hfont = create_font("3x2", &lf);
465     old_hfont = SelectObject(hdc, hfont);
466     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
467     SelectObject(hdc, old_hfont);
468     DeleteObject(hfont);
469
470     /* test integer scaling 3x3 */
471     lf.lfHeight = height_orig * 3;
472     lf.lfWidth = lfWidth * 3;
473     hfont = create_font("3x3", &lf);
474     old_hfont = SelectObject(hdc, hfont);
475     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
476     SelectObject(hdc, old_hfont);
477     DeleteObject(hfont);
478
479     /* test integer scaling 1x1 */
480     lf.lfHeight = height_orig * 1;
481     lf.lfWidth = lfWidth * 1;
482     hfont = create_font("1x1", &lf);
483     old_hfont = SelectObject(hdc, hfont);
484     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
485     SelectObject(hdc, old_hfont);
486     DeleteObject(hfont);
487
488     /* test integer scaling 1x1 */
489     lf.lfHeight = height_orig;
490     lf.lfWidth = 0;
491     hfont = create_font("1x1", &lf);
492     old_hfont = SelectObject(hdc, hfont);
493     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
494
495     /* with an identity matrix */
496     memset(&gm, 0, sizeof(gm));
497     SetLastError(0xdeadbeef);
498     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
499     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
500     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
501     ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
502     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
503     /* with a custom matrix */
504     memset(&gm, 0, sizeof(gm));
505     SetLastError(0xdeadbeef);
506     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
507     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
508     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
509     ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
510     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
511
512     /* Test that changing the DC transformation affects only the font
513      * selected on this DC and doesn't affect the same font selected on
514      * another DC.
515      */
516     hdc_2 = CreateCompatibleDC(0);
517     old_hfont_2 = SelectObject(hdc_2, hfont);
518     test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
519
520     SetMapMode(hdc, MM_ANISOTROPIC);
521
522     /* font metrics on another DC should be unchanged */
523     test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
524
525     /* test restrictions of compatibility mode GM_COMPATIBLE */
526     /*  part 1: rescaling only X should not change font scaling on screen.
527                 So compressing the X axis by 2 is not done, and this
528                 appears as X scaling of 2 that no one requested. */
529     SetWindowExtEx(hdc, 100, 100, NULL);
530     SetViewportExtEx(hdc, 50, 100, NULL);
531     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
532     /* font metrics on another DC should be unchanged */
533     test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
534
535     /*  part 2: rescaling only Y should change font scaling.
536                 As also X is scaled by a factor of 2, but this is not
537                 requested by the DC transformation, we get a scaling factor
538                 of 2 in the X coordinate. */
539     SetViewportExtEx(hdc, 100, 200, NULL);
540     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
541     /* font metrics on another DC should be unchanged */
542     test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
543
544     /* restore scaling */
545     SetMapMode(hdc, MM_TEXT);
546
547     /* font metrics on another DC should be unchanged */
548     test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
549
550     SelectObject(hdc_2, old_hfont_2);
551     DeleteDC(hdc_2);
552
553     if (!SetGraphicsMode(hdc, GM_ADVANCED))
554     {
555         SelectObject(hdc, old_hfont);
556         DeleteObject(hfont);
557         DeleteDC(hdc);
558         skip("GM_ADVANCED is not supported on this platform\n");
559         return;
560     }
561
562     xform.eM11 = 20.0f;
563     xform.eM12 = 0.0f;
564     xform.eM21 = 0.0f;
565     xform.eM22 = 20.0f;
566     xform.eDx = 0.0f;
567     xform.eDy = 0.0f;
568
569     SetLastError(0xdeadbeef);
570     ret = SetWorldTransform(hdc, &xform);
571     ok(ret, "SetWorldTransform error %u\n", GetLastError());
572
573     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
574
575     /* with an identity matrix */
576     memset(&gm, 0, sizeof(gm));
577     SetLastError(0xdeadbeef);
578     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
579     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
580     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
581     pt.x = width_orig; pt.y = 0;
582     LPtoDP(hdc, &pt, 1);
583     ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
584     ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
585     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
586     /* with a custom matrix */
587     memset(&gm, 0, sizeof(gm));
588     SetLastError(0xdeadbeef);
589     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
590     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
591     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
592     pt.x = width_orig; pt.y = 0;
593     LPtoDP(hdc, &pt, 1);
594     ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
595     ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
596     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
597
598     SetLastError(0xdeadbeef);
599     ret = SetMapMode(hdc, MM_LOMETRIC);
600     ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
601
602     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
603
604     /* with an identity matrix */
605     memset(&gm, 0, sizeof(gm));
606     SetLastError(0xdeadbeef);
607     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
608     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
609     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
610     pt.x = width_orig; pt.y = 0;
611     LPtoDP(hdc, &pt, 1);
612     ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
613     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
614     /* with a custom matrix */
615     memset(&gm, 0, sizeof(gm));
616     SetLastError(0xdeadbeef);
617     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
618     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
619     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
620     pt.x = width_orig; pt.y = 0;
621     LPtoDP(hdc, &pt, 1);
622     ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
623     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
624
625     SetLastError(0xdeadbeef);
626     ret = SetMapMode(hdc, MM_TEXT);
627     ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
628
629     test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
630
631     /* with an identity matrix */
632     memset(&gm, 0, sizeof(gm));
633     SetLastError(0xdeadbeef);
634     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
635     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
636     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
637     pt.x = width_orig; pt.y = 0;
638     LPtoDP(hdc, &pt, 1);
639     ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
640     ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
641     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
642     /* with a custom matrix */
643     memset(&gm, 0, sizeof(gm));
644     SetLastError(0xdeadbeef);
645     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
646     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
647     trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
648     pt.x = width_orig; pt.y = 0;
649     LPtoDP(hdc, &pt, 1);
650     ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
651     ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
652     ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
653
654     SelectObject(hdc, old_hfont);
655     DeleteObject(hfont);
656     DeleteDC(hdc);
657 }
658
659 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
660 {
661     LOGFONT *lf = (LOGFONT *)lParam;
662
663     if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
664     {
665         *lf = *elf;
666         return 0; /* stop enumeration */
667     }
668     return 1; /* continue enumeration */
669 }
670
671 #define FH_SCALE 0x80000000
672 static void test_bitmap_font_metrics(void)
673 {
674     static const struct font_data
675     {
676         const char face_name[LF_FACESIZE];
677         int weight, height, ascent, descent, int_leading, ext_leading;
678         int ave_char_width, max_char_width, dpi;
679         BYTE first_char, last_char, def_char, break_char;
680         DWORD ansi_bitfield;
681         WORD skip_lang_id;
682         int scaled_height;
683     } fd[] =
684     {
685         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
686         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
687         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
688         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
689         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
690         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
691         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 13 },
692         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 13 },
693         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
694         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
695
696         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
697         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
698         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
699         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
700         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
701         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
702         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
703         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
704         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2, 0, 16 },
705         { "MS Sans Serif", FW_NORMAL, FH_SCALE | 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC, 0, 16 },
706
707         { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
708         { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
709         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
710         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
711         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
712         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
713         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
714         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
715         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
716         { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
717         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
718         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2 },
719         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
720         { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 },
721         { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2 },
722         { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
723
724         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
725         { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
726         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
727         { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
728         { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
729         { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
730         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
731         { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
732         { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
733         { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
734         { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1 | FS_LATIN2 },
735         { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC },
736
737         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
738         { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
739         { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
740         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
741         { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
742         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
743         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
744         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
745         { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
746         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
747         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
748         { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
749         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
750         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
751         { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
752         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
753         { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
754
755         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
756         { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
757         { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
758         { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
759         { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_CYRILLIC },
760         { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 },
761         { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
762         { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
763         { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
764         { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
765         { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
766
767         { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
768         { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
769         { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
770
771         { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
772         { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
773         { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
774
775         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
776         { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
777         { "System", FW_NORMAL, 18, 16, 2, 0, 2, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
778
779         { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
780         { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
781
782         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 },
783         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
784         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, 0, 0, 0, 0, FS_JISJAPAN },
785         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
786         { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
787         { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, 0, 0, 0, 0, FS_JISJAPAN },
788         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
789         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
790         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, 0, 0, 0, 0, FS_ARABIC },
791         { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, 0, 0, 0, 0, FS_JISJAPAN },
792         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1, LANG_ARABIC },
793         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
794         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, 0, 0, 0, 0, FS_ARABIC },
795         { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, 0, 0, 0, 0, FS_JISJAPAN },
796         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2, LANG_ARABIC },
797         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
798         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 9, 96, 0, 0, 0, 0, FS_ARABIC },
799         { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, 0, 0, 0, 0, FS_JISJAPAN },
800         { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC, LANG_ARABIC },
801         { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 4, 10, 96, 0, 0, 0, 0, FS_ARABIC },
802         { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, 0, 0, 0, 0, FS_JISJAPAN },
803
804         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
805         { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
806         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
807         { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
808         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_JISJAPAN },
809         { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2 | FS_CYRILLIC },
810         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
811         { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
812         { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
813         { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
814         { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
815         { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
816
817         { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 },
818         { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC },
819         { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, 0, 0, 0, 0, FS_JISJAPAN },
820
821         { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
822
823         /* FIXME: add "Terminal" */
824     };
825     static const int font_log_pixels[] = { 96, 120 };
826     HDC hdc;
827     LOGFONT lf;
828     HFONT hfont, old_hfont;
829     TEXTMETRIC tm;
830     INT ret, i, expected_cs, screen_log_pixels, diff, font_res;
831     WORD system_lang_id;
832     char face_name[LF_FACESIZE];
833     CHARSETINFO csi;
834
835     system_lang_id = PRIMARYLANGID(GetSystemDefaultLangID());
836     trace("system language id %04x\n", system_lang_id);
837
838     expected_cs = GetACP();
839     if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
840     {
841         skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
842         return;
843     }
844     expected_cs = csi.ciCharset;
845     trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
846
847     hdc = CreateCompatibleDC(0);
848     assert(hdc);
849
850     trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc, LOGPIXELSX),
851           GetDeviceCaps(hdc, LOGPIXELSY));
852
853     screen_log_pixels = GetDeviceCaps(hdc, LOGPIXELSY);
854     diff = 32768;
855     font_res = 0;
856     for (i = 0; i < sizeof(font_log_pixels)/sizeof(font_log_pixels[0]); i++)
857     {
858         int new_diff = abs(font_log_pixels[i] - screen_log_pixels);
859         if (new_diff < diff)
860         {
861             diff = new_diff;
862             font_res = font_log_pixels[i];
863         }
864     }
865     trace("best font resolution is %d\n", font_res);
866
867     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
868     {
869         int bit, height;
870
871         memset(&lf, 0, sizeof(lf));
872
873         height = fd[i].height & ~FH_SCALE;
874         lf.lfHeight = height;
875         strcpy(lf.lfFaceName, fd[i].face_name);
876
877         for(bit = 0; bit < 32; bit++)
878         {
879             GLYPHMETRICS gm;
880             DWORD fs[2];
881             BOOL bRet;
882
883             fs[0] = 1L << bit;
884             fs[1] = 0;
885             if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
886             if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
887
888             lf.lfCharSet = csi.ciCharset;
889             trace("looking for %s height %d charset %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
890             ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
891             if (fd[i].height & FH_SCALE)
892                 ok(ret, "scaled font height %d should not be enumerated\n", height);
893             else
894             {
895                 if (font_res == fd[i].dpi && lf.lfCharSet == expected_cs)
896                 {
897                     if (ret) /* FIXME: Remove once Wine is fixed */
898                         todo_wine ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
899                     else
900                         ok(!ret, "%s height %d charset %d dpi %d should be enumerated\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
901                 }
902             }
903             if (ret && !(fd[i].height & FH_SCALE))
904                 continue;
905
906             hfont = create_font(lf.lfFaceName, &lf);
907             old_hfont = SelectObject(hdc, hfont);
908
909             SetLastError(0xdeadbeef);
910             ret = GetTextFace(hdc, sizeof(face_name), face_name);
911             ok(ret, "GetTextFace error %u\n", GetLastError());
912
913             if (lstrcmp(face_name, fd[i].face_name) != 0)
914             {
915                 ok(ret != ANSI_CHARSET, "font charset should not be ANSI_CHARSET\n");
916                 ok(ret != expected_cs, "font charset %d should not be %d\n", ret, expected_cs);
917                 trace("Skipping replacement %s height %d charset %d\n", face_name, tm.tmHeight, tm.tmCharSet);
918                 SelectObject(hdc, old_hfont);
919                 DeleteObject(hfont);
920                 continue;
921             }
922
923             memset(&gm, 0, sizeof(gm));
924             SetLastError(0xdeadbeef);
925             ret = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
926             todo_wine {
927             ok(ret == GDI_ERROR, "GetGlyphOutline should fail for a bitmap font\n");
928             ok(GetLastError() == ERROR_CAN_NOT_COMPLETE, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
929             }
930
931             bRet = GetTextMetrics(hdc, &tm);
932             ok(bRet, "GetTextMetrics error %d\n", GetLastError());
933
934             SetLastError(0xdeadbeef);
935             ret = GetTextCharset(hdc);
936             ok(ret == expected_cs, "got charset %d, expected %d\n", ret, expected_cs);
937
938             trace("created %s, height %d charset %x dpi %d\n", face_name, tm.tmHeight, tm.tmCharSet, tm.tmDigitizedAspectX);
939             trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd[i].face_name, height, fd[i].scaled_height, fd[i].dpi);
940
941             if(fd[i].dpi == tm.tmDigitizedAspectX)
942             {
943                 trace("matched %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
944                 if (fd[i].skip_lang_id == 0 || system_lang_id != fd[i].skip_lang_id)
945                 {
946                     ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, height, tm.tmWeight, fd[i].weight);
947                     if (fd[i].height & FH_SCALE)
948                         ok(tm.tmHeight == fd[i].scaled_height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, height, tm.tmHeight, fd[i].scaled_height);
949                     else
950                         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);
951                     ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, height, tm.tmAscent, fd[i].ascent);
952                     ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, height, tm.tmDescent, fd[i].descent);
953                     ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, height, tm.tmInternalLeading, fd[i].int_leading);
954                     ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, height, tm.tmExternalLeading, fd[i].ext_leading);
955                     ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, height, tm.tmAveCharWidth, fd[i].ave_char_width);
956                     ok(tm.tmFirstChar == fd[i].first_char, "%s(%d): tm.tmFirstChar = %02x\n", fd[i].face_name, height, tm.tmFirstChar);
957                     ok(tm.tmLastChar == fd[i].last_char, "%s(%d): tm.tmLastChar = %02x\n", fd[i].face_name, height, tm.tmLastChar);
958                     /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
959                        make default char test fail */
960                     if (tm.tmCharSet == lf.lfCharSet)
961                         ok(tm.tmDefaultChar == fd[i].def_char, "%s(%d): tm.tmDefaultChar = %02x\n", fd[i].face_name, height, tm.tmDefaultChar);
962                     ok(tm.tmBreakChar == fd[i].break_char, "%s(%d): tm.tmBreakChar = %02x\n", fd[i].face_name, height, tm.tmBreakChar);
963                     ok(tm.tmCharSet == expected_cs || tm.tmCharSet == ANSI_CHARSET, "%s(%d): tm.tmCharSet %d != %d\n", fd[i].face_name, height, tm.tmCharSet, expected_cs);
964
965                     /* Don't run the max char width test on System/ANSI_CHARSET.  We have extra characters in our font
966                        that make the max width bigger */
967                     if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
968                         ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, height, tm.tmMaxCharWidth, fd[i].max_char_width);
969                 }
970                 else
971                     skip("Skipping font metrics test for system langid 0x%x\n",
972                          system_lang_id);
973             }
974             SelectObject(hdc, old_hfont);
975             DeleteObject(hfont);
976         }
977     }
978
979     DeleteDC(hdc);
980 }
981
982 static void test_GdiGetCharDimensions(void)
983 {
984     HDC hdc;
985     TEXTMETRICW tm;
986     LONG ret;
987     SIZE size;
988     LONG avgwidth, height;
989     static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
990
991     if (!pGdiGetCharDimensions)
992     {
993         win_skip("GdiGetCharDimensions not available on this platform\n");
994         return;
995     }
996
997     hdc = CreateCompatibleDC(NULL);
998
999     GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
1000     avgwidth = ((size.cx / 26) + 1) / 2;
1001
1002     ret = pGdiGetCharDimensions(hdc, &tm, &height);
1003     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1004     ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
1005
1006     ret = pGdiGetCharDimensions(hdc, &tm, NULL);
1007     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1008
1009     ret = pGdiGetCharDimensions(hdc, NULL, NULL);
1010     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1011
1012     height = 0;
1013     ret = pGdiGetCharDimensions(hdc, NULL, &height);
1014     ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
1015     ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
1016
1017     DeleteDC(hdc);
1018 }
1019
1020 static int CALLBACK create_font_proc(const LOGFONT *lpelfe,
1021                                      const TEXTMETRIC *lpntme,
1022                                      DWORD FontType, LPARAM lParam)
1023 {
1024     if (FontType & TRUETYPE_FONTTYPE)
1025     {
1026         HFONT hfont;
1027
1028         hfont = CreateFontIndirect(lpelfe);
1029         if (hfont)
1030         {
1031             *(HFONT *)lParam = hfont;
1032             return 0;
1033         }
1034     }
1035
1036     return 1;
1037 }
1038
1039 static void test_GetCharABCWidths(void)
1040 {
1041     static const WCHAR str[] = {'a',0};
1042     BOOL ret;
1043     HDC hdc;
1044     LOGFONTA lf;
1045     HFONT hfont;
1046     ABC abc[1];
1047     ABCFLOAT abcf[1];
1048     WORD glyphs[1];
1049     DWORD nb;
1050     static const struct
1051     {
1052         UINT first;
1053         UINT last;
1054     } range[] =
1055     {
1056         {0xff, 0xff},
1057         {0x100, 0x100},
1058         {0xff, 0x100},
1059         {0x1ff, 0xff00},
1060         {0xffff, 0xffff},
1061         {0x10000, 0x10000},
1062         {0xffff, 0x10000},
1063         {0xffffff, 0xffffff},
1064         {0x1000000, 0x1000000},
1065         {0xffffff, 0x1000000},
1066         {0xffffffff, 0xffffffff},
1067         {0x00, 0xff}
1068     };
1069     static const struct
1070     {
1071         UINT cs;
1072         UINT a;
1073         UINT w;
1074         BOOL r[sizeof range / sizeof range[0]];
1075     } c[] =
1076     {
1077         {ANSI_CHARSET, 0x30, 0x30,
1078          {TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1079         {SHIFTJIS_CHARSET, 0x82a0, 0x3042,
1080          {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1081         {HANGEUL_CHARSET, 0x8141, 0xac02,
1082          {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1083         {JOHAB_CHARSET, 0x8446, 0x3135,
1084          {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1085         {GB2312_CHARSET, 0x8141, 0x4e04,
1086          {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}},
1087         {CHINESEBIG5_CHARSET, 0xa142, 0x3001,
1088          {TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE}}
1089     };
1090     UINT i;
1091
1092     if (!pGetCharABCWidthsA || !pGetCharABCWidthsW || !pGetCharABCWidthsFloatW || !pGetCharABCWidthsI)
1093     {
1094         win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1095         return;
1096     }
1097
1098     memset(&lf, 0, sizeof(lf));
1099     strcpy(lf.lfFaceName, "System");
1100     lf.lfHeight = 20;
1101
1102     hfont = CreateFontIndirectA(&lf);
1103     hdc = GetDC(0);
1104     hfont = SelectObject(hdc, hfont);
1105
1106     nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
1107     ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
1108
1109     ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
1110     ok(!ret, "GetCharABCWidthsI should have failed\n");
1111
1112     ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
1113     ok(!ret, "GetCharABCWidthsI should have failed\n");
1114
1115     ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
1116     ok(ret, "GetCharABCWidthsI should have succeeded\n");
1117
1118     ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
1119     ok(!ret, "GetCharABCWidthsW should have failed\n");
1120
1121     ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
1122     ok(!ret, "GetCharABCWidthsW should have failed\n");
1123
1124     ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
1125     ok(!ret, "GetCharABCWidthsW should have failed\n");
1126
1127     ret = pGetCharABCWidthsFloatW(NULL, 'a', 'a', abcf);
1128     ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1129
1130     ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', NULL);
1131     ok(!ret, "GetCharABCWidthsFloatW should have failed\n");
1132
1133     ret = pGetCharABCWidthsFloatW(hdc, 'a', 'a', abcf);
1134     ok(ret, "GetCharABCWidthsFloatW should have succeeded\n");
1135
1136     hfont = SelectObject(hdc, hfont);
1137     DeleteObject(hfont);
1138
1139     for (i = 0; i < sizeof c / sizeof c[0]; ++i)
1140     {
1141         ABC a[2], w[2];
1142         ABC full[256];
1143         UINT code = 0x41, j;
1144
1145         lf.lfFaceName[0] = '\0';
1146         lf.lfCharSet = c[i].cs;
1147         lf.lfPitchAndFamily = 0;
1148         if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
1149         {
1150             skip("TrueType font for charset %u is not installed\n", c[i].cs);
1151             continue;
1152         }
1153
1154         memset(a, 0, sizeof a);
1155         memset(w, 0, sizeof w);
1156         hfont = SelectObject(hdc, hfont);
1157         ok(pGetCharABCWidthsA(hdc, c[i].a, c[i].a + 1, a) &&
1158            pGetCharABCWidthsW(hdc, c[i].w, c[i].w + 1, w) &&
1159            memcmp(a, w, sizeof a) == 0,
1160            "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c[i].cs);
1161
1162         memset(a, 0xbb, sizeof a);
1163         ret = pGetCharABCWidthsA(hdc, code, code, a);
1164         ok(ret, "GetCharABCWidthsA should have succeeded\n");
1165         memset(full, 0xcc, sizeof full);
1166         ret = pGetCharABCWidthsA(hdc, 0x00, code, full);
1167         ok(ret, "GetCharABCWidthsA should have succeeded\n");
1168         ok(memcmp(&a[0], &full[code], sizeof(ABC)) == 0,
1169            "GetCharABCWidthsA info should match. codepage = %u\n", c[i].cs);
1170
1171         for (j = 0; j < sizeof range / sizeof range[0]; ++j)
1172         {
1173             memset(full, 0xdd, sizeof full);
1174             ret = pGetCharABCWidthsA(hdc, range[j].first, range[j].last, full);
1175             ok(ret == c[i].r[j], "GetCharABCWidthsA %x - %x should have %s\n",
1176                range[j].first, range[j].last, c[i].r[j] ? "succeeded" : "failed");
1177             if (ret)
1178             {
1179                 UINT last = range[j].last - range[j].first;
1180                 ret = pGetCharABCWidthsA(hdc, range[j].last, range[j].last, a);
1181                 ok(ret && memcmp(&full[last], &a[0], sizeof(ABC)) == 0,
1182                    "GetCharABCWidthsA %x should match. codepage = %u\n",
1183                    range[j].last, c[i].cs);
1184             }
1185         }
1186
1187         hfont = SelectObject(hdc, hfont);
1188         DeleteObject(hfont);
1189     }
1190
1191     ReleaseDC(NULL, hdc);
1192 }
1193
1194 static void test_text_extents(void)
1195 {
1196     static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
1197     LPINT extents;
1198     INT i, len, fit1, fit2;
1199     LOGFONTA lf;
1200     TEXTMETRICA tm;
1201     HDC hdc;
1202     HFONT hfont;
1203     SIZE sz;
1204     SIZE sz1, sz2;
1205     BOOL ret;
1206
1207     memset(&lf, 0, sizeof(lf));
1208     strcpy(lf.lfFaceName, "Arial");
1209     lf.lfHeight = 20;
1210
1211     hfont = CreateFontIndirectA(&lf);
1212     hdc = GetDC(0);
1213     hfont = SelectObject(hdc, hfont);
1214     GetTextMetricsA(hdc, &tm);
1215     GetTextExtentPointA(hdc, "o", 1, &sz);
1216     ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1217
1218     SetLastError(0xdeadbeef);
1219     GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1220     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1221     {
1222         win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1223         hfont = SelectObject(hdc, hfont);
1224         DeleteObject(hfont);
1225         ReleaseDC(0, hdc);
1226         return;
1227     }
1228
1229     len = lstrlenW(wt);
1230     extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1231     extents[0] = 1;         /* So that the increasing sequence test will fail
1232                                if the extents array is untouched.  */
1233     GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1234     GetTextExtentPointW(hdc, wt, len, &sz2);
1235     ok(sz1.cy == sz2.cy,
1236        "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1237     /* Because of the '\n' in the string GetTextExtentExPoint and
1238        GetTextExtentPoint return different widths under Win2k, but
1239        under WinXP they return the same width.  So we don't test that
1240        here. */
1241
1242     for (i = 1; i < len; ++i)
1243         ok(extents[i-1] <= extents[i],
1244            "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1245            i);
1246     ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1247     ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1248     ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1249     GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1250     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1251     ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1252     GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1253     ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1254     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1255     ok(extents[0] == extents[2] && extents[1] == extents[3],
1256        "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1257     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1258     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1259        "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1260     HeapFree(GetProcessHeap(), 0, extents);
1261
1262     /* extents functions fail with -ve counts (the interesting case being -1) */
1263     ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1264     ok(ret == FALSE, "got %d\n", ret);
1265     ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1266     ok(ret == FALSE, "got %d\n", ret);
1267     ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1268     ok(ret == FALSE, "got %d\n", ret);
1269
1270     /* max_extent = 0 succeeds and returns zero */
1271     fit1 = fit2 = -215;
1272     ret = GetTextExtentExPointA(hdc, NULL, 0, 0, &fit1, NULL, &sz);
1273     ok(ret == TRUE ||
1274        broken(ret == FALSE), /* NT4, 2k */
1275        "got %d\n", ret);
1276     ok(fit1 == 0 ||
1277        broken(fit1 == -215), /* NT4, 2k */
1278        "fit = %d\n", fit1);
1279     ret = GetTextExtentExPointW(hdc, NULL, 0, 0, &fit2, NULL, &sz1);
1280     ok(ret == TRUE, "got %d\n", ret);
1281     ok(fit2 == 0, "fit = %d\n", fit2);
1282
1283     /* max_extent = -1 is interpreted as a very large width that will
1284      * definitely fit our three characters */
1285     fit1 = fit2 = -215;
1286     ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz);
1287     ok(ret == TRUE, "got %d\n", ret);
1288     todo_wine ok(fit1 == 3, "fit = %d\n", fit1);
1289     ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz);
1290     ok(ret == TRUE, "got %d\n", ret);
1291     todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1292
1293     /* max_extent = -2 is interpreted similarly, but the Ansi version
1294      * rejects it while the Unicode one accepts it */
1295     fit1 = fit2 = -215;
1296     ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz);
1297     todo_wine ok(ret == FALSE, "got %d\n", ret);
1298     todo_wine ok(fit1 == -215, "fit = %d\n", fit1);
1299     ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz);
1300     ok(ret == TRUE, "got %d\n", ret);
1301     todo_wine ok(fit2 == 3, "fit = %d\n", fit2);
1302
1303     hfont = SelectObject(hdc, hfont);
1304     DeleteObject(hfont);
1305     ReleaseDC(NULL, hdc);
1306 }
1307
1308 static void test_GetGlyphIndices(void)
1309 {
1310     HDC      hdc;
1311     HFONT    hfont;
1312     DWORD    charcount;
1313     LOGFONTA lf;
1314     DWORD    flags = 0;
1315     WCHAR    testtext[] = {'T','e','s','t',0xffff,0};
1316     WORD     glyphs[(sizeof(testtext)/2)-1];
1317     TEXTMETRIC textm;
1318     HFONT hOldFont;
1319
1320     if (!pGetGlyphIndicesW) {
1321         win_skip("GetGlyphIndicesW not available on platform\n");
1322         return;
1323     }
1324
1325     hdc = GetDC(0);
1326
1327     memset(&lf, 0, sizeof(lf));
1328     strcpy(lf.lfFaceName, "System");
1329     lf.lfHeight = 16;
1330     lf.lfCharSet = ANSI_CHARSET;
1331
1332     hfont = CreateFontIndirectA(&lf);
1333     ok(hfont != 0, "CreateFontIndirectEx failed\n");
1334     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1335     if (textm.tmCharSet == ANSI_CHARSET)
1336     {
1337         flags |= GGI_MARK_NONEXISTING_GLYPHS;
1338         charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1339         ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1340         ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1341         flags = 0;
1342         charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1343         ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1344         ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1345                         textm.tmDefaultChar, glyphs[4]);
1346     }
1347     else
1348         /* FIXME: Write tests for non-ANSI charsets. */
1349         skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1350
1351     if(!is_font_installed("Tahoma"))
1352     {
1353         skip("Tahoma is not installed so skipping this test\n");
1354         return;
1355     }
1356     memset(&lf, 0, sizeof(lf));
1357     strcpy(lf.lfFaceName, "Tahoma");
1358     lf.lfHeight = 20;
1359
1360     hfont = CreateFontIndirectA(&lf);
1361     hOldFont = SelectObject(hdc, hfont);
1362     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1363     flags |= GGI_MARK_NONEXISTING_GLYPHS;
1364     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1365     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1366     ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1367     flags = 0;
1368     testtext[0] = textm.tmDefaultChar;
1369     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1370     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1371     ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1372     ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1373     DeleteObject(SelectObject(hdc, hOldFont));
1374 }
1375
1376 static void test_GetKerningPairs(void)
1377 {
1378     static const struct kerning_data
1379     {
1380         const char face_name[LF_FACESIZE];
1381         LONG height;
1382         /* some interesting fields from OUTLINETEXTMETRIC */
1383         LONG tmHeight, tmAscent, tmDescent;
1384         UINT otmEMSquare;
1385         INT  otmAscent;
1386         INT  otmDescent;
1387         UINT otmLineGap;
1388         UINT otmsCapEmHeight;
1389         UINT otmsXHeight;
1390         INT  otmMacAscent;
1391         INT  otmMacDescent;
1392         UINT otmMacLineGap;
1393         UINT otmusMinimumPPEM;
1394         /* small subset of kerning pairs to test */
1395         DWORD total_kern_pairs;
1396         const KERNINGPAIR kern_pair[26];
1397     } kd[] =
1398     {
1399         {"Arial", 12, 12, 9, 3,
1400                   2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1401                   26,
1402             {
1403                 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1404                 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1405                 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1406                 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1407                 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1408                 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1409                 {933,970,+1},{933,972,-1}
1410                 }
1411         },
1412         {"Arial", -34, 39, 32, 7,
1413                   2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1414                   26,
1415             {
1416                 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1417                 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1418                 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1419                 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1420                 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1421                 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1422                 {933,970,+2},{933,972,-3}
1423             }
1424         },
1425         { "Arial", 120, 120, 97, 23,
1426                    2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1427                    26,
1428             {
1429                 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1430                 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1431                 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1432                 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1433                 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1434                 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1435                 {933,970,+6},{933,972,-10}
1436             }
1437         },
1438 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1439         { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1440                    2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1441                    26,
1442             {
1443                 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1444                 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1445                 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1446                 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1447                 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1448                 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1449                 {933,970,+54},{933,972,-83}
1450             }
1451         }
1452 #endif
1453     };
1454     LOGFONT lf;
1455     HFONT hfont, hfont_old;
1456     KERNINGPAIR *kern_pair;
1457     HDC hdc;
1458     DWORD total_kern_pairs, ret, i, n, matches;
1459
1460     hdc = GetDC(0);
1461
1462     /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1463      * which may render this test unusable, so we're trying to avoid that.
1464      */
1465     SetLastError(0xdeadbeef);
1466     GetKerningPairsW(hdc, 0, NULL);
1467     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1468     {
1469         win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1470         ReleaseDC(0, hdc);
1471         return;
1472     }
1473
1474     for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1475     {
1476         OUTLINETEXTMETRICW otm;
1477         UINT uiRet;
1478
1479         if (!is_font_installed(kd[i].face_name))
1480         {
1481             trace("%s is not installed so skipping this test\n", kd[i].face_name);
1482             continue;
1483         }
1484
1485         trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1486
1487         memset(&lf, 0, sizeof(lf));
1488         strcpy(lf.lfFaceName, kd[i].face_name);
1489         lf.lfHeight = kd[i].height;
1490         hfont = CreateFontIndirect(&lf);
1491         assert(hfont != 0);
1492
1493         hfont_old = SelectObject(hdc, hfont);
1494
1495         SetLastError(0xdeadbeef);
1496         otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1497         uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1498         ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1499
1500         ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1501            kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1502         ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1503            kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1504         ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1505            kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1506
1507         ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1508            kd[i].otmEMSquare, otm.otmEMSquare);
1509         ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1510            kd[i].otmAscent, otm.otmAscent);
1511         ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1512            kd[i].otmDescent, otm.otmDescent);
1513         ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1514            kd[i].otmLineGap, otm.otmLineGap);
1515         ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1516            kd[i].otmMacDescent, otm.otmMacDescent);
1517         ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1518            kd[i].otmMacAscent, otm.otmMacAscent);
1519 todo_wine {
1520         ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1521            kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1522         ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1523            kd[i].otmsXHeight, otm.otmsXHeight);
1524         /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1525         if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1526            kd[i].otmMacLineGap, otm.otmMacLineGap);
1527         ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1528            kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1529 }
1530
1531         total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1532         trace("total_kern_pairs %u\n", total_kern_pairs);
1533         kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1534
1535         /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1536          * passes on XP.
1537          */
1538         SetLastError(0xdeadbeef);
1539         ret = GetKerningPairsW(hdc, 0, kern_pair);
1540         ok(GetLastError() == ERROR_INVALID_PARAMETER,
1541            "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1542         ok(ret == 0, "got %u, expected 0\n", ret);
1543
1544         ret = GetKerningPairsW(hdc, 100, NULL);
1545         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1546
1547         ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1548         ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1549
1550         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1551         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1552
1553         matches = 0;
1554
1555         for (n = 0; n < ret; n++)
1556         {
1557             DWORD j;
1558             /* Disabled to limit console spam */
1559             if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1560                 trace("{'%c','%c',%d},\n",
1561                       kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1562             for (j = 0; j < kd[i].total_kern_pairs; j++)
1563             {
1564                 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1565                     kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1566                 {
1567                     ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1568                        "pair %d:%d got %d, expected %d\n",
1569                        kern_pair[n].wFirst, kern_pair[n].wSecond,
1570                        kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1571                     matches++;
1572                 }
1573             }
1574         }
1575
1576         ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1577            matches, kd[i].total_kern_pairs);
1578
1579         HeapFree(GetProcessHeap(), 0, kern_pair);
1580
1581         SelectObject(hdc, hfont_old);
1582         DeleteObject(hfont);
1583     }
1584
1585     ReleaseDC(0, hdc);
1586 }
1587
1588 static void test_height_selection(void)
1589 {
1590     static const struct font_data
1591     {
1592         const char face_name[LF_FACESIZE];
1593         int requested_height;
1594         int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1595     } fd[] =
1596     {
1597         {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1598         {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1599         {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1600         {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1601         {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1602         {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1603         {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1604         {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1605         {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1606         {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1607     };
1608     HDC hdc;
1609     LOGFONT lf;
1610     HFONT hfont, old_hfont;
1611     TEXTMETRIC tm;
1612     INT ret, i;
1613
1614     hdc = CreateCompatibleDC(0);
1615     assert(hdc);
1616
1617     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1618     {
1619         if (!is_truetype_font_installed(fd[i].face_name))
1620         {
1621             skip("%s is not installed\n", fd[i].face_name);
1622             continue;
1623         }
1624
1625         memset(&lf, 0, sizeof(lf));
1626         lf.lfHeight = fd[i].requested_height;
1627         lf.lfWeight = fd[i].weight;
1628         strcpy(lf.lfFaceName, fd[i].face_name);
1629
1630         hfont = CreateFontIndirect(&lf);
1631         assert(hfont);
1632
1633         old_hfont = SelectObject(hdc, hfont);
1634         ret = GetTextMetrics(hdc, &tm);
1635         ok(ret, "GetTextMetrics error %d\n", GetLastError());
1636         if(fd[i].dpi == tm.tmDigitizedAspectX)
1637         {
1638             trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1639             ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1640             ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1641             ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1642             ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1643 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1644             ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1645 #endif
1646             ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1647         }
1648
1649         SelectObject(hdc, old_hfont);
1650         DeleteObject(hfont);
1651     }
1652
1653     DeleteDC(hdc);
1654 }
1655
1656 static void test_GetOutlineTextMetrics(void)
1657 {
1658     OUTLINETEXTMETRIC *otm;
1659     LOGFONT lf;
1660     HFONT hfont, hfont_old;
1661     HDC hdc;
1662     DWORD ret, otm_size;
1663     LPSTR unset_ptr;
1664
1665     if (!is_font_installed("Arial"))
1666     {
1667         skip("Arial is not installed\n");
1668         return;
1669     }
1670
1671     hdc = GetDC(0);
1672
1673     memset(&lf, 0, sizeof(lf));
1674     strcpy(lf.lfFaceName, "Arial");
1675     lf.lfHeight = -13;
1676     lf.lfWeight = FW_NORMAL;
1677     lf.lfPitchAndFamily = DEFAULT_PITCH;
1678     lf.lfQuality = PROOF_QUALITY;
1679     hfont = CreateFontIndirect(&lf);
1680     assert(hfont != 0);
1681
1682     hfont_old = SelectObject(hdc, hfont);
1683     otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1684     trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1685
1686     otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1687
1688     memset(otm, 0xAA, otm_size);
1689     SetLastError(0xdeadbeef);
1690     otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1691     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1692     ok(ret == 1 /* Win9x */ ||
1693        ret == otm->otmSize /* XP*/,
1694        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1695     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1696     {
1697         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1698         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1699         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1700         ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1701     }
1702
1703     memset(otm, 0xAA, otm_size);
1704     SetLastError(0xdeadbeef);
1705     otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1706     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1707     ok(ret == 1 /* Win9x */ ||
1708        ret == otm->otmSize /* XP*/,
1709        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1710     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1711     {
1712         ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1713         ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1714         ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1715         ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1716     }
1717
1718     /* ask about truncated data */
1719     memset(otm, 0xAA, otm_size);
1720     memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1721     SetLastError(0xdeadbeef);
1722     otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1723     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1724     ok(ret == 1 /* Win9x */ ||
1725        ret == otm->otmSize /* XP*/,
1726        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1727     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1728     {
1729         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1730         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1731         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1732     }
1733     ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1734
1735     HeapFree(GetProcessHeap(), 0, otm);
1736
1737     SelectObject(hdc, hfont_old);
1738     DeleteObject(hfont);
1739
1740     ReleaseDC(0, hdc);
1741 }
1742
1743 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1744 {
1745     INT         y,
1746                 breakCount,
1747                 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1748                 areaWidth = clientArea->right - clientArea->left,
1749                 nErrors = 0, e;
1750     BOOL        lastExtent = FALSE;
1751     PSTR        pFirstChar, pLastChar;
1752     SIZE        size;
1753     TEXTMETRICA tm;
1754     struct err
1755     {
1756         char extent[100];
1757         int  GetTextExtentExPointWWidth;
1758     } error[10];
1759
1760     GetTextMetricsA(hdc, &tm);
1761     y = clientArea->top;
1762     do {
1763         breakCount = 0;
1764         while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1765         pFirstChar = str;
1766
1767         do {
1768             pLastChar = str;
1769
1770             /* if not at the end of the string, ... */
1771             if (*str == '\0') break;
1772             /* ... add the next word to the current extent */
1773             while (*str != '\0' && *str++ != tm.tmBreakChar);
1774             breakCount++;
1775             SetTextJustification(hdc, 0, 0);
1776             GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1777         } while ((int) size.cx < areaWidth);
1778
1779         /* ignore trailing break chars */
1780         breakCount--;
1781         while (*(pLastChar - 1) == tm.tmBreakChar)
1782         {
1783             pLastChar--;
1784             breakCount--;
1785         }
1786
1787         if (*str == '\0' || breakCount <= 0) pLastChar = str;
1788
1789         SetTextJustification(hdc, 0, 0);
1790         GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1791
1792         /* do not justify the last extent */
1793         if (*str != '\0' && breakCount > 0)
1794         {
1795             SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1796             GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1797             justifiedWidth = size.cx;
1798         }
1799         else lastExtent = TRUE;
1800
1801         /* catch errors and report them */
1802         if (!lastExtent && (justifiedWidth != areaWidth))
1803         {
1804             memset(error[nErrors].extent, 0, 100);
1805             memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1806             error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1807             nErrors++;
1808         }
1809
1810         y += size.cy;
1811         str = pLastChar;
1812     } while (*str && y < clientArea->bottom);
1813
1814     for (e = 0; e < nErrors; e++)
1815     {
1816         /* The width returned by GetTextExtentPoint32() is exactly the same
1817            returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1818         ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1819             "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1820             error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1821     }
1822 }
1823
1824 static void test_SetTextJustification(void)
1825 {
1826     HDC hdc;
1827     RECT clientArea;
1828     LOGFONTA lf;
1829     HFONT hfont;
1830     HWND hwnd;
1831     static char testText[] =
1832             "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1833             "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1834             "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1835             "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1836             "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1837             "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1838             "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1839
1840     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1841     GetClientRect( hwnd, &clientArea );
1842     hdc = GetDC( hwnd );
1843
1844     memset(&lf, 0, sizeof lf);
1845     lf.lfCharSet = ANSI_CHARSET;
1846     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1847     lf.lfWeight = FW_DONTCARE;
1848     lf.lfHeight = 20;
1849     lf.lfQuality = DEFAULT_QUALITY;
1850     lstrcpyA(lf.lfFaceName, "Times New Roman");
1851     hfont = create_font("Times New Roman", &lf);
1852     SelectObject(hdc, hfont);
1853
1854     testJustification(hdc, testText, &clientArea);
1855
1856     DeleteObject(hfont);
1857     ReleaseDC(hwnd, hdc);
1858     DestroyWindow(hwnd);
1859 }
1860
1861 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1862 {
1863     HDC hdc;
1864     LOGFONTA lf;
1865     HFONT hfont, hfont_old;
1866     CHARSETINFO csi;
1867     FONTSIGNATURE fs;
1868     INT cs;
1869     DWORD i, ret;
1870     char name[64];
1871
1872     assert(count <= 128);
1873
1874     memset(&lf, 0, sizeof(lf));
1875
1876     lf.lfCharSet = charset;
1877     lf.lfHeight = 10;
1878     lstrcpyA(lf.lfFaceName, "Arial");
1879     SetLastError(0xdeadbeef);
1880     hfont = CreateFontIndirectA(&lf);
1881     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1882
1883     hdc = GetDC(0);
1884     hfont_old = SelectObject(hdc, hfont);
1885
1886     cs = GetTextCharsetInfo(hdc, &fs, 0);
1887     ok(cs == charset, "expected %d, got %d\n", charset, cs);
1888
1889     SetLastError(0xdeadbeef);
1890     ret = GetTextFaceA(hdc, sizeof(name), name);
1891     ok(ret, "GetTextFaceA error %u\n", GetLastError());
1892
1893     if (charset == SYMBOL_CHARSET)
1894     {
1895         ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1896         ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1897     }
1898     else
1899     {
1900         ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1901         ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1902     }
1903
1904     if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1905     {
1906         trace("Can't find codepage for charset %d\n", cs);
1907         ReleaseDC(0, hdc);
1908         return FALSE;
1909     }
1910     ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1911
1912     if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1913     {
1914         skip("Font code page %d, looking for code page %d\n",
1915              pGdiGetCodePage(hdc), code_page);
1916         ReleaseDC(0, hdc);
1917         return FALSE;
1918     }
1919
1920     if (unicode)
1921     {
1922         char ansi_buf[128];
1923         WCHAR unicode_buf[128];
1924
1925         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1926
1927         MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1928
1929         SetLastError(0xdeadbeef);
1930         ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1931         ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1932            count, ret, GetLastError());
1933     }
1934     else
1935     {
1936         char ansi_buf[128];
1937
1938         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1939
1940         SetLastError(0xdeadbeef);
1941         ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1942         ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1943            count, ret, GetLastError());
1944     }
1945
1946     SelectObject(hdc, hfont_old);
1947     DeleteObject(hfont);
1948
1949     ReleaseDC(0, hdc);
1950
1951     return TRUE;
1952 }
1953
1954 static void test_font_charset(void)
1955 {
1956     static struct charset_data
1957     {
1958         INT charset;
1959         UINT code_page;
1960         WORD font_idxA[128], font_idxW[128];
1961     } cd[] =
1962     {
1963         { ANSI_CHARSET, 1252 },
1964         { RUSSIAN_CHARSET, 1251 },
1965         { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1966     };
1967     int i;
1968
1969     if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1970     {
1971         win_skip("Skipping the font charset test on a Win9x platform\n");
1972         return;
1973     }
1974
1975     if (!is_font_installed("Arial"))
1976     {
1977         skip("Arial is not installed\n");
1978         return;
1979     }
1980
1981     for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1982     {
1983         if (cd[i].charset == SYMBOL_CHARSET)
1984         {
1985             if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1986             {
1987                 skip("Symbol or Wingdings is not installed\n");
1988                 break;
1989             }
1990         }
1991         if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1992             get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1993             ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1994     }
1995
1996     ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1997     if (i > 2)
1998     {
1999         ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
2000         ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
2001     }
2002     else
2003         skip("Symbol or Wingdings is not installed\n");
2004 }
2005
2006 static void test_GetFontUnicodeRanges(void)
2007 {
2008     LOGFONTA lf;
2009     HDC hdc;
2010     HFONT hfont, hfont_old;
2011     DWORD size;
2012     GLYPHSET *gs;
2013     DWORD i;
2014
2015     if (!pGetFontUnicodeRanges)
2016     {
2017         win_skip("GetFontUnicodeRanges not available before W2K\n");
2018         return;
2019     }
2020
2021     memset(&lf, 0, sizeof(lf));
2022     lstrcpyA(lf.lfFaceName, "Arial");
2023     hfont = create_font("Arial", &lf);
2024
2025     hdc = GetDC(0);
2026     hfont_old = SelectObject(hdc, hfont);
2027
2028     size = pGetFontUnicodeRanges(NULL, NULL);
2029     ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
2030
2031     size = pGetFontUnicodeRanges(hdc, NULL);
2032     ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
2033
2034     gs = HeapAlloc(GetProcessHeap(), 0, size);
2035
2036     size = pGetFontUnicodeRanges(hdc, gs);
2037     ok(size, "GetFontUnicodeRanges failed\n");
2038
2039     if (0) /* Disabled to limit console spam */
2040         for (i = 0; i < gs->cRanges; i++)
2041             trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
2042     trace("found %u ranges\n", gs->cRanges);
2043
2044     HeapFree(GetProcessHeap(), 0, gs);
2045
2046     SelectObject(hdc, hfont_old);
2047     DeleteObject(hfont);
2048     ReleaseDC(NULL, hdc);
2049 }
2050
2051 #define MAX_ENUM_FONTS 4096
2052
2053 struct enum_font_data
2054 {
2055     int total;
2056     LOGFONT lf[MAX_ENUM_FONTS];
2057 };
2058
2059 struct enum_fullname_data
2060 {
2061     int total;
2062     ENUMLOGFONT elf[MAX_ENUM_FONTS];
2063 };
2064
2065 struct enum_font_dataW
2066 {
2067     int total;
2068     LOGFONTW lf[MAX_ENUM_FONTS];
2069 };
2070
2071 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
2072 {
2073     struct enum_font_data *efd = (struct enum_font_data *)lParam;
2074     const NEWTEXTMETRIC *ntm = (const NEWTEXTMETRIC *)tm;
2075
2076     ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2077     ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2078
2079     if (type != TRUETYPE_FONTTYPE) return 1;
2080
2081     ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2082
2083     if (0) /* Disabled to limit console spam */
2084         trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2085               lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2086     if (efd->total < MAX_ENUM_FONTS)
2087         efd->lf[efd->total++] = *lf;
2088     else
2089         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2090
2091     return 1;
2092 }
2093
2094 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
2095 {
2096     struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
2097     const NEWTEXTMETRICW *ntm = (const NEWTEXTMETRICW *)tm;
2098
2099     ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
2100     ok(lf->lfHeight > 0 && lf->lfHeight < 200, "enumerated font height %d\n", lf->lfHeight);
2101
2102     if (type != TRUETYPE_FONTTYPE) return 1;
2103
2104     ok(ntm->ntmCellHeight + ntm->ntmCellHeight/5 >= ntm->ntmSizeEM, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm->ntmCellHeight, ntm->ntmSizeEM);
2105
2106     if (0) /* Disabled to limit console spam */
2107         trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2108               wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
2109     if (efd->total < MAX_ENUM_FONTS)
2110         efd->lf[efd->total++] = *lf;
2111     else
2112         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2113
2114     return 1;
2115 }
2116
2117 static void get_charset_stats(struct enum_font_data *efd,
2118                               int *ansi_charset, int *symbol_charset,
2119                               int *russian_charset)
2120 {
2121     int i;
2122
2123     *ansi_charset = 0;
2124     *symbol_charset = 0;
2125     *russian_charset = 0;
2126
2127     for (i = 0; i < efd->total; i++)
2128     {
2129         switch (efd->lf[i].lfCharSet)
2130         {
2131         case ANSI_CHARSET:
2132             (*ansi_charset)++;
2133             break;
2134         case SYMBOL_CHARSET:
2135             (*symbol_charset)++;
2136             break;
2137         case RUSSIAN_CHARSET:
2138             (*russian_charset)++;
2139             break;
2140         }
2141     }
2142 }
2143
2144 static void get_charset_statsW(struct enum_font_dataW *efd,
2145                               int *ansi_charset, int *symbol_charset,
2146                               int *russian_charset)
2147 {
2148     int i;
2149
2150     *ansi_charset = 0;
2151     *symbol_charset = 0;
2152     *russian_charset = 0;
2153
2154     for (i = 0; i < efd->total; i++)
2155     {
2156         switch (efd->lf[i].lfCharSet)
2157         {
2158         case ANSI_CHARSET:
2159             (*ansi_charset)++;
2160             break;
2161         case SYMBOL_CHARSET:
2162             (*symbol_charset)++;
2163             break;
2164         case RUSSIAN_CHARSET:
2165             (*russian_charset)++;
2166             break;
2167         }
2168     }
2169 }
2170
2171 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
2172 {
2173     struct enum_font_data efd;
2174     struct enum_font_dataW efdw;
2175     LOGFONT lf;
2176     HDC hdc;
2177     int i, ret, ansi_charset, symbol_charset, russian_charset;
2178
2179     trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
2180
2181     if (*font_name && !is_truetype_font_installed(font_name))
2182     {
2183         skip("%s is not installed\n", font_name);
2184         return;
2185     }
2186
2187     hdc = GetDC(0);
2188
2189     /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2190      * while EnumFontFamiliesEx doesn't.
2191      */
2192     if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
2193     {
2194         /*
2195          * Use EnumFontFamiliesW since win98 crashes when the
2196          *    second parameter is NULL using EnumFontFamilies
2197          */
2198         efdw.total = 0;
2199         SetLastError(0xdeadbeef);
2200         ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2201         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2202         if(ret)
2203         {
2204             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2205             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2206                   ansi_charset, symbol_charset, russian_charset);
2207             ok(efdw.total > 0, "fonts enumerated: NULL\n");
2208             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2209             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2210             ok(russian_charset > 0 ||
2211                broken(russian_charset == 0), /* NT4 */
2212                "NULL family should enumerate RUSSIAN_CHARSET\n");
2213         }
2214
2215         efdw.total = 0;
2216         SetLastError(0xdeadbeef);
2217         ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2218         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2219         if(ret)
2220         {
2221             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2222             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2223                   ansi_charset, symbol_charset, russian_charset);
2224             ok(efdw.total > 0, "fonts enumerated: NULL\n");
2225             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2226             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2227             ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2228         }
2229     }
2230
2231     efd.total = 0;
2232     SetLastError(0xdeadbeef);
2233     ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2234     ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2235     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2236     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2237           ansi_charset, symbol_charset, russian_charset,
2238           *font_name ? font_name : "<empty>");
2239     if (*font_name)
2240         ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2241     else
2242         ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2243     for (i = 0; i < efd.total; i++)
2244     {
2245 /* FIXME: remove completely once Wine is fixed */
2246 if (efd.lf[i].lfCharSet != font_charset)
2247 {
2248 todo_wine
2249     ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2250 }
2251 else
2252         ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2253         ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2254            font_name, efd.lf[i].lfFaceName);
2255     }
2256
2257     memset(&lf, 0, sizeof(lf));
2258     lf.lfCharSet = ANSI_CHARSET;
2259     lstrcpy(lf.lfFaceName, font_name);
2260     efd.total = 0;
2261     SetLastError(0xdeadbeef);
2262     ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2263     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2264     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2265     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2266           ansi_charset, symbol_charset, russian_charset,
2267           *font_name ? font_name : "<empty>");
2268     if (font_charset == SYMBOL_CHARSET)
2269     {
2270         if (*font_name)
2271             ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2272         else
2273             ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2274     }
2275     else
2276     {
2277         ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2278         for (i = 0; i < efd.total; i++)
2279         {
2280             ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2281             if (*font_name)
2282                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2283                    font_name, efd.lf[i].lfFaceName);
2284         }
2285     }
2286
2287     /* DEFAULT_CHARSET should enumerate all available charsets */
2288     memset(&lf, 0, sizeof(lf));
2289     lf.lfCharSet = DEFAULT_CHARSET;
2290     lstrcpy(lf.lfFaceName, font_name);
2291     efd.total = 0;
2292     SetLastError(0xdeadbeef);
2293     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2294     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2295     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2296     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2297           ansi_charset, symbol_charset, russian_charset,
2298           *font_name ? font_name : "<empty>");
2299     ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2300     for (i = 0; i < efd.total; i++)
2301     {
2302         if (*font_name)
2303             ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2304                font_name, efd.lf[i].lfFaceName);
2305     }
2306     if (*font_name)
2307     {
2308         switch (font_charset)
2309         {
2310         case ANSI_CHARSET:
2311             ok(ansi_charset > 0,
2312                "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2313             ok(!symbol_charset,
2314                "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2315             ok(russian_charset > 0,
2316                "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2317             break;
2318         case SYMBOL_CHARSET:
2319             ok(!ansi_charset,
2320                "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2321             ok(symbol_charset,
2322                "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2323             ok(!russian_charset,
2324                "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2325             break;
2326         case DEFAULT_CHARSET:
2327             ok(ansi_charset > 0,
2328                "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2329             ok(symbol_charset > 0,
2330                "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2331             ok(russian_charset > 0,
2332                "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2333             break;
2334         }
2335     }
2336     else
2337     {
2338         ok(ansi_charset > 0,
2339            "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2340         ok(symbol_charset > 0,
2341            "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2342         ok(russian_charset > 0,
2343            "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2344     }
2345
2346     memset(&lf, 0, sizeof(lf));
2347     lf.lfCharSet = SYMBOL_CHARSET;
2348     lstrcpy(lf.lfFaceName, font_name);
2349     efd.total = 0;
2350     SetLastError(0xdeadbeef);
2351     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2352     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2353     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2354     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2355           ansi_charset, symbol_charset, russian_charset,
2356           *font_name ? font_name : "<empty>");
2357     if (*font_name && font_charset == ANSI_CHARSET)
2358         ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2359     else
2360     {
2361         ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2362         for (i = 0; i < efd.total; i++)
2363         {
2364             ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2365             if (*font_name)
2366                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2367                    font_name, efd.lf[i].lfFaceName);
2368         }
2369
2370         ok(!ansi_charset,
2371            "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2372         ok(symbol_charset > 0,
2373            "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2374         ok(!russian_charset,
2375            "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2376     }
2377
2378     ReleaseDC(0, hdc);
2379 }
2380
2381 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2382 {
2383     struct enum_font_data *efd = (struct enum_font_data *)lParam;
2384
2385     if (type != TRUETYPE_FONTTYPE) return 1;
2386
2387     if (efd->total < MAX_ENUM_FONTS)
2388         efd->lf[efd->total++] = *lf;
2389     else
2390         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2391
2392     return 1;
2393 }
2394
2395 static INT CALLBACK enum_fullname_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2396 {
2397     struct enum_fullname_data *efnd = (struct enum_fullname_data *)lParam;
2398
2399     if (type != TRUETYPE_FONTTYPE) return 1;
2400
2401     if (efnd->total < MAX_ENUM_FONTS)
2402         efnd->elf[efnd->total++] = *(ENUMLOGFONT*)lf;
2403     else
2404         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2405
2406     return 1;
2407 }
2408
2409 static void test_EnumFontFamiliesEx_default_charset(void)
2410 {
2411     struct enum_font_data efd;
2412     LOGFONT gui_font, enum_font;
2413     DWORD ret;
2414     HDC hdc;
2415
2416     ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2417     ok(ret, "GetObject failed.\n");
2418     if (!ret)
2419         return;
2420
2421     efd.total = 0;
2422
2423     hdc = GetDC(0);
2424     memset(&enum_font, 0, sizeof(enum_font));
2425     lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2426     enum_font.lfCharSet = DEFAULT_CHARSET;
2427     EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2428     ReleaseDC(0, hdc);
2429
2430     if (efd.total == 0) {
2431         skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2432         return;
2433     }
2434     trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2435
2436     ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2437        "(%s) got charset %d expected %d\n",
2438        efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2439
2440     return;
2441 }
2442
2443 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2444 {
2445     HFONT hfont, hfont_prev;
2446     DWORD ret;
2447     GLYPHMETRICS gm1, gm2;
2448     LOGFONTA lf2 = *lf;
2449     WORD idx;
2450
2451     if(!pGetGlyphIndicesA)
2452         return;
2453
2454     /* negative widths are handled just as positive ones */
2455     lf2.lfWidth = -lf->lfWidth;
2456
2457     SetLastError(0xdeadbeef);
2458     hfont = CreateFontIndirectA(lf);
2459     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2460     check_font("original", lf, hfont);
2461
2462     hfont_prev = SelectObject(hdc, hfont);
2463
2464     ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2465     if (ret == GDI_ERROR || idx == 0xffff)
2466     {
2467         SelectObject(hdc, hfont_prev);
2468         DeleteObject(hfont);
2469         skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2470         return;
2471     }
2472
2473     /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2474     memset(&gm1, 0xab, sizeof(gm1));
2475     SetLastError(0xdeadbeef);
2476     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2477     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2478
2479     SelectObject(hdc, hfont_prev);
2480     DeleteObject(hfont);
2481
2482     SetLastError(0xdeadbeef);
2483     hfont = CreateFontIndirectA(&lf2);
2484     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2485     check_font("negative width", &lf2, hfont);
2486
2487     hfont_prev = SelectObject(hdc, hfont);
2488
2489     memset(&gm2, 0xbb, sizeof(gm2));
2490     SetLastError(0xdeadbeef);
2491     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2492     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2493
2494     SelectObject(hdc, hfont_prev);
2495     DeleteObject(hfont);
2496
2497     ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2498        gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2499        gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2500        gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2501        gm1.gmCellIncX == gm2.gmCellIncX &&
2502        gm1.gmCellIncY == gm2.gmCellIncY,
2503        "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2504        gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2505        gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2506        gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2507        gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2508 }
2509
2510 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2511 #include "pshpack2.h"
2512 typedef struct
2513 {
2514     USHORT version;
2515     SHORT xAvgCharWidth;
2516     USHORT usWeightClass;
2517     USHORT usWidthClass;
2518     SHORT fsType;
2519     SHORT ySubscriptXSize;
2520     SHORT ySubscriptYSize;
2521     SHORT ySubscriptXOffset;
2522     SHORT ySubscriptYOffset;
2523     SHORT ySuperscriptXSize;
2524     SHORT ySuperscriptYSize;
2525     SHORT ySuperscriptXOffset;
2526     SHORT ySuperscriptYOffset;
2527     SHORT yStrikeoutSize;
2528     SHORT yStrikeoutPosition;
2529     SHORT sFamilyClass;
2530     PANOSE panose;
2531     ULONG ulUnicodeRange1;
2532     ULONG ulUnicodeRange2;
2533     ULONG ulUnicodeRange3;
2534     ULONG ulUnicodeRange4;
2535     CHAR achVendID[4];
2536     USHORT fsSelection;
2537     USHORT usFirstCharIndex;
2538     USHORT usLastCharIndex;
2539     /* According to the Apple spec, original version didn't have the below fields,
2540      * version numbers were taken from the OpenType spec.
2541      */
2542     /* version 0 (TrueType 1.5) */
2543     USHORT sTypoAscender;
2544     USHORT sTypoDescender;
2545     USHORT sTypoLineGap;
2546     USHORT usWinAscent;
2547     USHORT usWinDescent;
2548     /* version 1 (TrueType 1.66) */
2549     ULONG ulCodePageRange1;
2550     ULONG ulCodePageRange2;
2551     /* version 2 (OpenType 1.2) */
2552     SHORT sxHeight;
2553     SHORT sCapHeight;
2554     USHORT usDefaultChar;
2555     USHORT usBreakChar;
2556     USHORT usMaxContext;
2557 } TT_OS2_V2;
2558 #include "poppack.h"
2559
2560 #ifdef WORDS_BIGENDIAN
2561 #define GET_BE_WORD(x) (x)
2562 #define GET_BE_DWORD(x) (x)
2563 #else
2564 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2565 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2566 #endif
2567
2568 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2569                     ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2570                     ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2571 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2572 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2573 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2574
2575 typedef struct
2576 {
2577     USHORT version;
2578     USHORT num_tables;
2579 } cmap_header;
2580
2581 typedef struct
2582 {
2583     USHORT plat_id;
2584     USHORT enc_id;
2585     ULONG offset;
2586 } cmap_encoding_record;
2587
2588 typedef struct
2589 {
2590     USHORT format;
2591     USHORT length;
2592     USHORT language;
2593
2594     BYTE glyph_ids[256];
2595 } cmap_format_0;
2596
2597 typedef struct
2598 {
2599     USHORT format;
2600     USHORT length;
2601     USHORT language;
2602
2603     USHORT seg_countx2;
2604     USHORT search_range;
2605     USHORT entry_selector;
2606     USHORT range_shift;
2607
2608     USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2609 /* Then follows:
2610     USHORT pad;
2611     USHORT start_count[seg_countx2 / 2];
2612     USHORT id_delta[seg_countx2 / 2];
2613     USHORT id_range_offset[seg_countx2 / 2];
2614     USHORT glyph_ids[];
2615 */
2616 } cmap_format_4;
2617
2618 typedef struct
2619 {
2620     USHORT end_count;
2621     USHORT start_count;
2622     USHORT id_delta;
2623     USHORT id_range_offset;
2624 } cmap_format_4_seg;
2625
2626 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2627 {
2628     ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2629        broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2630        "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2631        name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2632        os2->panose.bWeight, os2->panose.bProportion);
2633 }
2634
2635 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2636 {
2637     int i;
2638     cmap_format_0 *cmap = (cmap_format_0*)ptr;
2639
2640     *first = 256;
2641
2642     for(i = 0; i < 256; i++)
2643     {
2644         if(cmap->glyph_ids[i] == 0) continue;
2645         *last = i;
2646         if(*first == 256) *first = i;
2647     }
2648     if(*first == 256) return FALSE;
2649     return TRUE;
2650 }
2651
2652 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2653 {
2654     USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2655     seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2656     seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2657     seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2658     seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2659 }
2660
2661 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2662 {
2663     int i;
2664     cmap_format_4 *cmap = (cmap_format_4*)ptr;
2665     USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2666     USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2667
2668     *first = 0x10000;
2669
2670     for(i = 0; i < seg_count; i++)
2671     {
2672         DWORD code, index;
2673         cmap_format_4_seg seg;
2674
2675         get_seg4(cmap, i, &seg);
2676         for(code = seg.start_count; code <= seg.end_count; code++)
2677         {
2678             if(seg.id_range_offset == 0)
2679                 index = (seg.id_delta + code) & 0xffff;
2680             else
2681             {
2682                 index = seg.id_range_offset / 2
2683                     + code - seg.start_count
2684                     + i - seg_count;
2685
2686                 /* some fonts have broken last segment */
2687                 if ((char *)(glyph_ids + index + 1) < (char *)ptr + limit)
2688                     index = GET_BE_WORD(glyph_ids[index]);
2689                 else
2690                 {
2691                     trace("segment %04x/%04x index %04x points to nowhere\n",
2692                           seg.start_count, seg.end_count, index);
2693                     index = 0;
2694                 }
2695                 if(index) index += seg.id_delta;
2696             }
2697             if(*first == 0x10000)
2698                 *last = *first = code;
2699             else if(index)
2700                 *last = code;
2701         }
2702     }
2703
2704     if(*first == 0x10000) return FALSE;
2705     return TRUE;
2706 }
2707
2708 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2709 {
2710     USHORT i;
2711     cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2712
2713     for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2714     {
2715         if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2716             return (BYTE *)header + GET_BE_DWORD(record->offset);
2717         record++;
2718     }
2719     return NULL;
2720 }
2721
2722 typedef enum
2723 {
2724     cmap_none,
2725     cmap_ms_unicode,
2726     cmap_ms_symbol
2727 } cmap_type;
2728
2729 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2730 {
2731     LONG size, ret;
2732     cmap_header *header;
2733     void *cmap;
2734     BOOL r = FALSE;
2735     WORD format;
2736
2737     size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2738     ok(size != GDI_ERROR, "no cmap table found\n");
2739     if(size == GDI_ERROR) return FALSE;
2740
2741     header = HeapAlloc(GetProcessHeap(), 0, size);
2742     ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2743     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2744     ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2745
2746     cmap = get_cmap(header, 3, 1);
2747     if(cmap)
2748         *cmap_type = cmap_ms_unicode;
2749     else
2750     {
2751         cmap = get_cmap(header, 3, 0);
2752         if(cmap) *cmap_type = cmap_ms_symbol;
2753     }
2754     if(!cmap)
2755     {
2756         *cmap_type = cmap_none;
2757         goto end;
2758     }
2759
2760     format = GET_BE_WORD(*(WORD *)cmap);
2761     switch(format)
2762     {
2763     case 0:
2764         r = get_first_last_from_cmap0(cmap, first, last);
2765         break;
2766     case 4:
2767         r = get_first_last_from_cmap4(cmap, first, last, size);
2768         break;
2769     default:
2770         trace("unhandled cmap format %d\n", format);
2771         break;
2772     }
2773
2774 end:
2775     HeapFree(GetProcessHeap(), 0, header);
2776     return r;
2777 }
2778
2779 #define TT_PLATFORM_MICROSOFT 3
2780 #define TT_MS_ID_SYMBOL_CS 0
2781 #define TT_MS_ID_UNICODE_CS 1
2782 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2783 #define TT_NAME_ID_FONT_FAMILY 1
2784 #define TT_NAME_ID_FONT_SUBFAMILY 2
2785 #define TT_NAME_ID_UNIQUE_ID 3
2786 #define TT_NAME_ID_FULL_NAME 4
2787
2788 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, WCHAR *out_buf, SIZE_T out_size, LCID language_id)
2789 {
2790     struct sfnt_name_header
2791     {
2792         USHORT format;
2793         USHORT number_of_record;
2794         USHORT storage_offset;
2795     } *header;
2796     struct sfnt_name
2797     {
2798         USHORT platform_id;
2799         USHORT encoding_id;
2800         USHORT language_id;
2801         USHORT name_id;
2802         USHORT length;
2803         USHORT offset;
2804     } *entry;
2805     BOOL r = FALSE;
2806     LONG size, offset, length;
2807     LONG c, ret;
2808     WCHAR *name;
2809     BYTE *data;
2810     USHORT i;
2811
2812     size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2813     ok(size != GDI_ERROR, "no name table found\n");
2814     if(size == GDI_ERROR) return FALSE;
2815
2816     data = HeapAlloc(GetProcessHeap(), 0, size);
2817     ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2818     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2819
2820     header = (void *)data;
2821     header->format = GET_BE_WORD(header->format);
2822     header->number_of_record = GET_BE_WORD(header->number_of_record);
2823     header->storage_offset = GET_BE_WORD(header->storage_offset);
2824     if (header->format != 0)
2825     {
2826         trace("got format %u\n", header->format);
2827         goto out;
2828     }
2829     if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2830     {
2831         trace("number records out of range: %d\n", header->number_of_record);
2832         goto out;
2833     }
2834     if (header->storage_offset >= size)
2835     {
2836         trace("storage_offset %u > size %u\n", header->storage_offset, size);
2837         goto out;
2838     }
2839
2840     entry = (void *)&header[1];
2841     for (i = 0; i < header->number_of_record; i++)
2842     {
2843         if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2844             (GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS && GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_SYMBOL_CS) ||
2845             GET_BE_WORD(entry[i].language_id) != language_id ||
2846             GET_BE_WORD(entry[i].name_id) != name_id)
2847         {
2848             continue;
2849         }
2850
2851         offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2852         length = GET_BE_WORD(entry[i].length);
2853         if (offset + length > size)
2854         {
2855             trace("entry %d is out of range\n", i);
2856             break;
2857         }
2858         if (length >= out_size)
2859         {
2860             trace("buffer too small for entry %d\n", i);
2861             break;
2862         }
2863
2864         name = (WCHAR *)(data + offset);
2865         for (c = 0; c < length / 2; c++)
2866             out_buf[c] = GET_BE_WORD(name[c]);
2867         out_buf[c] = 0;
2868
2869         r = TRUE;
2870         break;
2871     }
2872
2873 out:
2874     HeapFree(GetProcessHeap(), 0, data);
2875     return r;
2876 }
2877
2878 static void test_text_metrics(const LOGFONT *lf, const NEWTEXTMETRIC *ntm)
2879 {
2880     HDC hdc;
2881     HFONT hfont, hfont_old;
2882     TEXTMETRICA tmA;
2883     TT_OS2_V2 tt_os2;
2884     LONG size, ret;
2885     const char *font_name = lf->lfFaceName;
2886     DWORD cmap_first = 0, cmap_last = 0;
2887     UINT ascent, descent, cell_height;
2888     cmap_type cmap_type;
2889     BOOL sys_lang_non_english;
2890
2891     sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2892     hdc = GetDC(0);
2893
2894     SetLastError(0xdeadbeef);
2895     hfont = CreateFontIndirectA(lf);
2896     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2897
2898     hfont_old = SelectObject(hdc, hfont);
2899
2900     size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2901     if (size == GDI_ERROR)
2902     {
2903         trace("OS/2 chunk was not found\n");
2904         goto end_of_test;
2905     }
2906     if (size > sizeof(tt_os2))
2907     {
2908         trace("got too large OS/2 chunk of size %u\n", size);
2909         size = sizeof(tt_os2);
2910     }
2911
2912     memset(&tt_os2, 0, sizeof(tt_os2));
2913     ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2914     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2915
2916     ascent = GET_BE_WORD(tt_os2.usWinAscent);
2917     descent = GET_BE_WORD(tt_os2.usWinDescent);
2918     cell_height = ascent + descent;
2919     ok(ntm->ntmCellHeight == cell_height, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
2920        font_name, ntm->ntmCellHeight, cell_height, ascent, descent);
2921
2922     SetLastError(0xdeadbeef);
2923     ret = GetTextMetricsA(hdc, &tmA);
2924     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2925
2926     if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2927     {
2928         skip("Unable to retrieve first and last glyphs from cmap\n");
2929     }
2930     else
2931     {
2932         USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2933         USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2934         UINT os2_first_char, os2_last_char, default_char, break_char;
2935         USHORT version;
2936         TEXTMETRICW tmW;
2937
2938         version = GET_BE_WORD(tt_os2.version);
2939
2940         os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2941         os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2942         default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2943         break_char = GET_BE_WORD(tt_os2.usBreakChar);
2944
2945         trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2946               font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2947               default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2948
2949         if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2950         {
2951             expect_first_W    = 0;
2952             switch(GetACP())
2953             {
2954             case 1257:  /* Baltic */
2955                 expect_last_W = 0xf8fd;
2956                 break;
2957             default:
2958                 expect_last_W = 0xf0ff;
2959             }
2960             expect_break_W    = 0x20;
2961             expect_default_W  = expect_break_W - 1;
2962             expect_first_A    = 0x1e;
2963             expect_last_A     = min(os2_last_char - os2_first_char + 0x20, 0xff);
2964         }
2965         else
2966         {
2967             expect_first_W    = cmap_first;
2968             expect_last_W     = min(cmap_last, os2_last_char);
2969             if(os2_first_char <= 1)
2970                 expect_break_W = os2_first_char + 2;
2971             else if(os2_first_char > 0xff)
2972                 expect_break_W = 0x20;
2973             else
2974                 expect_break_W = os2_first_char;
2975             expect_default_W  = expect_break_W - 1;
2976             expect_first_A    = expect_default_W - 1;
2977             expect_last_A     = min(expect_last_W, 0xff);
2978         }
2979         expect_break_A    = expect_break_W;
2980         expect_default_A  = expect_default_W;
2981
2982         /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2983         if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2984             todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2985                          tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2986                          "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2987         else
2988             ok(tmA.tmFirstChar == expect_first_A ||
2989                tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2990                "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2991         if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2992             ok(tmA.tmLastChar == expect_last_A ||
2993                tmA.tmLastChar == 0xff /* win9x */,
2994                "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2995         else
2996            skip("tmLastChar is DBCS lead byte\n");
2997         ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2998            font_name, tmA.tmBreakChar, expect_break_A);
2999         ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
3000            "A: tmDefaultChar for %s got %02x expected %02x\n",
3001            font_name, tmA.tmDefaultChar, expect_default_A);
3002
3003
3004         SetLastError(0xdeadbeef);
3005         ret = GetTextMetricsW(hdc, &tmW);
3006         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
3007            "GetTextMetricsW error %u\n", GetLastError());
3008         if (ret)
3009         {
3010             /* Wine uses the os2 first char */
3011             if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
3012                 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3013                              font_name, tmW.tmFirstChar, expect_first_W);
3014             else
3015                 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
3016                    font_name, tmW.tmFirstChar, expect_first_W);
3017
3018             /* Wine uses the os2 last char */
3019             if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
3020                 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3021                              font_name, tmW.tmLastChar, expect_last_W);
3022             else
3023                 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
3024                    font_name, tmW.tmLastChar, expect_last_W);
3025             ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
3026                font_name, tmW.tmBreakChar, expect_break_W);
3027             ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
3028                "W: tmDefaultChar for %s got %02x expected %02x\n",
3029                font_name, tmW.tmDefaultChar, expect_default_W);
3030
3031             /* Test the aspect ratio while we have tmW */
3032             ret = GetDeviceCaps(hdc, LOGPIXELSX);
3033             ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
3034                tmW.tmDigitizedAspectX, ret);
3035             ret = GetDeviceCaps(hdc, LOGPIXELSY);
3036             ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
3037                tmW.tmDigitizedAspectX, ret);
3038         }
3039     }
3040
3041     /* test FF_ values */
3042     switch(tt_os2.panose.bFamilyType)
3043     {
3044     case PAN_ANY:
3045     case PAN_NO_FIT:
3046     case PAN_FAMILY_TEXT_DISPLAY:
3047     case PAN_FAMILY_PICTORIAL:
3048     default:
3049         if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
3050            tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
3051         {
3052             expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
3053             break;
3054         }
3055         switch(tt_os2.panose.bSerifStyle)
3056         {
3057         case PAN_ANY:
3058         case PAN_NO_FIT:
3059         default:
3060             expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
3061             break;
3062
3063         case PAN_SERIF_COVE:
3064         case PAN_SERIF_OBTUSE_COVE:
3065         case PAN_SERIF_SQUARE_COVE:
3066         case PAN_SERIF_OBTUSE_SQUARE_COVE:
3067         case PAN_SERIF_SQUARE:
3068         case PAN_SERIF_THIN:
3069         case PAN_SERIF_BONE:
3070         case PAN_SERIF_EXAGGERATED:
3071         case PAN_SERIF_TRIANGLE:
3072             expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
3073             break;
3074
3075         case PAN_SERIF_NORMAL_SANS:
3076         case PAN_SERIF_OBTUSE_SANS:
3077         case PAN_SERIF_PERP_SANS:
3078         case PAN_SERIF_FLARED:
3079         case PAN_SERIF_ROUNDED:
3080             expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
3081             break;
3082         }
3083         break;
3084
3085     case PAN_FAMILY_SCRIPT:
3086         expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
3087         break;
3088
3089     case PAN_FAMILY_DECORATIVE:
3090         expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
3091         break;
3092     }
3093
3094     test_negative_width(hdc, lf);
3095
3096 end_of_test:
3097     SelectObject(hdc, hfont_old);
3098     DeleteObject(hfont);
3099
3100     ReleaseDC(0, hdc);
3101 }
3102
3103 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3104 {
3105     INT *enumed = (INT *)lParam;
3106
3107     if (type == TRUETYPE_FONTTYPE)
3108     {
3109         (*enumed)++;
3110         test_text_metrics(lf, (const NEWTEXTMETRIC *)ntm);
3111     }
3112     return 1;
3113 }
3114
3115 static void test_GetTextMetrics(void)
3116 {
3117     LOGFONTA lf;
3118     HDC hdc;
3119     INT enumed;
3120
3121     /* Report only once */
3122     if(!pGetGlyphIndicesA)
3123         win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3124
3125     hdc = GetDC(0);
3126
3127     memset(&lf, 0, sizeof(lf));
3128     lf.lfCharSet = DEFAULT_CHARSET;
3129     enumed = 0;
3130     EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
3131     trace("Tested metrics of %d truetype fonts\n", enumed);
3132
3133     ReleaseDC(0, hdc);
3134 }
3135
3136 static void test_nonexistent_font(void)
3137 {
3138     static const struct
3139     {
3140         const char *name;
3141         int charset;
3142     } font_subst[] =
3143     {
3144         { "Times New Roman Baltic", 186 },
3145         { "Times New Roman CE", 238 },
3146         { "Times New Roman CYR", 204 },
3147         { "Times New Roman Greek", 161 },
3148         { "Times New Roman TUR", 162 }
3149     };
3150     LOGFONTA lf;
3151     HDC hdc;
3152     HFONT hfont;
3153     CHARSETINFO csi;
3154     INT cs, expected_cs, i;
3155     char buf[LF_FACESIZE];
3156
3157     if (!is_truetype_font_installed("Arial") ||
3158         !is_truetype_font_installed("Times New Roman"))
3159     {
3160         skip("Arial or Times New Roman not installed\n");
3161         return;
3162     }
3163
3164     expected_cs = GetACP();
3165     if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
3166     {
3167         skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
3168         return;
3169     }
3170     expected_cs = csi.ciCharset;
3171     trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
3172
3173     hdc = GetDC(0);
3174
3175     memset(&lf, 0, sizeof(lf));
3176     lf.lfHeight = 100;
3177     lf.lfWeight = FW_REGULAR;
3178     lf.lfCharSet = ANSI_CHARSET;
3179     lf.lfPitchAndFamily = FF_SWISS;
3180     strcpy(lf.lfFaceName, "Nonexistent font");
3181     hfont = CreateFontIndirectA(&lf);
3182     hfont = SelectObject(hdc, hfont);
3183     GetTextFaceA(hdc, sizeof(buf), buf);
3184     ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
3185     cs = GetTextCharset(hdc);
3186     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3187     DeleteObject(SelectObject(hdc, hfont));
3188
3189     memset(&lf, 0, sizeof(lf));
3190     lf.lfHeight = -13;
3191     lf.lfWeight = FW_DONTCARE;
3192     strcpy(lf.lfFaceName, "Nonexistent font");
3193     hfont = CreateFontIndirectA(&lf);
3194     hfont = SelectObject(hdc, hfont);
3195     GetTextFaceA(hdc, sizeof(buf), buf);
3196 todo_wine /* Wine uses Arial for all substitutions */
3197     ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
3198        !lstrcmpiA(buf, "MS Serif") || /* Win9x */
3199        !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3200        "Got %s\n", buf);
3201     cs = GetTextCharset(hdc);
3202     ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
3203     DeleteObject(SelectObject(hdc, hfont));
3204
3205     memset(&lf, 0, sizeof(lf));
3206     lf.lfHeight = -13;
3207     lf.lfWeight = FW_REGULAR;
3208     strcpy(lf.lfFaceName, "Nonexistent font");
3209     hfont = CreateFontIndirectA(&lf);
3210     hfont = SelectObject(hdc, hfont);
3211     GetTextFaceA(hdc, sizeof(buf), buf);
3212     ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3213        !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
3214     cs = GetTextCharset(hdc);
3215     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3216     DeleteObject(SelectObject(hdc, hfont));
3217
3218     memset(&lf, 0, sizeof(lf));
3219     lf.lfHeight = -13;
3220     lf.lfWeight = FW_DONTCARE;
3221     strcpy(lf.lfFaceName, "Times New Roman");
3222     hfont = CreateFontIndirectA(&lf);
3223     hfont = SelectObject(hdc, hfont);
3224     GetTextFaceA(hdc, sizeof(buf), buf);
3225     ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3226     cs = GetTextCharset(hdc);
3227     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3228     DeleteObject(SelectObject(hdc, hfont));
3229
3230     for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3231     {
3232         memset(&lf, 0, sizeof(lf));
3233         lf.lfHeight = -13;
3234         lf.lfWeight = FW_REGULAR;
3235         strcpy(lf.lfFaceName, font_subst[i].name);
3236         hfont = CreateFontIndirectA(&lf);
3237         hfont = SelectObject(hdc, hfont);
3238         cs = GetTextCharset(hdc);
3239         if (font_subst[i].charset == expected_cs)
3240         {
3241             ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3242             GetTextFaceA(hdc, sizeof(buf), buf);
3243             ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3244         }
3245         else
3246         {
3247             ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3248             GetTextFaceA(hdc, sizeof(buf), buf);
3249             ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3250                !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3251         }
3252         DeleteObject(SelectObject(hdc, hfont));
3253
3254         memset(&lf, 0, sizeof(lf));
3255         lf.lfHeight = -13;
3256         lf.lfWeight = FW_DONTCARE;
3257         strcpy(lf.lfFaceName, font_subst[i].name);
3258         hfont = CreateFontIndirectA(&lf);
3259         hfont = SelectObject(hdc, hfont);
3260         GetTextFaceA(hdc, sizeof(buf), buf);
3261         ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3262            !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3263            !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3264            !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3265            "got %s for font %s\n", buf, font_subst[i].name);
3266         cs = GetTextCharset(hdc);
3267         ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3268         DeleteObject(SelectObject(hdc, hfont));
3269     }
3270
3271     ReleaseDC(0, hdc);
3272 }
3273
3274 static void test_GdiRealizationInfo(void)
3275 {
3276     HDC hdc;
3277     DWORD info[4];
3278     BOOL r;
3279     HFONT hfont, hfont_old;
3280     LOGFONTA lf;
3281
3282     if(!pGdiRealizationInfo)
3283     {
3284         win_skip("GdiRealizationInfo not available\n");
3285         return;
3286     }
3287
3288     hdc = GetDC(0);
3289
3290     memset(info, 0xcc, sizeof(info));
3291     r = pGdiRealizationInfo(hdc, info);
3292     ok(r != 0, "ret 0\n");
3293     ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3294     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3295
3296     if (!is_truetype_font_installed("Arial"))
3297     {
3298         skip("skipping GdiRealizationInfo with truetype font\n");
3299         goto end;
3300     }
3301
3302     memset(&lf, 0, sizeof(lf));
3303     strcpy(lf.lfFaceName, "Arial");
3304     lf.lfHeight = 20;
3305     lf.lfWeight = FW_NORMAL;
3306     hfont = CreateFontIndirectA(&lf);
3307     hfont_old = SelectObject(hdc, hfont);
3308
3309     memset(info, 0xcc, sizeof(info));
3310     r = pGdiRealizationInfo(hdc, info);
3311     ok(r != 0, "ret 0\n");
3312     ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3313     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3314
3315     DeleteObject(SelectObject(hdc, hfont_old));
3316
3317  end:
3318     ReleaseDC(0, hdc);
3319 }
3320
3321 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3322    the nul in the count of characters copied when the face name buffer is not
3323    NULL, whereas it does if the buffer is NULL.  Further, the Unicode version
3324    always includes it.  */
3325 static void test_GetTextFace(void)
3326 {
3327     static const char faceA[] = "Tahoma";
3328     static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3329     LOGFONTA fA = {0};
3330     LOGFONTW fW = {0};
3331     char bufA[LF_FACESIZE];
3332     WCHAR bufW[LF_FACESIZE];
3333     HFONT f, g;
3334     HDC dc;
3335     int n;
3336
3337     if(!is_font_installed("Tahoma"))
3338     {
3339         skip("Tahoma is not installed so skipping this test\n");
3340         return;
3341     }
3342
3343     /* 'A' case.  */
3344     memcpy(fA.lfFaceName, faceA, sizeof faceA);
3345     f = CreateFontIndirectA(&fA);
3346     ok(f != NULL, "CreateFontIndirectA failed\n");
3347
3348     dc = GetDC(NULL);
3349     g = SelectObject(dc, f);
3350     n = GetTextFaceA(dc, sizeof bufA, bufA);
3351     ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3352     ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3353
3354     /* Play with the count arg.  */
3355     bufA[0] = 'x';
3356     n = GetTextFaceA(dc, 0, bufA);
3357     ok(n == 0, "GetTextFaceA returned %d\n", n);
3358     ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3359
3360     bufA[0] = 'x';
3361     n = GetTextFaceA(dc, 1, bufA);
3362     ok(n == 0, "GetTextFaceA returned %d\n", n);
3363     ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3364
3365     bufA[0] = 'x'; bufA[1] = 'y';
3366     n = GetTextFaceA(dc, 2, bufA);
3367     ok(n == 1, "GetTextFaceA returned %d\n", n);
3368     ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3369
3370     n = GetTextFaceA(dc, 0, NULL);
3371     ok(n == sizeof faceA ||
3372        broken(n == 0), /* win98, winMe */
3373        "GetTextFaceA returned %d\n", n);
3374
3375     DeleteObject(SelectObject(dc, g));
3376     ReleaseDC(NULL, dc);
3377
3378     /* 'W' case.  */
3379     memcpy(fW.lfFaceName, faceW, sizeof faceW);
3380     SetLastError(0xdeadbeef);
3381     f = CreateFontIndirectW(&fW);
3382     if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3383     {
3384         win_skip("CreateFontIndirectW is not implemented\n");
3385         return;
3386     }
3387     ok(f != NULL, "CreateFontIndirectW failed\n");
3388
3389     dc = GetDC(NULL);
3390     g = SelectObject(dc, f);
3391     n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3392     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3393     ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3394
3395     /* Play with the count arg.  */
3396     bufW[0] = 'x';
3397     n = GetTextFaceW(dc, 0, bufW);
3398     ok(n == 0, "GetTextFaceW returned %d\n", n);
3399     ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3400
3401     bufW[0] = 'x';
3402     n = GetTextFaceW(dc, 1, bufW);
3403     ok(n == 1, "GetTextFaceW returned %d\n", n);
3404     ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3405
3406     bufW[0] = 'x'; bufW[1] = 'y';
3407     n = GetTextFaceW(dc, 2, bufW);
3408     ok(n == 2, "GetTextFaceW returned %d\n", n);
3409     ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3410
3411     n = GetTextFaceW(dc, 0, NULL);
3412     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3413
3414     DeleteObject(SelectObject(dc, g));
3415     ReleaseDC(NULL, dc);
3416 }
3417
3418 static void test_orientation(void)
3419 {
3420     static const char test_str[11] = "Test String";
3421     HDC hdc;
3422     LOGFONTA lf;
3423     HFONT hfont, old_hfont;
3424     SIZE size;
3425
3426     if (!is_truetype_font_installed("Arial"))
3427     {
3428         skip("Arial is not installed\n");
3429         return;
3430     }
3431
3432     hdc = CreateCompatibleDC(0);
3433     memset(&lf, 0, sizeof(lf));
3434     lstrcpyA(lf.lfFaceName, "Arial");
3435     lf.lfHeight = 72;
3436     lf.lfOrientation = lf.lfEscapement = 900;
3437     hfont = create_font("orientation", &lf);
3438     old_hfont = SelectObject(hdc, hfont);
3439     ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3440     ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3441     ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3442     SelectObject(hdc, old_hfont);
3443     DeleteObject(hfont);
3444     DeleteDC(hdc);
3445 }
3446
3447 static void test_oemcharset(void)
3448 {
3449     HDC hdc;
3450     LOGFONTA lf, clf;
3451     HFONT hfont, old_hfont;
3452     int charset;
3453
3454     hdc = CreateCompatibleDC(0);
3455     ZeroMemory(&lf, sizeof(lf));
3456     lf.lfHeight = 12;
3457     lf.lfCharSet = OEM_CHARSET;
3458     lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3459     lstrcpyA(lf.lfFaceName, "Terminal");
3460     hfont = CreateFontIndirectA(&lf);
3461     old_hfont = SelectObject(hdc, hfont);
3462     charset = GetTextCharset(hdc);
3463 todo_wine
3464     ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3465     hfont = SelectObject(hdc, old_hfont);
3466     GetObjectA(hfont, sizeof(clf), &clf);
3467     ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3468     ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3469     ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3470     ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3471     DeleteObject(hfont);
3472     DeleteDC(hdc);
3473 }
3474
3475 static void test_GetGlyphOutline(void)
3476 {
3477     HDC hdc;
3478     GLYPHMETRICS gm, gm2;
3479     LOGFONTA lf;
3480     HFONT hfont, old_hfont;
3481     INT ret, ret2;
3482     static const struct
3483     {
3484         UINT cs;
3485         UINT a;
3486         UINT w;
3487     } c[] =
3488     {
3489         {ANSI_CHARSET, 0x30, 0x30},
3490         {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3491         {HANGEUL_CHARSET, 0x8141, 0xac02},
3492         {JOHAB_CHARSET, 0x8446, 0x3135},
3493         {GB2312_CHARSET, 0x8141, 0x4e04},
3494         {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3495     };
3496     UINT i;
3497
3498     if (!is_truetype_font_installed("Tahoma"))
3499     {
3500         skip("Tahoma is not installed\n");
3501         return;
3502     }
3503
3504     hdc = CreateCompatibleDC(0);
3505     memset(&lf, 0, sizeof(lf));
3506     lf.lfHeight = 72;
3507     lstrcpyA(lf.lfFaceName, "Tahoma");
3508     SetLastError(0xdeadbeef);
3509     hfont = CreateFontIndirectA(&lf);
3510     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3511     old_hfont = SelectObject(hdc, hfont);
3512
3513     memset(&gm, 0, sizeof(gm));
3514     SetLastError(0xdeadbeef);
3515     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3516     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3517
3518     memset(&gm, 0, sizeof(gm));
3519     SetLastError(0xdeadbeef);
3520     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3521     ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3522     ok(GetLastError() == 0xdeadbeef ||
3523        GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3524        "expected 0xdeadbeef, got %u\n", GetLastError());
3525
3526     memset(&gm, 0, sizeof(gm));
3527     SetLastError(0xdeadbeef);
3528     ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3529     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3530         ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3531
3532     memset(&gm, 0, sizeof(gm));
3533     SetLastError(0xdeadbeef);
3534     ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3535     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3536     {
3537        ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3538        ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3539     }
3540
3541     /* test for needed buffer size request on space char */
3542     memset(&gm, 0, sizeof(gm));
3543     SetLastError(0xdeadbeef);
3544     ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3545     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3546         ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3547
3548     /* requesting buffer size for space char + error */
3549     memset(&gm, 0, sizeof(gm));
3550     SetLastError(0xdeadbeef);
3551     ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3552     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3553     {
3554        ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3555        ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3556     }
3557
3558     SelectObject(hdc, old_hfont);
3559     DeleteObject(hfont);
3560
3561     for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3562     {
3563         lf.lfFaceName[0] = '\0';
3564         lf.lfCharSet = c[i].cs;
3565         lf.lfPitchAndFamily = 0;
3566         if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3567         {
3568             skip("TrueType font for charset %u is not installed\n", c[i].cs);
3569             continue;
3570         }
3571
3572         old_hfont = SelectObject(hdc, hfont);
3573
3574         /* expected to ignore superfluous bytes (sigle-byte character) */
3575         ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3576         ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3577         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3578
3579         ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3580         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3581            "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3582
3583         /* expected to ignore superfluous bytes (double-byte character) */
3584         ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3585         ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3586         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3587            "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3588
3589         /* expected to match wide-char version results */
3590         ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3591         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3592
3593         hfont = SelectObject(hdc, old_hfont);
3594         DeleteObject(hfont);
3595     }
3596
3597     DeleteDC(hdc);
3598 }
3599
3600 /* bug #9995: there is a limit to the character width that can be specified */
3601 static void test_GetTextMetrics2(const char *fontname, int font_height)
3602 {
3603     HFONT of, hf;
3604     HDC hdc;
3605     TEXTMETRICA tm;
3606     BOOL ret;
3607     int ave_width, height, width, ratio, scale;
3608
3609     if (!is_truetype_font_installed( fontname)) {
3610         skip("%s is not installed\n", fontname);
3611         return;
3612     }
3613     hdc = CreateCompatibleDC(0);
3614     ok( hdc != NULL, "CreateCompatibleDC failed\n");
3615     /* select width = 0 */
3616     hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3617             DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3618             DEFAULT_QUALITY, VARIABLE_PITCH,
3619             fontname);
3620     ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3621     of = SelectObject( hdc, hf);
3622     ret = GetTextMetricsA( hdc, &tm);
3623     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3624     height = tm.tmHeight;
3625     ave_width = tm.tmAveCharWidth;
3626     SelectObject( hdc, of);
3627     DeleteObject( hf);
3628
3629     trace("height %d, ave width %d\n", height, ave_width);
3630
3631     for (width = ave_width * 2; /* nothing*/; width += ave_width)
3632     {
3633         hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3634                         DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3635                         DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3636         ok(hf != 0, "CreateFont failed\n");
3637         of = SelectObject(hdc, hf);
3638         ret = GetTextMetrics(hdc, &tm);
3639         ok(ret, "GetTextMetrics error %u\n", GetLastError());
3640         SelectObject(hdc, of);
3641         DeleteObject(hf);
3642
3643         if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3644             break;
3645     }
3646
3647     DeleteDC(hdc);
3648
3649     ratio = width / height;
3650     scale = width / ave_width;
3651
3652     trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3653           width, height, ratio, width, ave_width, scale);
3654
3655     ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3656 }
3657
3658 static void test_CreateFontIndirect(void)
3659 {
3660     LOGFONTA lf, getobj_lf;
3661     int ret, i;
3662     HFONT hfont;
3663     char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3664
3665     memset(&lf, 0, sizeof(lf));
3666     lf.lfCharSet = ANSI_CHARSET;
3667     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3668     lf.lfHeight = 16;
3669     lf.lfWidth = 16;
3670     lf.lfQuality = DEFAULT_QUALITY;
3671     lf.lfItalic = FALSE;
3672     lf.lfWeight = FW_DONTCARE;
3673
3674     for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3675     {
3676         lstrcpyA(lf.lfFaceName, TestName[i]);
3677         hfont = CreateFontIndirectA(&lf);
3678         ok(hfont != 0, "CreateFontIndirectA failed\n");
3679         SetLastError(0xdeadbeef);
3680         ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3681         ok(ret, "GetObject failed: %d\n", GetLastError());
3682         ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3683         ok(lf.lfWeight == getobj_lf.lfWeight ||
3684            broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3685            "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3686         ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3687            broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3688            "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3689         DeleteObject(hfont);
3690     }
3691 }
3692
3693 static void test_CreateFontIndirectEx(void)
3694 {
3695     ENUMLOGFONTEXDVA lfex;
3696     HFONT hfont;
3697
3698     if (!pCreateFontIndirectExA)
3699     {
3700         win_skip("CreateFontIndirectExA is not available\n");
3701         return;
3702     }
3703
3704     if (!is_truetype_font_installed("Arial"))
3705     {
3706         skip("Arial is not installed\n");
3707         return;
3708     }
3709
3710     SetLastError(0xdeadbeef);
3711     hfont = pCreateFontIndirectExA(NULL);
3712     ok(hfont == NULL, "got %p\n", hfont);
3713     ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3714
3715     memset(&lfex, 0, sizeof(lfex));
3716     lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3717     hfont = pCreateFontIndirectExA(&lfex);
3718     ok(hfont != 0, "CreateFontIndirectEx failed\n");
3719     if (hfont)
3720         check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3721     DeleteObject(hfont);
3722 }
3723
3724 static void free_font(void *font)
3725 {
3726     UnmapViewOfFile(font);
3727 }
3728
3729 static void *load_font(const char *font_name, DWORD *font_size)
3730 {
3731     char file_name[MAX_PATH];
3732     HANDLE file, mapping;
3733     void *font;
3734
3735     if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3736     strcat(file_name, "\\fonts\\");
3737     strcat(file_name, font_name);
3738
3739     file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3740     if (file == INVALID_HANDLE_VALUE) return NULL;
3741
3742     *font_size = GetFileSize(file, NULL);
3743
3744     mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3745     if (!mapping)
3746     {
3747         CloseHandle(file);
3748         return NULL;
3749     }
3750
3751     font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3752
3753     CloseHandle(file);
3754     CloseHandle(mapping);
3755     return font;
3756 }
3757
3758 static void test_AddFontMemResource(void)
3759 {
3760     void *font;
3761     DWORD font_size, num_fonts;
3762     HANDLE ret;
3763     BOOL bRet;
3764
3765     if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3766     {
3767         win_skip("AddFontMemResourceEx is not available on this platform\n");
3768         return;
3769     }
3770
3771     font = load_font("sserife.fon", &font_size);
3772     if (!font)
3773     {
3774         skip("Unable to locate and load font sserife.fon\n");
3775         return;
3776     }
3777
3778     SetLastError(0xdeadbeef);
3779     ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3780     ok(!ret, "AddFontMemResourceEx should fail\n");
3781     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3782        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3783        GetLastError());
3784
3785     SetLastError(0xdeadbeef);
3786     ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3787     ok(!ret, "AddFontMemResourceEx should fail\n");
3788     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3789        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3790        GetLastError());
3791
3792     SetLastError(0xdeadbeef);
3793     ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3794     ok(!ret, "AddFontMemResourceEx should fail\n");
3795     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3796        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3797        GetLastError());
3798
3799     SetLastError(0xdeadbeef);
3800     ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3801     ok(!ret, "AddFontMemResourceEx should fail\n");
3802     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3803        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3804        GetLastError());
3805
3806     SetLastError(0xdeadbeef);
3807     ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3808     ok(!ret, "AddFontMemResourceEx should fail\n");
3809     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3810        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3811        GetLastError());
3812
3813     SetLastError(0xdeadbeef);
3814     ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3815     ok(!ret, "AddFontMemResourceEx should fail\n");
3816     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3817        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3818        GetLastError());
3819
3820     num_fonts = 0xdeadbeef;
3821     SetLastError(0xdeadbeef);
3822     ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3823     ok(!ret, "AddFontMemResourceEx should fail\n");
3824     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3825        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3826        GetLastError());
3827     ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3828
3829     if (0) /* hangs under windows 2000 */
3830     {
3831         num_fonts = 0xdeadbeef;
3832         SetLastError(0xdeadbeef);
3833         ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3834         ok(!ret, "AddFontMemResourceEx should fail\n");
3835         ok(GetLastError() == 0xdeadbeef,
3836            "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3837            GetLastError());
3838         ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3839     }
3840
3841     num_fonts = 0xdeadbeef;
3842     SetLastError(0xdeadbeef);
3843     ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3844     ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3845     ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3846     ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3847
3848     free_font(font);
3849
3850     SetLastError(0xdeadbeef);
3851     bRet = pRemoveFontMemResourceEx(ret);
3852     ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3853
3854     /* test invalid pointer to number of loaded fonts */
3855     font = load_font("sserife.fon", &font_size);
3856     ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3857
3858     SetLastError(0xdeadbeef);
3859     ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3860     ok(!ret, "AddFontMemResourceEx should fail\n");
3861     ok(GetLastError() == 0xdeadbeef,
3862        "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3863        GetLastError());
3864
3865     SetLastError(0xdeadbeef);
3866     ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3867     ok(!ret, "AddFontMemResourceEx should fail\n");
3868     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3869        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3870        GetLastError());
3871
3872     free_font(font);
3873 }
3874
3875 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3876 {
3877     LOGFONT *lf;
3878
3879     if (type != TRUETYPE_FONTTYPE) return 1;
3880
3881     ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3882
3883     lf = (LOGFONT *)lparam;
3884     *lf = *elf;
3885     return 0;
3886 }
3887
3888 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3889 {
3890     int ret;
3891     LOGFONT *lf;
3892
3893     if (type != TRUETYPE_FONTTYPE) return 1;
3894
3895     lf = (LOGFONT *)lparam;
3896     ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3897     if(ret == 0)
3898     {
3899         ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3900         *lf = *elf;
3901         return 0;
3902     }
3903     return 1;
3904 }
3905
3906 static INT CALLBACK enum_with_magic_retval_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3907 {
3908     return lparam;
3909 }
3910
3911 static void test_EnumFonts(void)
3912 {
3913     int ret;
3914     LOGFONT lf;
3915     HDC hdc;
3916
3917     if (!is_truetype_font_installed("Arial"))
3918     {
3919         skip("Arial is not installed\n");
3920         return;
3921     }
3922
3923     /* Windows uses localized font face names, so Arial Bold won't be found */
3924     if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3925     {
3926         skip("User locale is not English, skipping the test\n");
3927         return;
3928     }
3929
3930     hdc = CreateCompatibleDC(0);
3931
3932     /* check that the enumproc's retval is returned */
3933     ret = EnumFontFamilies(hdc, NULL, enum_with_magic_retval_proc, 0xcafe);
3934     ok(ret == 0xcafe, "got %08x\n", ret);
3935
3936     ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3937     ok(!ret, "font Arial is not enumerated\n");
3938     ret = strcmp(lf.lfFaceName, "Arial");
3939     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3940     ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3941
3942     lstrcpy(lf.lfFaceName, "Arial");
3943     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3944     ok(!ret, "font Arial is not enumerated\n");
3945     ret = strcmp(lf.lfFaceName, "Arial");
3946     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3947     ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3948
3949     ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3950     ok(!ret, "font Arial Bold is not enumerated\n");
3951     ret = strcmp(lf.lfFaceName, "Arial");
3952     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3953     ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3954
3955     lstrcpy(lf.lfFaceName, "Arial Bold");
3956     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3957     ok(ret, "font Arial Bold should not be enumerated\n");
3958
3959     ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3960     ok(!ret, "font Arial Bold Italic is not enumerated\n");
3961     ret = strcmp(lf.lfFaceName, "Arial");
3962     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3963     ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3964
3965     lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3966     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3967     ok(ret, "font Arial Bold Italic should not be enumerated\n");
3968
3969     ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3970     ok(ret, "font Arial Italic Bold  should not be enumerated\n");
3971
3972     lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3973     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3974     ok(ret, "font Arial Italic Bold should not be enumerated\n");
3975
3976     DeleteDC(hdc);
3977 }
3978
3979 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3980 {
3981     const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3982     const char *fullname = (const char *)lParam;
3983
3984     if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3985
3986     return 1;
3987 }
3988
3989 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3990 {
3991     HDC hdc = GetDC(0);
3992     BOOL ret = FALSE;
3993
3994     if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3995         ret = TRUE;
3996
3997     ReleaseDC(0, hdc);
3998     return ret;
3999 }
4000
4001 static void test_fullname(void)
4002 {
4003     static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4004     WCHAR bufW[LF_FULLFACESIZE];
4005     char bufA[LF_FULLFACESIZE];
4006     HFONT hfont, of;
4007     LOGFONTA lf;
4008     HDC hdc;
4009     int i;
4010     DWORD ret;
4011
4012     hdc = CreateCompatibleDC(0);
4013     ok(hdc != NULL, "CreateCompatibleDC failed\n");
4014
4015     memset(&lf, 0, sizeof(lf));
4016     lf.lfCharSet = ANSI_CHARSET;
4017     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4018     lf.lfHeight = 16;
4019     lf.lfWidth = 16;
4020     lf.lfQuality = DEFAULT_QUALITY;
4021     lf.lfItalic = FALSE;
4022     lf.lfWeight = FW_DONTCARE;
4023
4024     for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
4025     {
4026         if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
4027         {
4028             skip("%s is not installed\n", TestName[i]);
4029             continue;
4030         }
4031
4032         lstrcpyA(lf.lfFaceName, TestName[i]);
4033         hfont = CreateFontIndirectA(&lf);
4034         ok(hfont != 0, "CreateFontIndirectA failed\n");
4035
4036         of = SelectObject(hdc, hfont);
4037         bufW[0] = 0;
4038         bufA[0] = 0;
4039         ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, sizeof(bufW), TT_MS_LANGID_ENGLISH_UNITED_STATES);
4040         ok(ret, "face full name could not be read\n");
4041         WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, sizeof(bufA), NULL, FALSE);
4042         ok(!lstrcmpA(bufA, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], bufA);
4043         SelectObject(hdc, of);
4044         DeleteObject(hfont);
4045     }
4046     DeleteDC(hdc);
4047 }
4048
4049 static void test_fullname2_helper(const char *Family)
4050 {
4051     char *FamilyName, *FaceName, *StyleName, *otmStr;
4052     struct enum_fullname_data efnd;
4053     WCHAR *bufW;
4054     char *bufA;
4055     HFONT hfont, of;
4056     LOGFONTA lf;
4057     HDC hdc;
4058     int i;
4059     DWORD otm_size, ret, buf_size;
4060     OUTLINETEXTMETRICA *otm;
4061     BOOL want_vertical, get_vertical;
4062     want_vertical = ( Family[0] == '@' );
4063
4064     hdc = CreateCompatibleDC(0);
4065     ok(hdc != NULL, "CreateCompatibleDC failed\n");
4066
4067     memset(&lf, 0, sizeof(lf));
4068     lf.lfCharSet = DEFAULT_CHARSET;
4069     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4070     lf.lfHeight = 16;
4071     lf.lfWidth = 16;
4072     lf.lfQuality = DEFAULT_QUALITY;
4073     lf.lfItalic = FALSE;
4074     lf.lfWeight = FW_DONTCARE;
4075     lstrcpy(lf.lfFaceName, Family);
4076     efnd.total = 0;
4077     EnumFontFamiliesExA(hdc, &lf, enum_fullname_data_proc, (LPARAM)&efnd, 0);
4078     if (efnd.total == 0)
4079         skip("%s is not installed\n", lf.lfFaceName);
4080
4081     for (i = 0; i < efnd.total; i++)
4082     {
4083         FamilyName = (char *)efnd.elf[i].elfLogFont.lfFaceName;
4084         FaceName = (char *)efnd.elf[i].elfFullName;
4085         StyleName = (char *)efnd.elf[i].elfStyle;
4086
4087         trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family, FamilyName, FaceName, StyleName);
4088
4089         get_vertical = ( FamilyName[0] == '@' );
4090         if (get_vertical)
4091         {
4092             todo_wine ok(get_vertical == want_vertical, "Vertical flags don't match: %s %s\n", Family, FamilyName);
4093             continue;
4094         }
4095
4096         lstrcpyA(lf.lfFaceName, FaceName);
4097         hfont = CreateFontIndirectA(&lf);
4098         ok(hfont != 0, "CreateFontIndirectA failed\n");
4099
4100         of = SelectObject(hdc, hfont);
4101         buf_size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
4102         ok(buf_size != GDI_ERROR, "no name table found\n");
4103         if (buf_size == GDI_ERROR) continue;
4104
4105         bufW = HeapAlloc(GetProcessHeap(), 0, buf_size);
4106         bufA = HeapAlloc(GetProcessHeap(), 0, buf_size);
4107
4108         otm_size = GetOutlineTextMetricsA(hdc, 0, NULL);
4109         otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
4110         memset(otm, 0, otm_size);
4111         ret = GetOutlineTextMetrics(hdc, otm_size, otm);
4112         ok(ret != 0, "GetOutlineTextMetrics fails!\n");
4113         if (ret == 0) continue;
4114
4115         bufW[0] = 0;
4116         bufA[0] = 0;
4117         ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, GetSystemDefaultLangID());
4118         if (!ret)
4119         {
4120             trace("no localized FONT_FAMILY found.\n");
4121             ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_FAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4122         }
4123         ok(ret, "FAMILY (family name) could not be read\n");
4124         WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4125         ok(!lstrcmpA(FamilyName, bufA), "font family names don't match: returned %s, expect %s\n", FamilyName, bufA);
4126         otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFamilyName;
4127         ok(!lstrcmpA(FamilyName, otmStr), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName, otmStr);
4128
4129         bufW[0] = 0;
4130         bufA[0] = 0;
4131         ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, GetSystemDefaultLangID());
4132         if (!ret)
4133         {
4134             trace("no localized FULL_NAME found.\n");
4135             ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4136         }
4137         ok(ret, "FULL_NAME (face name) could not be read\n");
4138         WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4139         ok(!lstrcmpA(FaceName, bufA), "font face names don't match: returned %s, expect %s\n", FaceName, bufA);
4140         otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFaceName;
4141         ok(!lstrcmpA(FaceName, otmStr), "FaceName %s doesn't match otmpFaceName %s\n", FaceName, otmStr);
4142
4143         bufW[0] = 0;
4144         bufA[0] = 0;
4145         ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, GetSystemDefaultLangID());
4146         if (!ret)
4147         {
4148             trace("no localized FONT_SUBFAMILY font.\n");
4149             ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_FONT_SUBFAMILY, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4150         }
4151         ok(ret, "SUBFAMILY (style name) could not be read\n");
4152         WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4153         ok(!lstrcmpA(StyleName, bufA), "style names don't match: returned %s, expect %s\n", StyleName, bufA);
4154         otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpStyleName;
4155         ok(!lstrcmpA(StyleName, otmStr), "StyleName %s doesn't match otmpStyleName %s\n", StyleName, otmStr);
4156
4157         bufW[0] = 0;
4158         bufA[0] = 0;
4159         ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, GetSystemDefaultLangID());
4160         if (!ret)
4161         {
4162             trace("no localized UNIQUE_ID found.\n");
4163             ret = get_ttf_nametable_entry(hdc, TT_NAME_ID_UNIQUE_ID, bufW, buf_size, TT_MS_LANGID_ENGLISH_UNITED_STATES);
4164         }
4165         ok(ret, "UNIQUE_ID (full name) could not be read\n");
4166         WideCharToMultiByte(CP_ACP, 0, bufW, -1, bufA, buf_size, NULL, FALSE);
4167         otmStr = (LPSTR)otm + (UINT_PTR)otm->otmpFullName;
4168         ok(!lstrcmpA(otmStr, bufA), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr, bufA);
4169
4170         SelectObject(hdc, of);
4171         DeleteObject(hfont);
4172
4173         HeapFree(GetProcessHeap(), 0, otm);
4174         HeapFree(GetProcessHeap(), 0, bufW);
4175         HeapFree(GetProcessHeap(), 0, bufA);
4176     }
4177     DeleteDC(hdc);
4178 }
4179
4180 static void test_fullname2(void)
4181 {
4182     test_fullname2_helper("Arial");
4183     test_fullname2_helper("DejaVu Sans");
4184     test_fullname2_helper("Lucida Sans");
4185     test_fullname2_helper("Tahoma");
4186     test_fullname2_helper("Webdings");
4187     test_fullname2_helper("Wingdings");
4188     test_fullname2_helper("SimSun");
4189     test_fullname2_helper("NSimSun");
4190     test_fullname2_helper("MingLiu");
4191     test_fullname2_helper("PMingLiu");
4192     test_fullname2_helper("WenQuanYi Micro Hei");
4193     test_fullname2_helper("MS UI Gothic");
4194     test_fullname2_helper("Ume UI Gothic");
4195     test_fullname2_helper("MS Gothic");
4196     test_fullname2_helper("Ume Gothic");
4197     test_fullname2_helper("MS PGothic");
4198     test_fullname2_helper("Ume P Gothic");
4199     test_fullname2_helper("Gulim");
4200     test_fullname2_helper("Batang");
4201     test_fullname2_helper("UnBatang");
4202     test_fullname2_helper("UnDotum");
4203
4204 }
4205
4206 static BOOL write_ttf_file(const char *fontname, char *tmp_name)
4207 {
4208     char tmp_path[MAX_PATH];
4209     HRSRC rsrc;
4210     void *rsrc_data;
4211     DWORD rsrc_size;
4212     HANDLE hfile;
4213     BOOL ret;
4214
4215     SetLastError(0xdeadbeef);
4216     rsrc = FindResource(GetModuleHandle(0), fontname, RT_RCDATA);
4217     ok(rsrc != 0, "FindResource error %d\n", GetLastError());
4218     if (!rsrc) return FALSE;
4219     SetLastError(0xdeadbeef);
4220     rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
4221     ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
4222     if (!rsrc_data) return FALSE;
4223     SetLastError(0xdeadbeef);
4224     rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
4225     ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
4226     if (!rsrc_size) return FALSE;
4227
4228     SetLastError(0xdeadbeef);
4229     ret = GetTempPath(MAX_PATH, tmp_path);
4230     ok(ret, "GetTempPath() error %d\n", GetLastError());
4231     SetLastError(0xdeadbeef);
4232     ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
4233     ok(ret, "GetTempFileName() error %d\n", GetLastError());
4234
4235     SetLastError(0xdeadbeef);
4236     hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
4237     ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
4238     if (hfile == INVALID_HANDLE_VALUE) return FALSE;
4239
4240     SetLastError(0xdeadbeef);
4241     ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
4242     ok(ret, "WriteFile() error %d\n", GetLastError());
4243
4244     CloseHandle(hfile);
4245     return ret;
4246 }
4247
4248 static void test_CreateScalableFontResource(void)
4249 {
4250     char ttf_name[MAX_PATH];
4251     char tmp_path[MAX_PATH];
4252     char fot_name[MAX_PATH];
4253     char *file_part;
4254     DWORD ret;
4255
4256     if (!pAddFontResourceExA || !pRemoveFontResourceExA)
4257     {
4258         win_skip("AddFontResourceExA is not available on this platform\n");
4259         return;
4260     }
4261
4262     if (!write_ttf_file("wine_test.ttf", ttf_name))
4263     {
4264         skip("Failed to create ttf file for testing\n");
4265         return;
4266     }
4267
4268     trace("created %s\n", ttf_name);
4269
4270     ret = is_truetype_font_installed("wine_test");
4271     ok(!ret, "font wine_test should not be enumerated\n");
4272
4273     ret = GetTempPath(MAX_PATH, tmp_path);
4274     ok(ret, "GetTempPath() error %d\n", GetLastError());
4275     ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
4276     ok(ret, "GetTempFileName() error %d\n", GetLastError());
4277
4278     ret = GetFileAttributes(fot_name);
4279     ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
4280
4281     SetLastError(0xdeadbeef);
4282     ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4283     ok(!ret, "CreateScalableFontResource() should fail\n");
4284     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4285
4286     SetLastError(0xdeadbeef);
4287     ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
4288     ok(!ret, "CreateScalableFontResource() should fail\n");
4289     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4290
4291     file_part = strrchr(ttf_name, '\\');
4292     SetLastError(0xdeadbeef);
4293     ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
4294     ok(!ret, "CreateScalableFontResource() should fail\n");
4295     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
4296
4297     SetLastError(0xdeadbeef);
4298     ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
4299     ok(!ret, "CreateScalableFontResource() should fail\n");
4300     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4301
4302     SetLastError(0xdeadbeef);
4303     ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
4304     ok(!ret, "CreateScalableFontResource() should fail\n");
4305     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
4306
4307     ret = DeleteFile(fot_name);
4308     ok(ret, "DeleteFile() error %d\n", GetLastError());
4309
4310     ret = pRemoveFontResourceExA(fot_name, 0, 0);
4311 todo_wine
4312     ok(!ret, "RemoveFontResourceEx() should fail\n");
4313
4314     /* test public font resource */
4315     SetLastError(0xdeadbeef);
4316     ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
4317     ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4318
4319     ret = is_truetype_font_installed("wine_test");
4320     ok(!ret, "font wine_test should not be enumerated\n");
4321
4322     SetLastError(0xdeadbeef);
4323     ret = pAddFontResourceExA(fot_name, 0, 0);
4324     ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4325
4326     ret = is_truetype_font_installed("wine_test");
4327     ok(ret, "font wine_test should be enumerated\n");
4328
4329     ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4330 todo_wine
4331     ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
4332
4333     SetLastError(0xdeadbeef);
4334     ret = pRemoveFontResourceExA(fot_name, 0, 0);
4335     ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4336
4337     ret = is_truetype_font_installed("wine_test");
4338 todo_wine
4339     ok(!ret, "font wine_test should not be enumerated\n");
4340
4341     /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4342     if (ret)
4343     {
4344         /* remove once RemoveFontResource is implemented */
4345         DeleteFile(fot_name);
4346         DeleteFile(ttf_name);
4347         return;
4348     }
4349
4350     ret = pRemoveFontResourceExA(fot_name, 0, 0);
4351     ok(!ret, "RemoveFontResourceEx() should fail\n");
4352
4353     DeleteFile(fot_name);
4354
4355     /* test hidden font resource */
4356     SetLastError(0xdeadbeef);
4357     ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
4358     ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
4359
4360     ret = is_truetype_font_installed("wine_test");
4361     ok(!ret, "font wine_test should not be enumerated\n");
4362
4363     SetLastError(0xdeadbeef);
4364     ret = pAddFontResourceExA(fot_name, 0, 0);
4365     ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
4366
4367     ret = is_truetype_font_installed("wine_test");
4368     ok(!ret, "font wine_test should not be enumerated\n");
4369
4370     /* XP allows removing a private font added with 0 flags */
4371     SetLastError(0xdeadbeef);
4372     ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
4373     ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4374
4375     ret = is_truetype_font_installed("wine_test");
4376     ok(!ret, "font wine_test should not be enumerated\n");
4377
4378     ret = pRemoveFontResourceExA(fot_name, 0, 0);
4379     ok(!ret, "RemoveFontResourceEx() should fail\n");
4380
4381     DeleteFile(fot_name);
4382     DeleteFile(ttf_name);
4383 }
4384
4385 static void check_vertical_font(const char *name, BOOL *installed, BOOL *selected, GLYPHMETRICS *gm, WORD *gi)
4386 {
4387     LOGFONTA lf;
4388     HFONT hfont, hfont_prev;
4389     HDC hdc;
4390     char facename[100];
4391     DWORD ret;
4392     static const WCHAR str[] = { 0x2025 };
4393
4394     *installed = is_truetype_font_installed(name);
4395
4396     lf.lfHeight = -18;
4397     lf.lfWidth = 0;
4398     lf.lfEscapement = 0;
4399     lf.lfOrientation = 0;
4400     lf.lfWeight = FW_DONTCARE;
4401     lf.lfItalic = 0;
4402     lf.lfUnderline = 0;
4403     lf.lfStrikeOut = 0;
4404     lf.lfCharSet = DEFAULT_CHARSET;
4405     lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
4406     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
4407     lf.lfQuality = DEFAULT_QUALITY;
4408     lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
4409     strcpy(lf.lfFaceName, name);
4410
4411     hfont = CreateFontIndirectA(&lf);
4412     ok(hfont != NULL, "CreateFontIndirectA failed\n");
4413
4414     hdc = GetDC(NULL);
4415
4416     hfont_prev = SelectObject(hdc, hfont);
4417     ok(hfont_prev != NULL, "SelectObject failed\n");
4418
4419     ret = GetTextFaceA(hdc, sizeof facename, facename);
4420     ok(ret, "GetTextFaceA failed\n");
4421     *selected = !strcmp(facename, name);
4422
4423     ret = GetGlyphOutlineW(hdc, 0x2025, GGO_METRICS, gm, 0, NULL, &mat);
4424     ok(ret != GDI_ERROR, "GetGlyphOutlineW failed\n");
4425     if (!*selected)
4426         memset(gm, 0, sizeof *gm);
4427
4428     ret = pGetGlyphIndicesW(hdc, str, 1, gi, 0);
4429     ok(ret != GDI_ERROR, "GetGlyphIndicesW failed\n");
4430
4431     SelectObject(hdc, hfont_prev);
4432     DeleteObject(hfont);
4433     ReleaseDC(NULL, hdc);
4434 }
4435
4436 static void test_vertical_font(void)
4437 {
4438     char ttf_name[MAX_PATH];
4439     int num;
4440     BOOL ret, installed, selected;
4441     GLYPHMETRICS gm;
4442     WORD hgi, vgi;
4443
4444     if (!pAddFontResourceExA || !pRemoveFontResourceExA || !pGetGlyphIndicesW)
4445     {
4446         win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4447         return;
4448     }
4449
4450     if (!write_ttf_file("vertical.ttf", ttf_name))
4451     {
4452         skip("Failed to create ttf file for testing\n");
4453         return;
4454     }
4455
4456     num = pAddFontResourceExA(ttf_name, FR_PRIVATE, 0);
4457     ok(num == 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4458
4459     check_vertical_font("@WineTestVertical", &installed, &selected, &gm, &hgi);
4460     ok(installed, "@WineTestVertical is not installed\n");
4461     ok(selected, "@WineTestVertical is not selected\n");
4462     ok(gm.gmBlackBoxX > gm.gmBlackBoxY,
4463        "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4464        gm.gmBlackBoxX, gm.gmBlackBoxY);
4465
4466     check_vertical_font("@@WineTestVertical", &installed, &selected, &gm, &vgi);
4467     ok(installed, "@@WineTestVertical is not installed\n");
4468     ok(selected, "@@WineTestVertical is not selected\n");
4469     ok(gm.gmBlackBoxX < gm.gmBlackBoxY,
4470        "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4471        gm.gmBlackBoxX, gm.gmBlackBoxY);
4472
4473     ok(hgi == vgi, "different glyph h:%u v:%u\n", hgi, vgi);
4474
4475     ret = pRemoveFontResourceExA(ttf_name, FR_PRIVATE, 0);
4476     ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
4477
4478     DeleteFile(ttf_name);
4479 }
4480
4481 static INT CALLBACK has_vertical_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm,
4482                                            DWORD type, LPARAM lParam)
4483 {
4484     if (lf->lfFaceName[0] == '@') {
4485         return 0;
4486     }
4487     return 1;
4488 }
4489
4490 static void test_east_asian_font_selection(void)
4491 {
4492     HDC hdc;
4493     UINT charset[] = { SHIFTJIS_CHARSET, HANGEUL_CHARSET, JOHAB_CHARSET,
4494                        GB2312_CHARSET, CHINESEBIG5_CHARSET };
4495     size_t i;
4496
4497     hdc = GetDC(NULL);
4498
4499     for (i = 0; i < sizeof(charset)/sizeof(charset[0]); i++)
4500     {
4501         LOGFONTA lf;
4502         HFONT hfont;
4503         char face_name[LF_FACESIZE];
4504         int ret;
4505
4506         memset(&lf, 0, sizeof lf);
4507         lf.lfFaceName[0] = '\0';
4508         lf.lfCharSet = charset[i];
4509
4510         if (EnumFontFamiliesEx(hdc, &lf, has_vertical_font_proc, 0, 0))
4511         {
4512             skip("Vertical font for charset %u is not installed\n", charset[i]);
4513             continue;
4514         }
4515
4516         hfont = CreateFontIndirectA(&lf);
4517         hfont = SelectObject(hdc, hfont);
4518         memset(face_name, 0, sizeof face_name);
4519         ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4520         ok(ret && face_name[0] != '@',
4521            "expected non-vertical face for charset %u, got %s\n", charset[i], face_name);
4522         DeleteObject(SelectObject(hdc, hfont));
4523
4524         memset(&lf, 0, sizeof lf);
4525         strcpy(lf.lfFaceName, "@");
4526         lf.lfCharSet = charset[i];
4527         hfont = CreateFontIndirectA(&lf);
4528         hfont = SelectObject(hdc, hfont);
4529         memset(face_name, 0, sizeof face_name);
4530         ret = GetTextFaceA(hdc, sizeof face_name, face_name);
4531         ok(ret && face_name[0] == '@',
4532            "expected vertical face for charset %u, got %s\n", charset[i], face_name);
4533         DeleteObject(SelectObject(hdc, hfont));
4534     }
4535     ReleaseDC(NULL, hdc);
4536 }
4537
4538 static int get_font_dpi(const LOGFONT *lf)
4539 {
4540     HDC hdc = CreateCompatibleDC(0);
4541     HFONT hfont;
4542     TEXTMETRIC tm;
4543     int ret;
4544
4545     hfont = CreateFontIndirect(lf);
4546     ok(hfont != 0, "CreateFontIndirect failed\n");
4547
4548     SelectObject(hdc, hfont);
4549     ret = GetTextMetrics(hdc, &tm);
4550     ok(ret, "GetTextMetrics failed\n");
4551     ret = tm.tmDigitizedAspectX;
4552
4553     DeleteDC(hdc);
4554     DeleteObject(hfont);
4555
4556     return ret;
4557 }
4558
4559 static void test_stock_fonts(void)
4560 {
4561     static const int font[] =
4562     {
4563         ANSI_FIXED_FONT, ANSI_VAR_FONT, SYSTEM_FONT, DEVICE_DEFAULT_FONT, DEFAULT_GUI_FONT
4564         /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4565     };
4566     static const struct test_data
4567     {
4568         int charset, weight, height, dpi;
4569         const char face_name[LF_FACESIZE];
4570     } td[][11] =
4571     {
4572         { /* ANSI_FIXED_FONT */
4573             { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "Courier" },
4574             { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "Courier" },
4575             { 0 }
4576         },
4577         { /* ANSI_VAR_FONT */
4578             { DEFAULT_CHARSET, FW_NORMAL, 12, 96, "MS Sans Serif" },
4579             { DEFAULT_CHARSET, FW_NORMAL, 12, 120, "MS Sans Serif" },
4580             { 0 }
4581         },
4582         { /* SYSTEM_FONT */
4583             { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4584             { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4585             { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4586             { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4587             { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4588             { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4589             { 0 }
4590         },
4591         { /* DEVICE_DEFAULT_FONT */
4592             { SHIFTJIS_CHARSET, FW_NORMAL, 18, 96, "System" },
4593             { SHIFTJIS_CHARSET, FW_NORMAL, 22, 120, "System" },
4594             { HANGEUL_CHARSET, FW_NORMAL, 16, 96, "System" },
4595             { HANGEUL_CHARSET, FW_NORMAL, 20, 120, "System" },
4596             { DEFAULT_CHARSET, FW_BOLD, 16, 96, "System" },
4597             { DEFAULT_CHARSET, FW_BOLD, 20, 120, "System" },
4598             { 0 }
4599         },
4600         { /* DEFAULT_GUI_FONT */
4601             { SHIFTJIS_CHARSET, FW_NORMAL, -12, 96, "?MS UI Gothic" },
4602             { SHIFTJIS_CHARSET, FW_NORMAL, -15, 120, "?MS UI Gothic" },
4603             { HANGEUL_CHARSET, FW_NORMAL, -12, 96, "?Gulim" },
4604             { HANGEUL_CHARSET, FW_NORMAL, -15, 120, "?Gulim" },
4605             { GB2312_CHARSET, FW_NORMAL, -12, 96, "?SimHei" },
4606             { GB2312_CHARSET, FW_NORMAL, -15, 120, "?SimHei" },
4607             { CHINESEBIG5_CHARSET, FW_NORMAL, -12, 96, "?MingLiU" },
4608             { CHINESEBIG5_CHARSET, FW_NORMAL, -15, 120, "?MingLiU" },
4609             { DEFAULT_CHARSET, FW_NORMAL, -11, 96, "MS Shell Dlg" },
4610             { DEFAULT_CHARSET, FW_NORMAL, -13, 120, "MS Shell Dlg" },
4611             { 0 }
4612         }
4613     };
4614     int i, j;
4615
4616     for (i = 0; i < sizeof(font)/sizeof(font[0]); i++)
4617     {
4618         HFONT hfont;
4619         LOGFONT lf;
4620         int ret;
4621
4622         hfont = GetStockObject(font[i]);
4623         ok(hfont != 0, "%d: GetStockObject(%d) failed\n", i, font[i]);
4624
4625         ret = GetObject(hfont, sizeof(lf), &lf);
4626         if (ret != sizeof(lf))
4627         {
4628             /* NT4 */
4629             win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i, ret);
4630             continue;
4631         }
4632
4633         for (j = 0; td[i][j].face_name[0] != 0; j++)
4634         {
4635             if (lf.lfCharSet != td[i][j].charset && td[i][j].charset != DEFAULT_CHARSET)
4636             {
4637                 continue;
4638             }
4639
4640             ret = get_font_dpi(&lf);
4641             if (ret != td[i][j].dpi)
4642             {
4643                 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4644                       i, j, lf.lfFaceName, ret, td[i][j].dpi);
4645                 continue;
4646             }
4647
4648             ok(td[i][j].weight == lf.lfWeight, "%d(%d): expected lfWeight %d, got %d\n", i, j, td[i][j].weight, lf.lfWeight);
4649             ok(td[i][j].height == lf.lfHeight, "%d(%d): expected lfHeight %d, got %d\n", i, j, td[i][j].height, lf.lfHeight);
4650             if (td[i][j].face_name[0] == '?')
4651             {
4652                 /* Wine doesn't have this font, skip this case for now.
4653                    Actually, the face name is localized on Windows and varies
4654                    dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4655                 trace("%d(%d): default gui font is %s\n", i, j, lf.lfFaceName);
4656             }
4657             else
4658             {
4659                 ok(!lstrcmp(td[i][j].face_name, lf.lfFaceName), "%d(%d): expected lfFaceName %s, got %s\n", i, j, td[i][j].face_name, lf.lfFaceName);
4660             }
4661             break;
4662         }
4663     }
4664 }
4665
4666 START_TEST(font)
4667 {
4668     init();
4669
4670     test_stock_fonts();
4671     test_logfont();
4672     test_bitmap_font();
4673     test_outline_font();
4674     test_bitmap_font_metrics();
4675     test_GdiGetCharDimensions();
4676     test_GetCharABCWidths();
4677     test_text_extents();
4678     test_GetGlyphIndices();
4679     test_GetKerningPairs();
4680     test_GetOutlineTextMetrics();
4681     test_SetTextJustification();
4682     test_font_charset();
4683     test_GetFontUnicodeRanges();
4684     test_nonexistent_font();
4685     test_orientation();
4686     test_height_selection();
4687     test_AddFontMemResource();
4688     test_EnumFonts();
4689
4690     /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4691      * I'd like to avoid them in this test.
4692      */
4693     test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4694     test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4695     if (is_truetype_font_installed("Arial Black") &&
4696         (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4697     {
4698         test_EnumFontFamilies("", ANSI_CHARSET);
4699         test_EnumFontFamilies("", SYMBOL_CHARSET);
4700         test_EnumFontFamilies("", DEFAULT_CHARSET);
4701     }
4702     else
4703         skip("Arial Black or Symbol/Wingdings is not installed\n");
4704     test_EnumFontFamiliesEx_default_charset();
4705     test_GetTextMetrics();
4706     test_GdiRealizationInfo();
4707     test_GetTextFace();
4708     test_GetGlyphOutline();
4709     test_GetTextMetrics2("Tahoma", -11);
4710     test_GetTextMetrics2("Tahoma", -55);
4711     test_GetTextMetrics2("Tahoma", -110);
4712     test_GetTextMetrics2("Arial", -11);
4713     test_GetTextMetrics2("Arial", -55);
4714     test_GetTextMetrics2("Arial", -110);
4715     test_CreateFontIndirect();
4716     test_CreateFontIndirectEx();
4717     test_oemcharset();
4718     test_fullname();
4719     test_fullname2();
4720     test_east_asian_font_selection();
4721
4722     /* These tests should be last test until RemoveFontResource
4723      * is properly implemented.
4724      */
4725     test_vertical_font();
4726     test_CreateScalableFontResource();
4727 }