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