kernel32/tests: Better check the NT path returned by QueryFullProcessImageName().
[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         /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1346          * passes on XP.
1347          */
1348         SetLastError(0xdeadbeef);
1349         ret = GetKerningPairsW(hdc, 0, kern_pair);
1350         ok(GetLastError() == ERROR_INVALID_PARAMETER,
1351            "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1352         ok(ret == 0, "got %u, expected 0\n", ret);
1353
1354         ret = GetKerningPairsW(hdc, 100, NULL);
1355         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1356
1357         ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1358         ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1359
1360         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1361         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1362
1363         matches = 0;
1364
1365         for (n = 0; n < ret; n++)
1366         {
1367             DWORD j;
1368             /* Disabled to limit console spam */
1369             if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1370                 trace("{'%c','%c',%d},\n",
1371                       kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
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     DWORD i;
1824
1825     if (!pGetFontUnicodeRanges)
1826     {
1827         win_skip("GetFontUnicodeRanges not available before W2K\n");
1828         return;
1829     }
1830
1831     memset(&lf, 0, sizeof(lf));
1832     lstrcpyA(lf.lfFaceName, "Arial");
1833     hfont = create_font("Arial", &lf);
1834
1835     hdc = GetDC(0);
1836     hfont_old = SelectObject(hdc, hfont);
1837
1838     size = pGetFontUnicodeRanges(NULL, NULL);
1839     ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1840
1841     size = pGetFontUnicodeRanges(hdc, NULL);
1842     ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1843
1844     gs = HeapAlloc(GetProcessHeap(), 0, size);
1845
1846     size = pGetFontUnicodeRanges(hdc, gs);
1847     ok(size, "GetFontUnicodeRanges failed\n");
1848
1849     if (0) /* Disabled to limit console spam */
1850         for (i = 0; i < gs->cRanges; i++)
1851             trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1852     trace("found %u ranges\n", gs->cRanges);
1853
1854     HeapFree(GetProcessHeap(), 0, gs);
1855
1856     SelectObject(hdc, hfont_old);
1857     DeleteObject(hfont);
1858     ReleaseDC(NULL, hdc);
1859 }
1860
1861 #define MAX_ENUM_FONTS 4096
1862
1863 struct enum_font_data
1864 {
1865     int total;
1866     LOGFONT lf[MAX_ENUM_FONTS];
1867 };
1868
1869 struct enum_font_dataW
1870 {
1871     int total;
1872     LOGFONTW lf[MAX_ENUM_FONTS];
1873 };
1874
1875 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1876 {
1877     struct enum_font_data *efd = (struct enum_font_data *)lParam;
1878
1879     ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1880
1881     if (type != TRUETYPE_FONTTYPE) return 1;
1882     if (0) /* Disabled to limit console spam */
1883         trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1884               lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
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) /* Disabled to limit console spam */
1901         trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1902               wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1903     if (efd->total < MAX_ENUM_FONTS)
1904         efd->lf[efd->total++] = *lf;
1905     else
1906         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1907
1908     return 1;
1909 }
1910
1911 static void get_charset_stats(struct enum_font_data *efd,
1912                               int *ansi_charset, int *symbol_charset,
1913                               int *russian_charset)
1914 {
1915     int i;
1916
1917     *ansi_charset = 0;
1918     *symbol_charset = 0;
1919     *russian_charset = 0;
1920
1921     for (i = 0; i < efd->total; i++)
1922     {
1923         switch (efd->lf[i].lfCharSet)
1924         {
1925         case ANSI_CHARSET:
1926             (*ansi_charset)++;
1927             break;
1928         case SYMBOL_CHARSET:
1929             (*symbol_charset)++;
1930             break;
1931         case RUSSIAN_CHARSET:
1932             (*russian_charset)++;
1933             break;
1934         }
1935     }
1936 }
1937
1938 static void get_charset_statsW(struct enum_font_dataW *efd,
1939                               int *ansi_charset, int *symbol_charset,
1940                               int *russian_charset)
1941 {
1942     int i;
1943
1944     *ansi_charset = 0;
1945     *symbol_charset = 0;
1946     *russian_charset = 0;
1947
1948     for (i = 0; i < efd->total; i++)
1949     {
1950         switch (efd->lf[i].lfCharSet)
1951         {
1952         case ANSI_CHARSET:
1953             (*ansi_charset)++;
1954             break;
1955         case SYMBOL_CHARSET:
1956             (*symbol_charset)++;
1957             break;
1958         case RUSSIAN_CHARSET:
1959             (*russian_charset)++;
1960             break;
1961         }
1962     }
1963 }
1964
1965 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1966 {
1967     struct enum_font_data efd;
1968     struct enum_font_dataW efdw;
1969     LOGFONT lf;
1970     HDC hdc;
1971     int i, ret, ansi_charset, symbol_charset, russian_charset;
1972
1973     trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1974
1975     if (*font_name && !is_truetype_font_installed(font_name))
1976     {
1977         skip("%s is not installed\n", font_name);
1978         return;
1979     }
1980
1981     hdc = GetDC(0);
1982
1983     /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1984      * while EnumFontFamiliesEx doesn't.
1985      */
1986     if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1987     {
1988         /*
1989          * Use EnumFontFamiliesW since win98 crashes when the
1990          *    second parameter is NULL using EnumFontFamilies
1991          */
1992         efdw.total = 0;
1993         SetLastError(0xdeadbeef);
1994         ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1995         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1996         if(ret)
1997         {
1998             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1999             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2000                   ansi_charset, symbol_charset, russian_charset);
2001             ok(efdw.total > 0, "fonts enumerated: NULL\n");
2002             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2003             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2004             ok(russian_charset > 0 ||
2005                broken(russian_charset == 0), /* NT4 */
2006                "NULL family should enumerate RUSSIAN_CHARSET\n");
2007         }
2008
2009         efdw.total = 0;
2010         SetLastError(0xdeadbeef);
2011         ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2012         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2013         if(ret)
2014         {
2015             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2016             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2017                   ansi_charset, symbol_charset, russian_charset);
2018             ok(efdw.total > 0, "fonts enumerated: NULL\n");
2019             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2020             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2021             ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2022         }
2023     }
2024
2025     efd.total = 0;
2026     SetLastError(0xdeadbeef);
2027     ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2028     ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2029     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2030     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2031           ansi_charset, symbol_charset, russian_charset,
2032           *font_name ? font_name : "<empty>");
2033     if (*font_name)
2034         ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2035     else
2036         ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2037     for (i = 0; i < efd.total; i++)
2038     {
2039 /* FIXME: remove completely once Wine is fixed */
2040 if (efd.lf[i].lfCharSet != font_charset)
2041 {
2042 todo_wine
2043     ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2044 }
2045 else
2046         ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2047         ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2048            font_name, efd.lf[i].lfFaceName);
2049     }
2050
2051     memset(&lf, 0, sizeof(lf));
2052     lf.lfCharSet = ANSI_CHARSET;
2053     lstrcpy(lf.lfFaceName, font_name);
2054     efd.total = 0;
2055     SetLastError(0xdeadbeef);
2056     ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2057     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2058     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2059     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2060           ansi_charset, symbol_charset, russian_charset,
2061           *font_name ? font_name : "<empty>");
2062     if (font_charset == SYMBOL_CHARSET)
2063     {
2064         if (*font_name)
2065             ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2066         else
2067             ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2068     }
2069     else
2070     {
2071         ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2072         for (i = 0; i < efd.total; i++)
2073         {
2074             ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2075             if (*font_name)
2076                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2077                    font_name, efd.lf[i].lfFaceName);
2078         }
2079     }
2080
2081     /* DEFAULT_CHARSET should enumerate all available charsets */
2082     memset(&lf, 0, sizeof(lf));
2083     lf.lfCharSet = DEFAULT_CHARSET;
2084     lstrcpy(lf.lfFaceName, font_name);
2085     efd.total = 0;
2086     SetLastError(0xdeadbeef);
2087     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2088     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2089     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2090     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2091           ansi_charset, symbol_charset, russian_charset,
2092           *font_name ? font_name : "<empty>");
2093     ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2094     for (i = 0; i < efd.total; i++)
2095     {
2096         if (*font_name)
2097             ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2098                font_name, efd.lf[i].lfFaceName);
2099     }
2100     if (*font_name)
2101     {
2102         switch (font_charset)
2103         {
2104         case ANSI_CHARSET:
2105             ok(ansi_charset > 0,
2106                "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2107             ok(!symbol_charset,
2108                "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2109             ok(russian_charset > 0,
2110                "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2111             break;
2112         case SYMBOL_CHARSET:
2113             ok(!ansi_charset,
2114                "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2115             ok(symbol_charset,
2116                "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2117             ok(!russian_charset,
2118                "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2119             break;
2120         case DEFAULT_CHARSET:
2121             ok(ansi_charset > 0,
2122                "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2123             ok(symbol_charset > 0,
2124                "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2125             ok(russian_charset > 0,
2126                "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2127             break;
2128         }
2129     }
2130     else
2131     {
2132         ok(ansi_charset > 0,
2133            "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2134         ok(symbol_charset > 0,
2135            "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2136         ok(russian_charset > 0,
2137            "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2138     }
2139
2140     memset(&lf, 0, sizeof(lf));
2141     lf.lfCharSet = SYMBOL_CHARSET;
2142     lstrcpy(lf.lfFaceName, font_name);
2143     efd.total = 0;
2144     SetLastError(0xdeadbeef);
2145     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2146     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2147     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2148     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2149           ansi_charset, symbol_charset, russian_charset,
2150           *font_name ? font_name : "<empty>");
2151     if (*font_name && font_charset == ANSI_CHARSET)
2152         ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2153     else
2154     {
2155         ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2156         for (i = 0; i < efd.total; i++)
2157         {
2158             ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2159             if (*font_name)
2160                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2161                    font_name, efd.lf[i].lfFaceName);
2162         }
2163
2164         ok(!ansi_charset,
2165            "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2166         ok(symbol_charset > 0,
2167            "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2168         ok(!russian_charset,
2169            "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2170     }
2171
2172     ReleaseDC(0, hdc);
2173 }
2174
2175 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2176 {
2177     struct enum_font_data *efd = (struct enum_font_data *)lParam;
2178
2179     if (type != TRUETYPE_FONTTYPE) return 1;
2180
2181     if (efd->total < MAX_ENUM_FONTS)
2182         efd->lf[efd->total++] = *lf;
2183     else
2184         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2185
2186     return 1;
2187 }
2188
2189 static void test_EnumFontFamiliesEx_default_charset(void)
2190 {
2191     struct enum_font_data efd;
2192     LOGFONT gui_font, enum_font;
2193     DWORD ret;
2194     HDC hdc;
2195
2196     ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2197     ok(ret, "GetObject failed.\n");
2198     if (!ret)
2199         return;
2200
2201     efd.total = 0;
2202
2203     hdc = GetDC(0);
2204     memset(&enum_font, 0, sizeof(enum_font));
2205     lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2206     enum_font.lfCharSet = DEFAULT_CHARSET;
2207     EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2208     ReleaseDC(0, hdc);
2209
2210     if (efd.total == 0) {
2211         skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2212         return;
2213     }
2214     trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2215
2216     ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2217        "(%s) got charset %d expected %d\n",
2218        efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2219
2220     return;
2221 }
2222
2223 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2224 {
2225     HFONT hfont, hfont_prev;
2226     DWORD ret;
2227     GLYPHMETRICS gm1, gm2;
2228     LOGFONTA lf2 = *lf;
2229     WORD idx;
2230
2231     if(!pGetGlyphIndicesA)
2232         return;
2233
2234     /* negative widths are handled just as positive ones */
2235     lf2.lfWidth = -lf->lfWidth;
2236
2237     SetLastError(0xdeadbeef);
2238     hfont = CreateFontIndirectA(lf);
2239     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2240     check_font("original", lf, hfont);
2241
2242     hfont_prev = SelectObject(hdc, hfont);
2243
2244     ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2245     if (ret == GDI_ERROR || idx == 0xffff)
2246     {
2247         SelectObject(hdc, hfont_prev);
2248         DeleteObject(hfont);
2249         skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2250         return;
2251     }
2252
2253     /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2254     memset(&gm1, 0xab, sizeof(gm1));
2255     SetLastError(0xdeadbeef);
2256     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2257     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2258
2259     SelectObject(hdc, hfont_prev);
2260     DeleteObject(hfont);
2261
2262     SetLastError(0xdeadbeef);
2263     hfont = CreateFontIndirectA(&lf2);
2264     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2265     check_font("negative width", &lf2, hfont);
2266
2267     hfont_prev = SelectObject(hdc, hfont);
2268
2269     memset(&gm2, 0xbb, sizeof(gm2));
2270     SetLastError(0xdeadbeef);
2271     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2272     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2273
2274     SelectObject(hdc, hfont_prev);
2275     DeleteObject(hfont);
2276
2277     ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2278        gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2279        gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2280        gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2281        gm1.gmCellIncX == gm2.gmCellIncX &&
2282        gm1.gmCellIncY == gm2.gmCellIncY,
2283        "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2284        gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2285        gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2286        gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2287        gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2288 }
2289
2290 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2291 #include "pshpack2.h"
2292 typedef struct
2293 {
2294     USHORT version;
2295     SHORT xAvgCharWidth;
2296     USHORT usWeightClass;
2297     USHORT usWidthClass;
2298     SHORT fsType;
2299     SHORT ySubscriptXSize;
2300     SHORT ySubscriptYSize;
2301     SHORT ySubscriptXOffset;
2302     SHORT ySubscriptYOffset;
2303     SHORT ySuperscriptXSize;
2304     SHORT ySuperscriptYSize;
2305     SHORT ySuperscriptXOffset;
2306     SHORT ySuperscriptYOffset;
2307     SHORT yStrikeoutSize;
2308     SHORT yStrikeoutPosition;
2309     SHORT sFamilyClass;
2310     PANOSE panose;
2311     ULONG ulUnicodeRange1;
2312     ULONG ulUnicodeRange2;
2313     ULONG ulUnicodeRange3;
2314     ULONG ulUnicodeRange4;
2315     CHAR achVendID[4];
2316     USHORT fsSelection;
2317     USHORT usFirstCharIndex;
2318     USHORT usLastCharIndex;
2319     /* According to the Apple spec, original version didn't have the below fields,
2320      * version numbers were taken from the OpenType spec.
2321      */
2322     /* version 0 (TrueType 1.5) */
2323     USHORT sTypoAscender;
2324     USHORT sTypoDescender;
2325     USHORT sTypoLineGap;
2326     USHORT usWinAscent;
2327     USHORT usWinDescent;
2328     /* version 1 (TrueType 1.66) */
2329     ULONG ulCodePageRange1;
2330     ULONG ulCodePageRange2;
2331     /* version 2 (OpenType 1.2) */
2332     SHORT sxHeight;
2333     SHORT sCapHeight;
2334     USHORT usDefaultChar;
2335     USHORT usBreakChar;
2336     USHORT usMaxContext;
2337 } TT_OS2_V2;
2338 #include "poppack.h"
2339
2340 #ifdef WORDS_BIGENDIAN
2341 #define GET_BE_WORD(x) (x)
2342 #define GET_BE_DWORD(x) (x)
2343 #else
2344 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2345 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2346 #endif
2347
2348 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2349                     ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2350                     ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2351 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2352 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2353 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2354
2355 typedef struct
2356 {
2357     USHORT version;
2358     USHORT num_tables;
2359 } cmap_header;
2360
2361 typedef struct
2362 {
2363     USHORT plat_id;
2364     USHORT enc_id;
2365     ULONG offset;
2366 } cmap_encoding_record;
2367
2368 typedef struct
2369 {
2370     USHORT format;
2371     USHORT length;
2372     USHORT language;
2373
2374     BYTE glyph_ids[256];
2375 } cmap_format_0;
2376
2377 typedef struct
2378 {
2379     USHORT format;
2380     USHORT length;
2381     USHORT language;
2382
2383     USHORT seg_countx2;
2384     USHORT search_range;
2385     USHORT entry_selector;
2386     USHORT range_shift;
2387
2388     USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2389 /* Then follows:
2390     USHORT pad;
2391     USHORT start_count[seg_countx2 / 2];
2392     USHORT id_delta[seg_countx2 / 2];
2393     USHORT id_range_offset[seg_countx2 / 2];
2394     USHORT glyph_ids[];
2395 */
2396 } cmap_format_4;
2397
2398 typedef struct
2399 {
2400     USHORT end_count;
2401     USHORT start_count;
2402     USHORT id_delta;
2403     USHORT id_range_offset;
2404 } cmap_format_4_seg;
2405
2406 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2407 {
2408     ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2409        broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2410        "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2411        name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2412        os2->panose.bWeight, os2->panose.bProportion);
2413 }
2414
2415 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2416 {
2417     int i;
2418     cmap_format_0 *cmap = (cmap_format_0*)ptr;
2419
2420     *first = 256;
2421
2422     for(i = 0; i < 256; i++)
2423     {
2424         if(cmap->glyph_ids[i] == 0) continue;
2425         *last = i;
2426         if(*first == 256) *first = i;
2427     }
2428     if(*first == 256) return FALSE;
2429     return TRUE;
2430 }
2431
2432 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2433 {
2434     USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2435     seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2436     seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2437     seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2438     seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2439 }
2440
2441 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2442 {
2443     int i;
2444     cmap_format_4 *cmap = (cmap_format_4*)ptr;
2445     USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2446     USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2447
2448     *first = 0x10000;
2449
2450     for(i = 0; i < seg_count; i++)
2451     {
2452         DWORD code, index;
2453         cmap_format_4_seg seg;
2454
2455         get_seg4(cmap, i, &seg);
2456         for(code = seg.start_count; code <= seg.end_count; code++)
2457         {
2458             if(seg.id_range_offset == 0)
2459                 index = (seg.id_delta + code) & 0xffff;
2460             else
2461             {
2462                 index = seg.id_range_offset / 2
2463                     + code - seg.start_count
2464                     + i - seg_count;
2465
2466                 /* some fonts have broken last segment */
2467                 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2468                     index = GET_BE_WORD(glyph_ids[index]);
2469                 else
2470                 {
2471                     trace("segment %04x/%04x index %04x points to nowhere\n",
2472                           seg.start_count, seg.end_count, index);
2473                     index = 0;
2474                 }
2475                 if(index) index += seg.id_delta;
2476             }
2477             if(*first == 0x10000)
2478                 *last = *first = code;
2479             else if(index)
2480                 *last = code;
2481         }
2482     }
2483
2484     if(*first == 0x10000) return FALSE;
2485     return TRUE;
2486 }
2487
2488 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2489 {
2490     USHORT i;
2491     cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2492
2493     for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2494     {
2495         if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2496             return (BYTE *)header + GET_BE_DWORD(record->offset);
2497         record++;
2498     }
2499     return NULL;
2500 }
2501
2502 typedef enum
2503 {
2504     cmap_none,
2505     cmap_ms_unicode,
2506     cmap_ms_symbol
2507 } cmap_type;
2508
2509 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2510 {
2511     LONG size, ret;
2512     cmap_header *header;
2513     void *cmap;
2514     BOOL r = FALSE;
2515     WORD format;
2516
2517     size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2518     ok(size != GDI_ERROR, "no cmap table found\n");
2519     if(size == GDI_ERROR) return FALSE;
2520
2521     header = HeapAlloc(GetProcessHeap(), 0, size);
2522     ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2523     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2524     ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2525
2526     cmap = get_cmap(header, 3, 1);
2527     if(cmap)
2528         *cmap_type = cmap_ms_unicode;
2529     else
2530     {
2531         cmap = get_cmap(header, 3, 0);
2532         if(cmap) *cmap_type = cmap_ms_symbol;
2533     }
2534     if(!cmap)
2535     {
2536         *cmap_type = cmap_none;
2537         goto end;
2538     }
2539
2540     format = GET_BE_WORD(*(WORD *)cmap);
2541     switch(format)
2542     {
2543     case 0:
2544         r = get_first_last_from_cmap0(cmap, first, last);
2545         break;
2546     case 4:
2547         r = get_first_last_from_cmap4(cmap, first, last, size);
2548         break;
2549     default:
2550         trace("unhandled cmap format %d\n", format);
2551         break;
2552     }
2553
2554 end:
2555     HeapFree(GetProcessHeap(), 0, header);
2556     return r;
2557 }
2558
2559 #define TT_PLATFORM_MICROSOFT 3
2560 #define TT_MS_ID_UNICODE_CS 1
2561 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2562 #define TT_NAME_ID_FULL_NAME 4
2563
2564 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2565 {
2566     struct sfnt_name_header
2567     {
2568         USHORT format;
2569         USHORT number_of_record;
2570         USHORT storage_offset;
2571     } *header;
2572     struct sfnt_name
2573     {
2574         USHORT platform_id;
2575         USHORT encoding_id;
2576         USHORT language_id;
2577         USHORT name_id;
2578         USHORT length;
2579         USHORT offset;
2580     } *entry;
2581     BOOL r = FALSE;
2582     LONG size, offset, length;
2583     LONG c, ret;
2584     WCHAR *name;
2585     BYTE *data;
2586     USHORT i;
2587
2588     size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2589     ok(size != GDI_ERROR, "no name table found\n");
2590     if(size == GDI_ERROR) return FALSE;
2591
2592     data = HeapAlloc(GetProcessHeap(), 0, size);
2593     ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2594     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2595
2596     header = (void *)data;
2597     header->format = GET_BE_WORD(header->format);
2598     header->number_of_record = GET_BE_WORD(header->number_of_record);
2599     header->storage_offset = GET_BE_WORD(header->storage_offset);
2600     if (header->format != 0)
2601     {
2602         trace("got format %u\n", header->format);
2603         goto out;
2604     }
2605     if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2606     {
2607         trace("number records out of range: %d\n", header->number_of_record);
2608         goto out;
2609     }
2610     if (header->storage_offset >= size)
2611     {
2612         trace("storage_offset %u > size %u\n", header->storage_offset, size);
2613         goto out;
2614     }
2615
2616     entry = (void *)&header[1];
2617     for (i = 0; i < header->number_of_record; i++)
2618     {
2619         if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2620             GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2621             GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2622             GET_BE_WORD(entry[i].name_id) != name_id)
2623         {
2624             continue;
2625         }
2626
2627         offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2628         length = GET_BE_WORD(entry[i].length);
2629         if (offset + length > size)
2630         {
2631             trace("entry %d is out of range\n", i);
2632             break;
2633         }
2634         if (length >= out_size)
2635         {
2636             trace("buffer too small for entry %d\n", i);
2637             break;
2638         }
2639
2640         name = (WCHAR *)(data + offset);
2641         for (c = 0; c < length / 2; c++)
2642             out_buf[c] = GET_BE_WORD(name[c]);
2643         out_buf[c] = 0;
2644
2645         r = TRUE;
2646         break;
2647     }
2648
2649 out:
2650     HeapFree(GetProcessHeap(), 0, data);
2651     return r;
2652 }
2653
2654 static void test_text_metrics(const LOGFONTA *lf)
2655 {
2656     HDC hdc;
2657     HFONT hfont, hfont_old;
2658     TEXTMETRICA tmA;
2659     TT_OS2_V2 tt_os2;
2660     LONG size, ret;
2661     const char *font_name = lf->lfFaceName;
2662     DWORD cmap_first = 0, cmap_last = 0;
2663     cmap_type cmap_type;
2664     BOOL sys_lang_non_english;
2665
2666     sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2667     hdc = GetDC(0);
2668
2669     SetLastError(0xdeadbeef);
2670     hfont = CreateFontIndirectA(lf);
2671     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2672
2673     hfont_old = SelectObject(hdc, hfont);
2674
2675     size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2676     if (size == GDI_ERROR)
2677     {
2678         trace("OS/2 chunk was not found\n");
2679         goto end_of_test;
2680     }
2681     if (size > sizeof(tt_os2))
2682     {
2683         trace("got too large OS/2 chunk of size %u\n", size);
2684         size = sizeof(tt_os2);
2685     }
2686
2687     memset(&tt_os2, 0, sizeof(tt_os2));
2688     ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2689     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2690
2691     SetLastError(0xdeadbeef);
2692     ret = GetTextMetricsA(hdc, &tmA);
2693     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2694
2695     if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2696     {
2697         skip("Unable to retrieve first and last glyphs from cmap\n");
2698     }
2699     else
2700     {
2701         USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2702         USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2703         UINT os2_first_char, os2_last_char, default_char, break_char;
2704         USHORT version;
2705         TEXTMETRICW tmW;
2706
2707         version = GET_BE_WORD(tt_os2.version);
2708
2709         os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2710         os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2711         default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2712         break_char = GET_BE_WORD(tt_os2.usBreakChar);
2713
2714         trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2715               font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2716               default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2717
2718         if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2719         {
2720             expect_first_W    = 0;
2721             switch(GetACP())
2722             {
2723             case 1257:  /* Baltic */
2724                 expect_last_W = 0xf8fd;
2725                 break;
2726             default:
2727                 expect_last_W = 0xf0ff;
2728             }
2729             expect_break_W    = 0x20;
2730             expect_default_W  = expect_break_W - 1;
2731             expect_first_A    = 0x1e;
2732             expect_last_A     = min(os2_last_char - os2_first_char + 0x20, 0xff);
2733         }
2734         else
2735         {
2736             expect_first_W    = cmap_first;
2737             expect_last_W     = min(cmap_last, os2_last_char);
2738             if(os2_first_char <= 1)
2739                 expect_break_W = os2_first_char + 2;
2740             else if(os2_first_char > 0xff)
2741                 expect_break_W = 0x20;
2742             else
2743                 expect_break_W = os2_first_char;
2744             expect_default_W  = expect_break_W - 1;
2745             expect_first_A    = expect_default_W - 1;
2746             expect_last_A     = min(expect_last_W, 0xff);
2747         }
2748         expect_break_A    = expect_break_W;
2749         expect_default_A  = expect_default_W;
2750
2751         /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2752         if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2753             todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2754                          tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2755                          "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2756         else
2757             ok(tmA.tmFirstChar == expect_first_A ||
2758                tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2759                "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2760         if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2761             ok(tmA.tmLastChar == expect_last_A ||
2762                tmA.tmLastChar == 0xff /* win9x */,
2763                "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2764         else
2765            skip("tmLastChar is DBCS lead byte\n");
2766         ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2767            font_name, tmA.tmBreakChar, expect_break_A);
2768         ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2769            "A: tmDefaultChar for %s got %02x expected %02x\n",
2770            font_name, tmA.tmDefaultChar, expect_default_A);
2771
2772
2773         SetLastError(0xdeadbeef);
2774         ret = GetTextMetricsW(hdc, &tmW);
2775         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2776            "GetTextMetricsW error %u\n", GetLastError());
2777         if (ret)
2778         {
2779             /* Wine uses the os2 first char */
2780             if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2781                 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2782                              font_name, tmW.tmFirstChar, expect_first_W);
2783             else
2784                 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2785                    font_name, tmW.tmFirstChar, expect_first_W);
2786
2787             /* Wine uses the os2 last char */
2788             if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2789                 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2790                              font_name, tmW.tmLastChar, expect_last_W);
2791             else
2792                 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2793                    font_name, tmW.tmLastChar, expect_last_W);
2794             ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2795                font_name, tmW.tmBreakChar, expect_break_W);
2796             ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2797                "W: tmDefaultChar for %s got %02x expected %02x\n",
2798                font_name, tmW.tmDefaultChar, expect_default_W);
2799
2800             /* Test the aspect ratio while we have tmW */
2801             ret = GetDeviceCaps(hdc, LOGPIXELSX);
2802             ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2803                tmW.tmDigitizedAspectX, ret);
2804             ret = GetDeviceCaps(hdc, LOGPIXELSY);
2805             ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2806                tmW.tmDigitizedAspectX, ret);
2807         }
2808     }
2809
2810     /* test FF_ values */
2811     switch(tt_os2.panose.bFamilyType)
2812     {
2813     case PAN_ANY:
2814     case PAN_NO_FIT:
2815     case PAN_FAMILY_TEXT_DISPLAY:
2816     case PAN_FAMILY_PICTORIAL:
2817     default:
2818         if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2819            tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2820         {
2821             expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2822             break;
2823         }
2824         switch(tt_os2.panose.bSerifStyle)
2825         {
2826         case PAN_ANY:
2827         case PAN_NO_FIT:
2828         default:
2829             expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2830             break;
2831
2832         case PAN_SERIF_COVE:
2833         case PAN_SERIF_OBTUSE_COVE:
2834         case PAN_SERIF_SQUARE_COVE:
2835         case PAN_SERIF_OBTUSE_SQUARE_COVE:
2836         case PAN_SERIF_SQUARE:
2837         case PAN_SERIF_THIN:
2838         case PAN_SERIF_BONE:
2839         case PAN_SERIF_EXAGGERATED:
2840         case PAN_SERIF_TRIANGLE:
2841             expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2842             break;
2843
2844         case PAN_SERIF_NORMAL_SANS:
2845         case PAN_SERIF_OBTUSE_SANS:
2846         case PAN_SERIF_PERP_SANS:
2847         case PAN_SERIF_FLARED:
2848         case PAN_SERIF_ROUNDED:
2849             expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2850             break;
2851         }
2852         break;
2853
2854     case PAN_FAMILY_SCRIPT:
2855         expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2856         break;
2857
2858     case PAN_FAMILY_DECORATIVE:
2859         expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2860         break;
2861     }
2862
2863     test_negative_width(hdc, lf);
2864
2865 end_of_test:
2866     SelectObject(hdc, hfont_old);
2867     DeleteObject(hfont);
2868
2869     ReleaseDC(0, hdc);
2870 }
2871
2872 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2873 {
2874     INT *enumed = (INT *)lParam;
2875
2876     if (type == TRUETYPE_FONTTYPE)
2877     {
2878         (*enumed)++;
2879         test_text_metrics(lf);
2880     }
2881     return 1;
2882 }
2883
2884 static void test_GetTextMetrics(void)
2885 {
2886     LOGFONTA lf;
2887     HDC hdc;
2888     INT enumed;
2889
2890     /* Report only once */
2891     if(!pGetGlyphIndicesA)
2892         win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2893
2894     hdc = GetDC(0);
2895
2896     memset(&lf, 0, sizeof(lf));
2897     lf.lfCharSet = DEFAULT_CHARSET;
2898     enumed = 0;
2899     EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2900     trace("Tested metrics of %d truetype fonts\n", enumed);
2901
2902     ReleaseDC(0, hdc);
2903 }
2904
2905 static void test_nonexistent_font(void)
2906 {
2907     static const struct
2908     {
2909         const char *name;
2910         int charset;
2911     } font_subst[] =
2912     {
2913         { "Times New Roman Baltic", 186 },
2914         { "Times New Roman CE", 238 },
2915         { "Times New Roman CYR", 204 },
2916         { "Times New Roman Greek", 161 },
2917         { "Times New Roman TUR", 162 }
2918     };
2919     LOGFONTA lf;
2920     HDC hdc;
2921     HFONT hfont;
2922     CHARSETINFO csi;
2923     INT cs, expected_cs, i;
2924     char buf[LF_FACESIZE];
2925
2926     if (!is_truetype_font_installed("Arial") ||
2927         !is_truetype_font_installed("Times New Roman"))
2928     {
2929         skip("Arial or Times New Roman not installed\n");
2930         return;
2931     }
2932
2933     expected_cs = GetACP();
2934     if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2935     {
2936         skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2937         return;
2938     }
2939     expected_cs = csi.ciCharset;
2940     trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2941
2942     hdc = GetDC(0);
2943
2944     memset(&lf, 0, sizeof(lf));
2945     lf.lfHeight = 100;
2946     lf.lfWeight = FW_REGULAR;
2947     lf.lfCharSet = ANSI_CHARSET;
2948     lf.lfPitchAndFamily = FF_SWISS;
2949     strcpy(lf.lfFaceName, "Nonexistent font");
2950     hfont = CreateFontIndirectA(&lf);
2951     hfont = SelectObject(hdc, hfont);
2952     GetTextFaceA(hdc, sizeof(buf), buf);
2953     ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2954     cs = GetTextCharset(hdc);
2955     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2956     DeleteObject(SelectObject(hdc, hfont));
2957
2958     memset(&lf, 0, sizeof(lf));
2959     lf.lfHeight = -13;
2960     lf.lfWeight = FW_DONTCARE;
2961     strcpy(lf.lfFaceName, "Nonexistent font");
2962     hfont = CreateFontIndirectA(&lf);
2963     hfont = SelectObject(hdc, hfont);
2964     GetTextFaceA(hdc, sizeof(buf), buf);
2965 todo_wine /* Wine uses Arial for all substitutions */
2966     ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2967        !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2968        !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2969        "Got %s\n", buf);
2970     cs = GetTextCharset(hdc);
2971     ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2972     DeleteObject(SelectObject(hdc, hfont));
2973
2974     memset(&lf, 0, sizeof(lf));
2975     lf.lfHeight = -13;
2976     lf.lfWeight = FW_REGULAR;
2977     strcpy(lf.lfFaceName, "Nonexistent font");
2978     hfont = CreateFontIndirectA(&lf);
2979     hfont = SelectObject(hdc, hfont);
2980     GetTextFaceA(hdc, sizeof(buf), buf);
2981     ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2982        !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2983     cs = GetTextCharset(hdc);
2984     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2985     DeleteObject(SelectObject(hdc, hfont));
2986
2987     memset(&lf, 0, sizeof(lf));
2988     lf.lfHeight = -13;
2989     lf.lfWeight = FW_DONTCARE;
2990     strcpy(lf.lfFaceName, "Times New Roman");
2991     hfont = CreateFontIndirectA(&lf);
2992     hfont = SelectObject(hdc, hfont);
2993     GetTextFaceA(hdc, sizeof(buf), buf);
2994     ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2995     cs = GetTextCharset(hdc);
2996     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2997     DeleteObject(SelectObject(hdc, hfont));
2998
2999     for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3000     {
3001         memset(&lf, 0, sizeof(lf));
3002         lf.lfHeight = -13;
3003         lf.lfWeight = FW_REGULAR;
3004         strcpy(lf.lfFaceName, font_subst[i].name);
3005         hfont = CreateFontIndirectA(&lf);
3006         hfont = SelectObject(hdc, hfont);
3007         cs = GetTextCharset(hdc);
3008         if (font_subst[i].charset == expected_cs)
3009         {
3010             ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3011             GetTextFaceA(hdc, sizeof(buf), buf);
3012             ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3013         }
3014         else
3015         {
3016             ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3017             GetTextFaceA(hdc, sizeof(buf), buf);
3018             ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3019                !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3020         }
3021         DeleteObject(SelectObject(hdc, hfont));
3022
3023         memset(&lf, 0, sizeof(lf));
3024         lf.lfHeight = -13;
3025         lf.lfWeight = FW_DONTCARE;
3026         strcpy(lf.lfFaceName, font_subst[i].name);
3027         hfont = CreateFontIndirectA(&lf);
3028         hfont = SelectObject(hdc, hfont);
3029         GetTextFaceA(hdc, sizeof(buf), buf);
3030         ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3031            !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3032            !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3033            !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3034            "got %s for font %s\n", buf, font_subst[i].name);
3035         cs = GetTextCharset(hdc);
3036         ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3037         DeleteObject(SelectObject(hdc, hfont));
3038     }
3039
3040     ReleaseDC(0, hdc);
3041 }
3042
3043 static void test_GdiRealizationInfo(void)
3044 {
3045     HDC hdc;
3046     DWORD info[4];
3047     BOOL r;
3048     HFONT hfont, hfont_old;
3049     LOGFONTA lf;
3050
3051     if(!pGdiRealizationInfo)
3052     {
3053         win_skip("GdiRealizationInfo not available\n");
3054         return;
3055     }
3056
3057     hdc = GetDC(0);
3058
3059     memset(info, 0xcc, sizeof(info));
3060     r = pGdiRealizationInfo(hdc, info);
3061     ok(r != 0, "ret 0\n");
3062     ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3063     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3064
3065     if (!is_truetype_font_installed("Arial"))
3066     {
3067         skip("skipping GdiRealizationInfo with truetype font\n");
3068         goto end;
3069     }
3070
3071     memset(&lf, 0, sizeof(lf));
3072     strcpy(lf.lfFaceName, "Arial");
3073     lf.lfHeight = 20;
3074     lf.lfWeight = FW_NORMAL;
3075     hfont = CreateFontIndirectA(&lf);
3076     hfont_old = SelectObject(hdc, hfont);
3077
3078     memset(info, 0xcc, sizeof(info));
3079     r = pGdiRealizationInfo(hdc, info);
3080     ok(r != 0, "ret 0\n");
3081     ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3082     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3083
3084     DeleteObject(SelectObject(hdc, hfont_old));
3085
3086  end:
3087     ReleaseDC(0, hdc);
3088 }
3089
3090 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3091    the nul in the count of characters copied when the face name buffer is not
3092    NULL, whereas it does if the buffer is NULL.  Further, the Unicode version
3093    always includes it.  */
3094 static void test_GetTextFace(void)
3095 {
3096     static const char faceA[] = "Tahoma";
3097     static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3098     LOGFONTA fA = {0};
3099     LOGFONTW fW = {0};
3100     char bufA[LF_FACESIZE];
3101     WCHAR bufW[LF_FACESIZE];
3102     HFONT f, g;
3103     HDC dc;
3104     int n;
3105
3106     if(!is_font_installed("Tahoma"))
3107     {
3108         skip("Tahoma is not installed so skipping this test\n");
3109         return;
3110     }
3111
3112     /* 'A' case.  */
3113     memcpy(fA.lfFaceName, faceA, sizeof faceA);
3114     f = CreateFontIndirectA(&fA);
3115     ok(f != NULL, "CreateFontIndirectA failed\n");
3116
3117     dc = GetDC(NULL);
3118     g = SelectObject(dc, f);
3119     n = GetTextFaceA(dc, sizeof bufA, bufA);
3120     ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3121     ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3122
3123     /* Play with the count arg.  */
3124     bufA[0] = 'x';
3125     n = GetTextFaceA(dc, 0, bufA);
3126     ok(n == 0, "GetTextFaceA returned %d\n", n);
3127     ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3128
3129     bufA[0] = 'x';
3130     n = GetTextFaceA(dc, 1, bufA);
3131     ok(n == 0, "GetTextFaceA returned %d\n", n);
3132     ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3133
3134     bufA[0] = 'x'; bufA[1] = 'y';
3135     n = GetTextFaceA(dc, 2, bufA);
3136     ok(n == 1, "GetTextFaceA returned %d\n", n);
3137     ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3138
3139     n = GetTextFaceA(dc, 0, NULL);
3140     ok(n == sizeof faceA ||
3141        broken(n == 0), /* win98, winMe */
3142        "GetTextFaceA returned %d\n", n);
3143
3144     DeleteObject(SelectObject(dc, g));
3145     ReleaseDC(NULL, dc);
3146
3147     /* 'W' case.  */
3148     memcpy(fW.lfFaceName, faceW, sizeof faceW);
3149     SetLastError(0xdeadbeef);
3150     f = CreateFontIndirectW(&fW);
3151     if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3152     {
3153         win_skip("CreateFontIndirectW is not implemented\n");
3154         return;
3155     }
3156     ok(f != NULL, "CreateFontIndirectW failed\n");
3157
3158     dc = GetDC(NULL);
3159     g = SelectObject(dc, f);
3160     n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3161     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3162     ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3163
3164     /* Play with the count arg.  */
3165     bufW[0] = 'x';
3166     n = GetTextFaceW(dc, 0, bufW);
3167     ok(n == 0, "GetTextFaceW returned %d\n", n);
3168     ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3169
3170     bufW[0] = 'x';
3171     n = GetTextFaceW(dc, 1, bufW);
3172     ok(n == 1, "GetTextFaceW returned %d\n", n);
3173     ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3174
3175     bufW[0] = 'x'; bufW[1] = 'y';
3176     n = GetTextFaceW(dc, 2, bufW);
3177     ok(n == 2, "GetTextFaceW returned %d\n", n);
3178     ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3179
3180     n = GetTextFaceW(dc, 0, NULL);
3181     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3182
3183     DeleteObject(SelectObject(dc, g));
3184     ReleaseDC(NULL, dc);
3185 }
3186
3187 static void test_orientation(void)
3188 {
3189     static const char test_str[11] = "Test String";
3190     HDC hdc;
3191     LOGFONTA lf;
3192     HFONT hfont, old_hfont;
3193     SIZE size;
3194
3195     if (!is_truetype_font_installed("Arial"))
3196     {
3197         skip("Arial is not installed\n");
3198         return;
3199     }
3200
3201     hdc = CreateCompatibleDC(0);
3202     memset(&lf, 0, sizeof(lf));
3203     lstrcpyA(lf.lfFaceName, "Arial");
3204     lf.lfHeight = 72;
3205     lf.lfOrientation = lf.lfEscapement = 900;
3206     hfont = create_font("orientation", &lf);
3207     old_hfont = SelectObject(hdc, hfont);
3208     ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3209     ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3210     ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3211     SelectObject(hdc, old_hfont);
3212     DeleteObject(hfont);
3213     DeleteDC(hdc);
3214 }
3215
3216 static void test_oemcharset(void)
3217 {
3218     HDC hdc;
3219     LOGFONTA lf, clf;
3220     HFONT hfont, old_hfont;
3221     int charset;
3222
3223     hdc = CreateCompatibleDC(0);
3224     ZeroMemory(&lf, sizeof(lf));
3225     lf.lfHeight = 12;
3226     lf.lfCharSet = OEM_CHARSET;
3227     lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3228     lstrcpyA(lf.lfFaceName, "Terminal");
3229     hfont = CreateFontIndirectA(&lf);
3230     old_hfont = SelectObject(hdc, hfont);
3231     charset = GetTextCharset(hdc);
3232 todo_wine
3233     ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3234     hfont = SelectObject(hdc, old_hfont);
3235     GetObjectA(hfont, sizeof(clf), &clf);
3236     ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3237     ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3238     ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3239     ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3240     DeleteObject(hfont);
3241     DeleteDC(hdc);
3242 }
3243
3244 static void test_GetGlyphOutline(void)
3245 {
3246     HDC hdc;
3247     GLYPHMETRICS gm, gm2;
3248     LOGFONTA lf;
3249     HFONT hfont, old_hfont;
3250     INT ret, ret2;
3251     static const struct
3252     {
3253         UINT cs;
3254         UINT a;
3255         UINT w;
3256     } c[] =
3257     {
3258         {ANSI_CHARSET, 0x30, 0x30},
3259         {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3260         {HANGEUL_CHARSET, 0x8141, 0xac02},
3261         {JOHAB_CHARSET, 0x8446, 0x3135},
3262         {GB2312_CHARSET, 0x8141, 0x4e04},
3263         {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3264     };
3265     UINT i;
3266
3267     if (!is_truetype_font_installed("Tahoma"))
3268     {
3269         skip("Tahoma is not installed\n");
3270         return;
3271     }
3272
3273     hdc = CreateCompatibleDC(0);
3274     memset(&lf, 0, sizeof(lf));
3275     lf.lfHeight = 72;
3276     lstrcpyA(lf.lfFaceName, "Tahoma");
3277     SetLastError(0xdeadbeef);
3278     hfont = CreateFontIndirectA(&lf);
3279     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3280     old_hfont = SelectObject(hdc, hfont);
3281
3282     memset(&gm, 0, sizeof(gm));
3283     SetLastError(0xdeadbeef);
3284     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3285     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3286
3287     memset(&gm, 0, sizeof(gm));
3288     SetLastError(0xdeadbeef);
3289     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3290     ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3291     ok(GetLastError() == 0xdeadbeef ||
3292        GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3293        "expected 0xdeadbeef, got %u\n", GetLastError());
3294
3295     memset(&gm, 0, sizeof(gm));
3296     SetLastError(0xdeadbeef);
3297     ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3298     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3299         ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3300
3301     memset(&gm, 0, sizeof(gm));
3302     SetLastError(0xdeadbeef);
3303     ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3304     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3305     {
3306        ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3307        ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3308     }
3309
3310     /* test for needed buffer size request on space char */
3311     memset(&gm, 0, sizeof(gm));
3312     SetLastError(0xdeadbeef);
3313     ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3314     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3315         ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3316
3317     /* requesting buffer size for space char + error */
3318     memset(&gm, 0, sizeof(gm));
3319     SetLastError(0xdeadbeef);
3320     ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3321     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3322     {
3323        ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3324        ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3325     }
3326
3327     SelectObject(hdc, old_hfont);
3328     DeleteObject(hfont);
3329
3330     for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3331     {
3332         lf.lfFaceName[0] = '\0';
3333         lf.lfCharSet = c[i].cs;
3334         lf.lfPitchAndFamily = 0;
3335         if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3336         {
3337             skip("TrueType font for charset %u is not installed\n", c[i].cs);
3338             continue;
3339         }
3340
3341         old_hfont = SelectObject(hdc, hfont);
3342
3343         /* expected to ignore superfluous bytes (sigle-byte character) */
3344         ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3345         ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3346         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3347
3348         ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3349         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3350            "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3351
3352         /* expected to ignore superfluous bytes (double-byte character) */
3353         ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3354         ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3355         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3356            "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3357
3358         /* expected to match wide-char version results */
3359         ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3360         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3361
3362         hfont = SelectObject(hdc, old_hfont);
3363         DeleteObject(hfont);
3364     }
3365
3366     DeleteDC(hdc);
3367 }
3368
3369 /* bug #9995: there is a limit to the character width that can be specified */
3370 static void test_GetTextMetrics2(const char *fontname, int font_height)
3371 {
3372     HFONT of, hf;
3373     HDC hdc;
3374     TEXTMETRICA tm;
3375     BOOL ret;
3376     int ave_width, height, width, ratio, scale;
3377
3378     if (!is_truetype_font_installed( fontname)) {
3379         skip("%s is not installed\n", fontname);
3380         return;
3381     }
3382     hdc = CreateCompatibleDC(0);
3383     ok( hdc != NULL, "CreateCompatibleDC failed\n");
3384     /* select width = 0 */
3385     hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3386             DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3387             DEFAULT_QUALITY, VARIABLE_PITCH,
3388             fontname);
3389     ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3390     of = SelectObject( hdc, hf);
3391     ret = GetTextMetricsA( hdc, &tm);
3392     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3393     height = tm.tmHeight;
3394     ave_width = tm.tmAveCharWidth;
3395     SelectObject( hdc, of);
3396     DeleteObject( hf);
3397
3398     trace("height %d, ave width %d\n", height, ave_width);
3399
3400     for (width = ave_width * 2; /* nothing*/; width += ave_width)
3401     {
3402         hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3403                         DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3404                         DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3405         ok(hf != 0, "CreateFont failed\n");
3406         of = SelectObject(hdc, hf);
3407         ret = GetTextMetrics(hdc, &tm);
3408         ok(ret, "GetTextMetrics error %u\n", GetLastError());
3409         SelectObject(hdc, of);
3410         DeleteObject(hf);
3411
3412         if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3413             break;
3414     }
3415
3416     DeleteDC(hdc);
3417
3418     ratio = width / height;
3419     scale = width / ave_width;
3420
3421     trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3422           width, height, ratio, width, ave_width, scale);
3423
3424     ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3425 }
3426
3427 static void test_CreateFontIndirect(void)
3428 {
3429     LOGFONTA lf, getobj_lf;
3430     int ret, i;
3431     HFONT hfont;
3432     char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3433
3434     memset(&lf, 0, sizeof(lf));
3435     lf.lfCharSet = ANSI_CHARSET;
3436     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3437     lf.lfHeight = 16;
3438     lf.lfWidth = 16;
3439     lf.lfQuality = DEFAULT_QUALITY;
3440     lf.lfItalic = FALSE;
3441     lf.lfWeight = FW_DONTCARE;
3442
3443     for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3444     {
3445         lstrcpyA(lf.lfFaceName, TestName[i]);
3446         hfont = CreateFontIndirectA(&lf);
3447         ok(hfont != 0, "CreateFontIndirectA failed\n");
3448         SetLastError(0xdeadbeef);
3449         ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3450         ok(ret, "GetObject failed: %d\n", GetLastError());
3451         ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3452         ok(lf.lfWeight == getobj_lf.lfWeight ||
3453            broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3454            "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3455         ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3456            broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3457            "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3458         DeleteObject(hfont);
3459     }
3460 }
3461
3462 static void test_CreateFontIndirectEx(void)
3463 {
3464     ENUMLOGFONTEXDVA lfex;
3465     HFONT hfont;
3466
3467     if (!pCreateFontIndirectExA)
3468     {
3469         win_skip("CreateFontIndirectExA is not available\n");
3470         return;
3471     }
3472
3473     if (!is_truetype_font_installed("Arial"))
3474     {
3475         skip("Arial is not installed\n");
3476         return;
3477     }
3478
3479     SetLastError(0xdeadbeef);
3480     hfont = pCreateFontIndirectExA(NULL);
3481     ok(hfont == NULL, "got %p\n", hfont);
3482     ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3483
3484     memset(&lfex, 0, sizeof(lfex));
3485     lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3486     hfont = pCreateFontIndirectExA(&lfex);
3487     ok(hfont != 0, "CreateFontIndirectEx failed\n");
3488     if (hfont)
3489         check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3490     DeleteObject(hfont);
3491 }
3492
3493 static void free_font(void *font)
3494 {
3495     UnmapViewOfFile(font);
3496 }
3497
3498 static void *load_font(const char *font_name, DWORD *font_size)
3499 {
3500     char file_name[MAX_PATH];
3501     HANDLE file, mapping;
3502     void *font;
3503
3504     if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3505     strcat(file_name, "\\fonts\\");
3506     strcat(file_name, font_name);
3507
3508     file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3509     if (file == INVALID_HANDLE_VALUE) return NULL;
3510
3511     *font_size = GetFileSize(file, NULL);
3512
3513     mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3514     if (!mapping)
3515     {
3516         CloseHandle(file);
3517         return NULL;
3518     }
3519
3520     font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3521
3522     CloseHandle(file);
3523     CloseHandle(mapping);
3524     return font;
3525 }
3526
3527 static void test_AddFontMemResource(void)
3528 {
3529     void *font;
3530     DWORD font_size, num_fonts;
3531     HANDLE ret;
3532     BOOL bRet;
3533
3534     if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3535     {
3536         win_skip("AddFontMemResourceEx is not available on this platform\n");
3537         return;
3538     }
3539
3540     font = load_font("sserife.fon", &font_size);
3541     if (!font)
3542     {
3543         skip("Unable to locate and load font sserife.fon\n");
3544         return;
3545     }
3546
3547     SetLastError(0xdeadbeef);
3548     ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3549     ok(!ret, "AddFontMemResourceEx should fail\n");
3550     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3551        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3552        GetLastError());
3553
3554     SetLastError(0xdeadbeef);
3555     ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3556     ok(!ret, "AddFontMemResourceEx should fail\n");
3557     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3558        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3559        GetLastError());
3560
3561     SetLastError(0xdeadbeef);
3562     ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3563     ok(!ret, "AddFontMemResourceEx should fail\n");
3564     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3565        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3566        GetLastError());
3567
3568     SetLastError(0xdeadbeef);
3569     ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3570     ok(!ret, "AddFontMemResourceEx should fail\n");
3571     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3572        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3573        GetLastError());
3574
3575     SetLastError(0xdeadbeef);
3576     ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3577     ok(!ret, "AddFontMemResourceEx should fail\n");
3578     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3579        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3580        GetLastError());
3581
3582     SetLastError(0xdeadbeef);
3583     ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3584     ok(!ret, "AddFontMemResourceEx should fail\n");
3585     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3586        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3587        GetLastError());
3588
3589     num_fonts = 0xdeadbeef;
3590     SetLastError(0xdeadbeef);
3591     ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3592     ok(!ret, "AddFontMemResourceEx should fail\n");
3593     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3594        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3595        GetLastError());
3596     ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3597
3598     if (0) /* hangs under windows 2000 */
3599     {
3600         num_fonts = 0xdeadbeef;
3601         SetLastError(0xdeadbeef);
3602         ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3603         ok(!ret, "AddFontMemResourceEx should fail\n");
3604         ok(GetLastError() == 0xdeadbeef,
3605            "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3606            GetLastError());
3607         ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3608     }
3609
3610     num_fonts = 0xdeadbeef;
3611     SetLastError(0xdeadbeef);
3612     ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3613     ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3614     ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3615     ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3616
3617     free_font(font);
3618
3619     SetLastError(0xdeadbeef);
3620     bRet = pRemoveFontMemResourceEx(ret);
3621     ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3622
3623     /* test invalid pointer to number of loaded fonts */
3624     font = load_font("sserife.fon", &font_size);
3625     ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3626
3627     SetLastError(0xdeadbeef);
3628     ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3629     ok(!ret, "AddFontMemResourceEx should fail\n");
3630     ok(GetLastError() == 0xdeadbeef,
3631        "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3632        GetLastError());
3633
3634     SetLastError(0xdeadbeef);
3635     ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3636     ok(!ret, "AddFontMemResourceEx should fail\n");
3637     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3638        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3639        GetLastError());
3640
3641     free_font(font);
3642 }
3643
3644 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3645 {
3646     LOGFONT *lf;
3647
3648     if (type != TRUETYPE_FONTTYPE) return 1;
3649
3650     ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3651
3652     lf = (LOGFONT *)lparam;
3653     *lf = *elf;
3654     return 0;
3655 }
3656
3657 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3658 {
3659     int ret;
3660     LOGFONT *lf;
3661
3662     if (type != TRUETYPE_FONTTYPE) return 1;
3663
3664     lf = (LOGFONT *)lparam;
3665     ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3666     if(ret == 0)
3667     {
3668         ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3669         *lf = *elf;
3670         return 0;
3671     }
3672     return 1;
3673 }
3674
3675 static void test_EnumFonts(void)
3676 {
3677     int ret;
3678     LOGFONT lf;
3679     HDC hdc;
3680
3681     if (!is_truetype_font_installed("Arial"))
3682     {
3683         skip("Arial is not installed\n");
3684         return;
3685     }
3686
3687     /* Windows uses localized font face names, so Arial Bold won't be found */
3688     if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3689     {
3690         skip("User locale is not English, skipping the test\n");
3691         return;
3692     }
3693
3694     hdc = CreateCompatibleDC(0);
3695
3696     ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3697     ok(!ret, "font Arial is not enumerated\n");
3698     ret = strcmp(lf.lfFaceName, "Arial");
3699     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3700     ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3701
3702     lstrcpy(lf.lfFaceName, "Arial");
3703     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3704     ok(!ret, "font Arial is not enumerated\n");
3705     ret = strcmp(lf.lfFaceName, "Arial");
3706     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3707     ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3708
3709     ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3710     ok(!ret, "font Arial Bold is not enumerated\n");
3711     ret = strcmp(lf.lfFaceName, "Arial");
3712     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3713     ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3714
3715     lstrcpy(lf.lfFaceName, "Arial Bold");
3716     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3717     ok(ret, "font Arial Bold should not be enumerated\n");
3718
3719     ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3720     ok(!ret, "font Arial Bold Italic is not enumerated\n");
3721     ret = strcmp(lf.lfFaceName, "Arial");
3722     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3723     ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3724
3725     lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3726     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3727     ok(ret, "font Arial Bold Italic should not be enumerated\n");
3728
3729     ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3730     ok(ret, "font Arial Italic Bold  should not be enumerated\n");
3731
3732     lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3733     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3734     ok(ret, "font Arial Italic Bold should not be enumerated\n");
3735
3736     DeleteDC(hdc);
3737 }
3738
3739 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3740 {
3741     const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3742     const char *fullname = (const char *)lParam;
3743
3744     if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3745
3746     return 1;
3747 }
3748
3749 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3750 {
3751     HDC hdc = GetDC(0);
3752     BOOL ret = FALSE;
3753
3754     if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3755         ret = TRUE;
3756
3757     ReleaseDC(0, hdc);
3758     return ret;
3759 }
3760
3761 static void test_fullname(void)
3762 {
3763     static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3764     char buf[LF_FULLFACESIZE];
3765     HFONT hfont, of;
3766     LOGFONTA lf;
3767     HDC hdc;
3768     int i;
3769
3770     hdc = CreateCompatibleDC(0);
3771     ok(hdc != NULL, "CreateCompatibleDC failed\n");
3772
3773     memset(&lf, 0, sizeof(lf));
3774     lf.lfCharSet = ANSI_CHARSET;
3775     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3776     lf.lfHeight = 16;
3777     lf.lfWidth = 16;
3778     lf.lfQuality = DEFAULT_QUALITY;
3779     lf.lfItalic = FALSE;
3780     lf.lfWeight = FW_DONTCARE;
3781
3782     for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3783     {
3784         if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3785         {
3786             skip("%s is not installed\n", TestName[i]);
3787             continue;
3788         }
3789
3790         lstrcpyA(lf.lfFaceName, TestName[i]);
3791         hfont = CreateFontIndirectA(&lf);
3792         ok(hfont != 0, "CreateFontIndirectA failed\n");
3793
3794         of = SelectObject(hdc, hfont);
3795         buf[0] = 0;
3796         ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3797            "face full name could not be read\n");
3798         ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3799         SelectObject(hdc, of);
3800         DeleteObject(hfont);
3801     }
3802     DeleteDC(hdc);
3803 }
3804
3805 static BOOL write_ttf_file(char *tmp_name)
3806 {
3807     char tmp_path[MAX_PATH];
3808     HRSRC rsrc;
3809     void *rsrc_data;
3810     DWORD rsrc_size;
3811     HANDLE hfile;
3812     BOOL ret;
3813
3814     SetLastError(0xdeadbeef);
3815     rsrc = FindResource(GetModuleHandle(0), "wine_test.ttf", RT_RCDATA);
3816     ok(rsrc != 0, "FindResource error %d\n", GetLastError());
3817     if (!rsrc) return FALSE;
3818     SetLastError(0xdeadbeef);
3819     rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
3820     ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
3821     if (!rsrc_data) return FALSE;
3822     SetLastError(0xdeadbeef);
3823     rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
3824     ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
3825     if (!rsrc_size) return FALSE;
3826
3827     SetLastError(0xdeadbeef);
3828     ret = GetTempPath(MAX_PATH, tmp_path);
3829     ok(ret, "GetTempPath() error %d\n", GetLastError());
3830     SetLastError(0xdeadbeef);
3831     ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
3832     ok(ret, "GetTempFileName() error %d\n", GetLastError());
3833
3834     SetLastError(0xdeadbeef);
3835     hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
3836     ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
3837     if (hfile == INVALID_HANDLE_VALUE) return FALSE;
3838
3839     SetLastError(0xdeadbeef);
3840     ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
3841     ok(ret, "WriteFile() error %d\n", GetLastError());
3842
3843     CloseHandle(hfile);
3844     return ret;
3845 }
3846
3847 static void test_CreateScalableFontResource(void)
3848 {
3849     char ttf_name[MAX_PATH];
3850     char tmp_path[MAX_PATH];
3851     char fot_name[MAX_PATH];
3852     char *file_part;
3853     DWORD ret;
3854
3855     if (!pAddFontResourceExA || !pRemoveFontResourceExA)
3856     {
3857         win_skip("AddFontResourceExA is not available on this platform\n");
3858         return;
3859     }
3860
3861     if (!write_ttf_file(ttf_name))
3862     {
3863         skip("Failed to create ttf file for testing\n");
3864         return;
3865     }
3866
3867     trace("created %s\n", ttf_name);
3868
3869     ret = is_truetype_font_installed("wine_test");
3870     ok(!ret, "font wine_test should not be enumerated\n");
3871
3872     ret = GetTempPath(MAX_PATH, tmp_path);
3873     ok(ret, "GetTempPath() error %d\n", GetLastError());
3874     ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
3875     ok(ret, "GetTempFileName() error %d\n", GetLastError());
3876
3877     ret = GetFileAttributes(fot_name);
3878     ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
3879
3880     SetLastError(0xdeadbeef);
3881     ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3882     ok(!ret, "CreateScalableFontResource() should fail\n");
3883     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3884
3885     SetLastError(0xdeadbeef);
3886     ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
3887     ok(!ret, "CreateScalableFontResource() should fail\n");
3888     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3889
3890     file_part = strrchr(ttf_name, '\\');
3891     SetLastError(0xdeadbeef);
3892     ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
3893     ok(!ret, "CreateScalableFontResource() should fail\n");
3894     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3895
3896     SetLastError(0xdeadbeef);
3897     ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
3898     ok(!ret, "CreateScalableFontResource() should fail\n");
3899 todo_wine
3900     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3901
3902     SetLastError(0xdeadbeef);
3903     ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
3904     ok(!ret, "CreateScalableFontResource() should fail\n");
3905 todo_wine
3906     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3907
3908     ret = DeleteFile(fot_name);
3909     ok(ret, "DeleteFile() error %d\n", GetLastError());
3910
3911     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3912 todo_wine
3913     ok(!ret, "RemoveFontResourceEx() should fail\n");
3914
3915     /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3916     if (ret) return;
3917
3918     /* test public font resource */
3919     SetLastError(0xdeadbeef);
3920     ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3921     ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3922
3923     ret = is_truetype_font_installed("wine_test");
3924     ok(!ret, "font wine_test should not be enumerated\n");
3925
3926     SetLastError(0xdeadbeef);
3927     ret = pAddFontResourceExA(fot_name, 0, 0);
3928     ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3929
3930     ret = is_truetype_font_installed("wine_test");
3931     ok(ret, "font wine_test should be enumerated\n");
3932
3933     ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3934     ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
3935
3936     SetLastError(0xdeadbeef);
3937     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3938 todo_wine
3939     ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3940
3941     ret = is_truetype_font_installed("wine_test");
3942 todo_wine
3943     ok(!ret, "font wine_test should not be enumerated\n");
3944
3945     /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
3946     if (ret)
3947     {
3948         /* remove once RemoveFontResource is implemented */
3949         DeleteFile(fot_name);
3950         DeleteFile(ttf_name);
3951         return;
3952     }
3953
3954     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3955     ok(!ret, "RemoveFontResourceEx() should fail\n");
3956
3957     DeleteFile(fot_name);
3958
3959     /* test hidden font resource */
3960     SetLastError(0xdeadbeef);
3961     ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
3962     ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3963
3964     ret = is_truetype_font_installed("wine_test");
3965     ok(!ret, "font wine_test should not be enumerated\n");
3966
3967     SetLastError(0xdeadbeef);
3968     ret = pAddFontResourceExA(fot_name, 0, 0);
3969     ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3970
3971     ret = is_truetype_font_installed("wine_test");
3972     ok(!ret, "font wine_test should not be enumerated\n");
3973
3974     /* XP allows removing a private font added with 0 flags */
3975     SetLastError(0xdeadbeef);
3976     ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3977     ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3978
3979     ret = is_truetype_font_installed("wine_test");
3980     ok(!ret, "font wine_test should not be enumerated\n");
3981
3982     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3983     ok(!ret, "RemoveFontResourceEx() should fail\n");
3984
3985     DeleteFile(fot_name);
3986     DeleteFile(ttf_name);
3987 }
3988
3989 START_TEST(font)
3990 {
3991     init();
3992
3993     test_logfont();
3994     test_bitmap_font();
3995     test_outline_font();
3996     test_bitmap_font_metrics();
3997     test_GdiGetCharDimensions();
3998     test_GetCharABCWidths();
3999     test_text_extents();
4000     test_GetGlyphIndices();
4001     test_GetKerningPairs();
4002     test_GetOutlineTextMetrics();
4003     test_SetTextJustification();
4004     test_font_charset();
4005     test_GetFontUnicodeRanges();
4006     test_nonexistent_font();
4007     test_orientation();
4008     test_height_selection();
4009     test_AddFontMemResource();
4010     test_EnumFonts();
4011
4012     /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4013      * I'd like to avoid them in this test.
4014      */
4015     test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4016     test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4017     if (is_truetype_font_installed("Arial Black") &&
4018         (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4019     {
4020         test_EnumFontFamilies("", ANSI_CHARSET);
4021         test_EnumFontFamilies("", SYMBOL_CHARSET);
4022         test_EnumFontFamilies("", DEFAULT_CHARSET);
4023     }
4024     else
4025         skip("Arial Black or Symbol/Wingdings is not installed\n");
4026     test_EnumFontFamiliesEx_default_charset();
4027     test_GetTextMetrics();
4028     test_GdiRealizationInfo();
4029     test_GetTextFace();
4030     test_GetGlyphOutline();
4031     test_GetTextMetrics2("Tahoma", -11);
4032     test_GetTextMetrics2("Tahoma", -55);
4033     test_GetTextMetrics2("Tahoma", -110);
4034     test_GetTextMetrics2("Arial", -11);
4035     test_GetTextMetrics2("Arial", -55);
4036     test_GetTextMetrics2("Arial", -110);
4037     test_CreateFontIndirect();
4038     test_CreateFontIndirectEx();
4039     test_oemcharset();
4040     test_fullname();
4041
4042     /* CreateScalableFontResource should be last test until RemoveFontResource
4043      * is properly implemented.
4044      */
4045     test_CreateScalableFontResource();
4046 }