mshtml: Implement IHTMLDOMNode replaceChild.
[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     BOOL ret;
1058
1059     memset(&lf, 0, sizeof(lf));
1060     strcpy(lf.lfFaceName, "Arial");
1061     lf.lfHeight = 20;
1062
1063     hfont = CreateFontIndirectA(&lf);
1064     hdc = GetDC(0);
1065     hfont = SelectObject(hdc, hfont);
1066     GetTextMetricsA(hdc, &tm);
1067     GetTextExtentPointA(hdc, "o", 1, &sz);
1068     ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
1069
1070     SetLastError(0xdeadbeef);
1071     GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
1072     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1073     {
1074         win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1075         hfont = SelectObject(hdc, hfont);
1076         DeleteObject(hfont);
1077         ReleaseDC(0, hdc);
1078         return;
1079     }
1080
1081     len = lstrlenW(wt);
1082     extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
1083     extents[0] = 1;         /* So that the increasing sequence test will fail
1084                                if the extents array is untouched.  */
1085     GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
1086     GetTextExtentPointW(hdc, wt, len, &sz2);
1087     ok(sz1.cy == sz2.cy,
1088        "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
1089     /* Because of the '\n' in the string GetTextExtentExPoint and
1090        GetTextExtentPoint return different widths under Win2k, but
1091        under WinXP they return the same width.  So we don't test that
1092        here. */
1093
1094     for (i = 1; i < len; ++i)
1095         ok(extents[i-1] <= extents[i],
1096            "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1097            i);
1098     ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
1099     ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
1100     ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1101     GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
1102     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
1103     ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1104     GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
1105     ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1106     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
1107     ok(extents[0] == extents[2] && extents[1] == extents[3],
1108        "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1109     GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
1110     ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
1111        "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1112     HeapFree(GetProcessHeap(), 0, extents);
1113
1114     /* extents functions fail with -ve counts (the interesting case being -1) */
1115     ret = GetTextExtentPointA(hdc, "o", -1, &sz);
1116     ok(ret == FALSE, "got %d\n", ret);
1117     ret = GetTextExtentExPointA(hdc, "o", -1, 0, NULL, NULL, &sz);
1118     ok(ret == FALSE, "got %d\n", ret);
1119     ret = GetTextExtentExPointW(hdc, wt, -1, 0, NULL, NULL, &sz1);
1120     ok(ret == FALSE, "got %d\n", ret);
1121
1122     hfont = SelectObject(hdc, hfont);
1123     DeleteObject(hfont);
1124     ReleaseDC(NULL, hdc);
1125 }
1126
1127 static void test_GetGlyphIndices(void)
1128 {
1129     HDC      hdc;
1130     HFONT    hfont;
1131     DWORD    charcount;
1132     LOGFONTA lf;
1133     DWORD    flags = 0;
1134     WCHAR    testtext[] = {'T','e','s','t',0xffff,0};
1135     WORD     glyphs[(sizeof(testtext)/2)-1];
1136     TEXTMETRIC textm;
1137     HFONT hOldFont;
1138
1139     if (!pGetGlyphIndicesW) {
1140         win_skip("GetGlyphIndicesW not available on platform\n");
1141         return;
1142     }
1143
1144     hdc = GetDC(0);
1145
1146     memset(&lf, 0, sizeof(lf));
1147     strcpy(lf.lfFaceName, "System");
1148     lf.lfHeight = 16;
1149     lf.lfCharSet = ANSI_CHARSET;
1150
1151     hfont = CreateFontIndirectA(&lf);
1152     ok(hfont != 0, "CreateFontIndirectEx failed\n");
1153     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1154     if (textm.tmCharSet == ANSI_CHARSET)
1155     {
1156         flags |= GGI_MARK_NONEXISTING_GLYPHS;
1157         charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1158         ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1159         ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1160         flags = 0;
1161         charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1162         ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1163         ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1164                         textm.tmDefaultChar, glyphs[4]);
1165     }
1166     else
1167         /* FIXME: Write tests for non-ANSI charsets. */
1168         skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1169
1170     if(!is_font_installed("Tahoma"))
1171     {
1172         skip("Tahoma is not installed so skipping this test\n");
1173         return;
1174     }
1175     memset(&lf, 0, sizeof(lf));
1176     strcpy(lf.lfFaceName, "Tahoma");
1177     lf.lfHeight = 20;
1178
1179     hfont = CreateFontIndirectA(&lf);
1180     hOldFont = SelectObject(hdc, hfont);
1181     ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1182     flags |= GGI_MARK_NONEXISTING_GLYPHS;
1183     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1184     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1185     ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1186     flags = 0;
1187     testtext[0] = textm.tmDefaultChar;
1188     charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1189     ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1190     ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1191     ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1192     DeleteObject(SelectObject(hdc, hOldFont));
1193 }
1194
1195 static void test_GetKerningPairs(void)
1196 {
1197     static const struct kerning_data
1198     {
1199         const char face_name[LF_FACESIZE];
1200         LONG height;
1201         /* some interesting fields from OUTLINETEXTMETRIC */
1202         LONG tmHeight, tmAscent, tmDescent;
1203         UINT otmEMSquare;
1204         INT  otmAscent;
1205         INT  otmDescent;
1206         UINT otmLineGap;
1207         UINT otmsCapEmHeight;
1208         UINT otmsXHeight;
1209         INT  otmMacAscent;
1210         INT  otmMacDescent;
1211         UINT otmMacLineGap;
1212         UINT otmusMinimumPPEM;
1213         /* small subset of kerning pairs to test */
1214         DWORD total_kern_pairs;
1215         const KERNINGPAIR kern_pair[26];
1216     } kd[] =
1217     {
1218         {"Arial", 12, 12, 9, 3,
1219                   2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1220                   26,
1221             {
1222                 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1223                 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1224                 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1225                 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1226                 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1227                 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1228                 {933,970,+1},{933,972,-1}
1229                 }
1230         },
1231         {"Arial", -34, 39, 32, 7,
1232                   2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1233                   26,
1234             {
1235                 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1236                 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1237                 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1238                 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1239                 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1240                 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1241                 {933,970,+2},{933,972,-3}
1242             }
1243         },
1244         { "Arial", 120, 120, 97, 23,
1245                    2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1246                    26,
1247             {
1248                 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1249                 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1250                 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1251                 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1252                 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1253                 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1254                 {933,970,+6},{933,972,-10}
1255             }
1256         },
1257 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1258         { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1259                    2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1260                    26,
1261             {
1262                 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1263                 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1264                 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1265                 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1266                 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1267                 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1268                 {933,970,+54},{933,972,-83}
1269             }
1270         }
1271 #endif
1272     };
1273     LOGFONT lf;
1274     HFONT hfont, hfont_old;
1275     KERNINGPAIR *kern_pair;
1276     HDC hdc;
1277     DWORD total_kern_pairs, ret, i, n, matches;
1278
1279     hdc = GetDC(0);
1280
1281     /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1282      * which may render this test unusable, so we're trying to avoid that.
1283      */
1284     SetLastError(0xdeadbeef);
1285     GetKerningPairsW(hdc, 0, NULL);
1286     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1287     {
1288         win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1289         ReleaseDC(0, hdc);
1290         return;
1291     }
1292
1293     for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1294     {
1295         OUTLINETEXTMETRICW otm;
1296         UINT uiRet;
1297
1298         if (!is_font_installed(kd[i].face_name))
1299         {
1300             trace("%s is not installed so skipping this test\n", kd[i].face_name);
1301             continue;
1302         }
1303
1304         trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1305
1306         memset(&lf, 0, sizeof(lf));
1307         strcpy(lf.lfFaceName, kd[i].face_name);
1308         lf.lfHeight = kd[i].height;
1309         hfont = CreateFontIndirect(&lf);
1310         assert(hfont != 0);
1311
1312         hfont_old = SelectObject(hdc, hfont);
1313
1314         SetLastError(0xdeadbeef);
1315         otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1316         uiRet = GetOutlineTextMetricsW(hdc, sizeof(otm), &otm);
1317         ok(uiRet == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1318
1319         ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1320            kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1321         ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1322            kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1323         ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1324            kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1325
1326         ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1327            kd[i].otmEMSquare, otm.otmEMSquare);
1328         ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1329            kd[i].otmAscent, otm.otmAscent);
1330         ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1331            kd[i].otmDescent, otm.otmDescent);
1332         ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1333            kd[i].otmLineGap, otm.otmLineGap);
1334         ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1335            kd[i].otmMacDescent, otm.otmMacDescent);
1336         ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1337            kd[i].otmMacAscent, otm.otmMacAscent);
1338 todo_wine {
1339         ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1340            kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1341         ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1342            kd[i].otmsXHeight, otm.otmsXHeight);
1343         /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1344         if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1345            kd[i].otmMacLineGap, otm.otmMacLineGap);
1346         ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1347            kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1348 }
1349
1350         total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1351         trace("total_kern_pairs %u\n", total_kern_pairs);
1352         kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1353
1354         /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1355          * passes on XP.
1356          */
1357         SetLastError(0xdeadbeef);
1358         ret = GetKerningPairsW(hdc, 0, kern_pair);
1359         ok(GetLastError() == ERROR_INVALID_PARAMETER,
1360            "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1361         ok(ret == 0, "got %u, expected 0\n", ret);
1362
1363         ret = GetKerningPairsW(hdc, 100, NULL);
1364         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1365
1366         ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1367         ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1368
1369         ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1370         ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1371
1372         matches = 0;
1373
1374         for (n = 0; n < ret; n++)
1375         {
1376             DWORD j;
1377             /* Disabled to limit console spam */
1378             if (0 && kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1379                 trace("{'%c','%c',%d},\n",
1380                       kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1381             for (j = 0; j < kd[i].total_kern_pairs; j++)
1382             {
1383                 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1384                     kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1385                 {
1386                     ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1387                        "pair %d:%d got %d, expected %d\n",
1388                        kern_pair[n].wFirst, kern_pair[n].wSecond,
1389                        kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1390                     matches++;
1391                 }
1392             }
1393         }
1394
1395         ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1396            matches, kd[i].total_kern_pairs);
1397
1398         HeapFree(GetProcessHeap(), 0, kern_pair);
1399
1400         SelectObject(hdc, hfont_old);
1401         DeleteObject(hfont);
1402     }
1403
1404     ReleaseDC(0, hdc);
1405 }
1406
1407 static void test_height_selection(void)
1408 {
1409     static const struct font_data
1410     {
1411         const char face_name[LF_FACESIZE];
1412         int requested_height;
1413         int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1414     } fd[] =
1415     {
1416         {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1417         {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1418         {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1419         {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1420         {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1421         {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1422         {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1423         {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1424         {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1425         {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1426     };
1427     HDC hdc;
1428     LOGFONT lf;
1429     HFONT hfont, old_hfont;
1430     TEXTMETRIC tm;
1431     INT ret, i;
1432
1433     hdc = CreateCompatibleDC(0);
1434     assert(hdc);
1435
1436     for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1437     {
1438         if (!is_truetype_font_installed(fd[i].face_name))
1439         {
1440             skip("%s is not installed\n", fd[i].face_name);
1441             continue;
1442         }
1443
1444         memset(&lf, 0, sizeof(lf));
1445         lf.lfHeight = fd[i].requested_height;
1446         lf.lfWeight = fd[i].weight;
1447         strcpy(lf.lfFaceName, fd[i].face_name);
1448
1449         hfont = CreateFontIndirect(&lf);
1450         assert(hfont);
1451
1452         old_hfont = SelectObject(hdc, hfont);
1453         ret = GetTextMetrics(hdc, &tm);
1454         ok(ret, "GetTextMetrics error %d\n", GetLastError());
1455         if(fd[i].dpi == tm.tmDigitizedAspectX)
1456         {
1457             trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1458             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);
1459             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);
1460             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);
1461             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);
1462 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1463             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);
1464 #endif
1465             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);
1466         }
1467
1468         SelectObject(hdc, old_hfont);
1469         DeleteObject(hfont);
1470     }
1471
1472     DeleteDC(hdc);
1473 }
1474
1475 static void test_GetOutlineTextMetrics(void)
1476 {
1477     OUTLINETEXTMETRIC *otm;
1478     LOGFONT lf;
1479     HFONT hfont, hfont_old;
1480     HDC hdc;
1481     DWORD ret, otm_size;
1482     LPSTR unset_ptr;
1483
1484     if (!is_font_installed("Arial"))
1485     {
1486         skip("Arial is not installed\n");
1487         return;
1488     }
1489
1490     hdc = GetDC(0);
1491
1492     memset(&lf, 0, sizeof(lf));
1493     strcpy(lf.lfFaceName, "Arial");
1494     lf.lfHeight = -13;
1495     lf.lfWeight = FW_NORMAL;
1496     lf.lfPitchAndFamily = DEFAULT_PITCH;
1497     lf.lfQuality = PROOF_QUALITY;
1498     hfont = CreateFontIndirect(&lf);
1499     assert(hfont != 0);
1500
1501     hfont_old = SelectObject(hdc, hfont);
1502     otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1503     trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1504
1505     otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1506
1507     memset(otm, 0xAA, otm_size);
1508     SetLastError(0xdeadbeef);
1509     otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1510     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1511     ok(ret == 1 /* Win9x */ ||
1512        ret == otm->otmSize /* XP*/,
1513        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1514     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1515     {
1516         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1517         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1518         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1519         ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1520     }
1521
1522     memset(otm, 0xAA, otm_size);
1523     SetLastError(0xdeadbeef);
1524     otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1525     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1526     ok(ret == 1 /* Win9x */ ||
1527        ret == otm->otmSize /* XP*/,
1528        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1529     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1530     {
1531         ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1532         ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1533         ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1534         ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1535     }
1536
1537     /* ask about truncated data */
1538     memset(otm, 0xAA, otm_size);
1539     memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1540     SetLastError(0xdeadbeef);
1541     otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1542     ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1543     ok(ret == 1 /* Win9x */ ||
1544        ret == otm->otmSize /* XP*/,
1545        "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1546     if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1547     {
1548         ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1549         ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1550         ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1551     }
1552     ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1553
1554     HeapFree(GetProcessHeap(), 0, otm);
1555
1556     SelectObject(hdc, hfont_old);
1557     DeleteObject(hfont);
1558
1559     ReleaseDC(0, hdc);
1560 }
1561
1562 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1563 {
1564     INT         y,
1565                 breakCount,
1566                 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1567                 areaWidth = clientArea->right - clientArea->left,
1568                 nErrors = 0, e;
1569     BOOL        lastExtent = FALSE;
1570     PSTR        pFirstChar, pLastChar;
1571     SIZE        size;
1572     TEXTMETRICA tm;
1573     struct err
1574     {
1575         char extent[100];
1576         int  GetTextExtentExPointWWidth;
1577     } error[10];
1578
1579     GetTextMetricsA(hdc, &tm);
1580     y = clientArea->top;
1581     do {
1582         breakCount = 0;
1583         while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1584         pFirstChar = str;
1585
1586         do {
1587             pLastChar = str;
1588
1589             /* if not at the end of the string, ... */
1590             if (*str == '\0') break;
1591             /* ... add the next word to the current extent */
1592             while (*str != '\0' && *str++ != tm.tmBreakChar);
1593             breakCount++;
1594             SetTextJustification(hdc, 0, 0);
1595             GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1596         } while ((int) size.cx < areaWidth);
1597
1598         /* ignore trailing break chars */
1599         breakCount--;
1600         while (*(pLastChar - 1) == tm.tmBreakChar)
1601         {
1602             pLastChar--;
1603             breakCount--;
1604         }
1605
1606         if (*str == '\0' || breakCount <= 0) pLastChar = str;
1607
1608         SetTextJustification(hdc, 0, 0);
1609         GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1610
1611         /* do not justify the last extent */
1612         if (*str != '\0' && breakCount > 0)
1613         {
1614             SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1615             GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1616             justifiedWidth = size.cx;
1617         }
1618         else lastExtent = TRUE;
1619
1620         /* catch errors and report them */
1621         if (!lastExtent && (justifiedWidth != areaWidth))
1622         {
1623             memset(error[nErrors].extent, 0, 100);
1624             memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1625             error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1626             nErrors++;
1627         }
1628
1629         y += size.cy;
1630         str = pLastChar;
1631     } while (*str && y < clientArea->bottom);
1632
1633     for (e = 0; e < nErrors; e++)
1634     {
1635         /* The width returned by GetTextExtentPoint32() is exactly the same
1636            returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1637         ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1638             "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1639             error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1640     }
1641 }
1642
1643 static void test_SetTextJustification(void)
1644 {
1645     HDC hdc;
1646     RECT clientArea;
1647     LOGFONTA lf;
1648     HFONT hfont;
1649     HWND hwnd;
1650     static char testText[] =
1651             "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1652             "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1653             "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1654             "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1655             "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1656             "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1657             "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1658
1659     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1660     GetClientRect( hwnd, &clientArea );
1661     hdc = GetDC( hwnd );
1662
1663     memset(&lf, 0, sizeof lf);
1664     lf.lfCharSet = ANSI_CHARSET;
1665     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1666     lf.lfWeight = FW_DONTCARE;
1667     lf.lfHeight = 20;
1668     lf.lfQuality = DEFAULT_QUALITY;
1669     lstrcpyA(lf.lfFaceName, "Times New Roman");
1670     hfont = create_font("Times New Roman", &lf);
1671     SelectObject(hdc, hfont);
1672
1673     testJustification(hdc, testText, &clientArea);
1674
1675     DeleteObject(hfont);
1676     ReleaseDC(hwnd, hdc);
1677     DestroyWindow(hwnd);
1678 }
1679
1680 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1681 {
1682     HDC hdc;
1683     LOGFONTA lf;
1684     HFONT hfont, hfont_old;
1685     CHARSETINFO csi;
1686     FONTSIGNATURE fs;
1687     INT cs;
1688     DWORD i, ret;
1689     char name[64];
1690
1691     assert(count <= 128);
1692
1693     memset(&lf, 0, sizeof(lf));
1694
1695     lf.lfCharSet = charset;
1696     lf.lfHeight = 10;
1697     lstrcpyA(lf.lfFaceName, "Arial");
1698     SetLastError(0xdeadbeef);
1699     hfont = CreateFontIndirectA(&lf);
1700     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1701
1702     hdc = GetDC(0);
1703     hfont_old = SelectObject(hdc, hfont);
1704
1705     cs = GetTextCharsetInfo(hdc, &fs, 0);
1706     ok(cs == charset, "expected %d, got %d\n", charset, cs);
1707
1708     SetLastError(0xdeadbeef);
1709     ret = GetTextFaceA(hdc, sizeof(name), name);
1710     ok(ret, "GetTextFaceA error %u\n", GetLastError());
1711
1712     if (charset == SYMBOL_CHARSET)
1713     {
1714         ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1715         ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1716     }
1717     else
1718     {
1719         ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1720         ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1721     }
1722
1723     if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1724     {
1725         trace("Can't find codepage for charset %d\n", cs);
1726         ReleaseDC(0, hdc);
1727         return FALSE;
1728     }
1729     ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1730
1731     if (pGdiGetCodePage != NULL && pGdiGetCodePage(hdc) != code_page)
1732     {
1733         skip("Font code page %d, looking for code page %d\n",
1734              pGdiGetCodePage(hdc), code_page);
1735         ReleaseDC(0, hdc);
1736         return FALSE;
1737     }
1738
1739     if (unicode)
1740     {
1741         char ansi_buf[128];
1742         WCHAR unicode_buf[128];
1743
1744         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1745
1746         MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1747
1748         SetLastError(0xdeadbeef);
1749         ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1750         ok(ret == count, "GetGlyphIndicesW expected %d got %d, error %u\n",
1751            count, ret, GetLastError());
1752     }
1753     else
1754     {
1755         char ansi_buf[128];
1756
1757         for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1758
1759         SetLastError(0xdeadbeef);
1760         ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1761         ok(ret == count, "GetGlyphIndicesA expected %d got %d, error %u\n",
1762            count, ret, GetLastError());
1763     }
1764
1765     SelectObject(hdc, hfont_old);
1766     DeleteObject(hfont);
1767
1768     ReleaseDC(0, hdc);
1769
1770     return TRUE;
1771 }
1772
1773 static void test_font_charset(void)
1774 {
1775     static struct charset_data
1776     {
1777         INT charset;
1778         UINT code_page;
1779         WORD font_idxA[128], font_idxW[128];
1780     } cd[] =
1781     {
1782         { ANSI_CHARSET, 1252 },
1783         { RUSSIAN_CHARSET, 1251 },
1784         { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1785     };
1786     int i;
1787
1788     if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1789     {
1790         win_skip("Skipping the font charset test on a Win9x platform\n");
1791         return;
1792     }
1793
1794     if (!is_font_installed("Arial"))
1795     {
1796         skip("Arial is not installed\n");
1797         return;
1798     }
1799
1800     for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1801     {
1802         if (cd[i].charset == SYMBOL_CHARSET)
1803         {
1804             if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1805             {
1806                 skip("Symbol or Wingdings is not installed\n");
1807                 break;
1808             }
1809         }
1810         if (get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE) &&
1811             get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE))
1812             ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1813     }
1814
1815     ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1816     if (i > 2)
1817     {
1818         ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1819         ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1820     }
1821     else
1822         skip("Symbol or Wingdings is not installed\n");
1823 }
1824
1825 static void test_GetFontUnicodeRanges(void)
1826 {
1827     LOGFONTA lf;
1828     HDC hdc;
1829     HFONT hfont, hfont_old;
1830     DWORD size;
1831     GLYPHSET *gs;
1832     DWORD i;
1833
1834     if (!pGetFontUnicodeRanges)
1835     {
1836         win_skip("GetFontUnicodeRanges not available before W2K\n");
1837         return;
1838     }
1839
1840     memset(&lf, 0, sizeof(lf));
1841     lstrcpyA(lf.lfFaceName, "Arial");
1842     hfont = create_font("Arial", &lf);
1843
1844     hdc = GetDC(0);
1845     hfont_old = SelectObject(hdc, hfont);
1846
1847     size = pGetFontUnicodeRanges(NULL, NULL);
1848     ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1849
1850     size = pGetFontUnicodeRanges(hdc, NULL);
1851     ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1852
1853     gs = HeapAlloc(GetProcessHeap(), 0, size);
1854
1855     size = pGetFontUnicodeRanges(hdc, gs);
1856     ok(size, "GetFontUnicodeRanges failed\n");
1857
1858     if (0) /* Disabled to limit console spam */
1859         for (i = 0; i < gs->cRanges; i++)
1860             trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1861     trace("found %u ranges\n", gs->cRanges);
1862
1863     HeapFree(GetProcessHeap(), 0, gs);
1864
1865     SelectObject(hdc, hfont_old);
1866     DeleteObject(hfont);
1867     ReleaseDC(NULL, hdc);
1868 }
1869
1870 #define MAX_ENUM_FONTS 4096
1871
1872 struct enum_font_data
1873 {
1874     int total;
1875     LOGFONT lf[MAX_ENUM_FONTS];
1876 };
1877
1878 struct enum_font_dataW
1879 {
1880     int total;
1881     LOGFONTW lf[MAX_ENUM_FONTS];
1882 };
1883
1884 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1885 {
1886     struct enum_font_data *efd = (struct enum_font_data *)lParam;
1887
1888     ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1889
1890     if (type != TRUETYPE_FONTTYPE) return 1;
1891     if (0) /* Disabled to limit console spam */
1892         trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1893               lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1894     if (efd->total < MAX_ENUM_FONTS)
1895         efd->lf[efd->total++] = *lf;
1896     else
1897         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1898
1899     return 1;
1900 }
1901
1902 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1903 {
1904     struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1905
1906     ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1907
1908     if (type != TRUETYPE_FONTTYPE) return 1;
1909     if (0) /* Disabled to limit console spam */
1910         trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
1911               wine_dbgstr_w(lf->lfFaceName), lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1912     if (efd->total < MAX_ENUM_FONTS)
1913         efd->lf[efd->total++] = *lf;
1914     else
1915         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1916
1917     return 1;
1918 }
1919
1920 static void get_charset_stats(struct enum_font_data *efd,
1921                               int *ansi_charset, int *symbol_charset,
1922                               int *russian_charset)
1923 {
1924     int i;
1925
1926     *ansi_charset = 0;
1927     *symbol_charset = 0;
1928     *russian_charset = 0;
1929
1930     for (i = 0; i < efd->total; i++)
1931     {
1932         switch (efd->lf[i].lfCharSet)
1933         {
1934         case ANSI_CHARSET:
1935             (*ansi_charset)++;
1936             break;
1937         case SYMBOL_CHARSET:
1938             (*symbol_charset)++;
1939             break;
1940         case RUSSIAN_CHARSET:
1941             (*russian_charset)++;
1942             break;
1943         }
1944     }
1945 }
1946
1947 static void get_charset_statsW(struct enum_font_dataW *efd,
1948                               int *ansi_charset, int *symbol_charset,
1949                               int *russian_charset)
1950 {
1951     int i;
1952
1953     *ansi_charset = 0;
1954     *symbol_charset = 0;
1955     *russian_charset = 0;
1956
1957     for (i = 0; i < efd->total; i++)
1958     {
1959         switch (efd->lf[i].lfCharSet)
1960         {
1961         case ANSI_CHARSET:
1962             (*ansi_charset)++;
1963             break;
1964         case SYMBOL_CHARSET:
1965             (*symbol_charset)++;
1966             break;
1967         case RUSSIAN_CHARSET:
1968             (*russian_charset)++;
1969             break;
1970         }
1971     }
1972 }
1973
1974 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1975 {
1976     struct enum_font_data efd;
1977     struct enum_font_dataW efdw;
1978     LOGFONT lf;
1979     HDC hdc;
1980     int i, ret, ansi_charset, symbol_charset, russian_charset;
1981
1982     trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1983
1984     if (*font_name && !is_truetype_font_installed(font_name))
1985     {
1986         skip("%s is not installed\n", font_name);
1987         return;
1988     }
1989
1990     hdc = GetDC(0);
1991
1992     /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1993      * while EnumFontFamiliesEx doesn't.
1994      */
1995     if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1996     {
1997         /*
1998          * Use EnumFontFamiliesW since win98 crashes when the
1999          *    second parameter is NULL using EnumFontFamilies
2000          */
2001         efdw.total = 0;
2002         SetLastError(0xdeadbeef);
2003         ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
2004         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
2005         if(ret)
2006         {
2007             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2008             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2009                   ansi_charset, symbol_charset, russian_charset);
2010             ok(efdw.total > 0, "fonts enumerated: NULL\n");
2011             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2012             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2013             ok(russian_charset > 0 ||
2014                broken(russian_charset == 0), /* NT4 */
2015                "NULL family should enumerate RUSSIAN_CHARSET\n");
2016         }
2017
2018         efdw.total = 0;
2019         SetLastError(0xdeadbeef);
2020         ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
2021         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
2022         if(ret)
2023         {
2024             get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
2025             trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2026                   ansi_charset, symbol_charset, russian_charset);
2027             ok(efdw.total > 0, "fonts enumerated: NULL\n");
2028             ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
2029             ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2030             ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2031         }
2032     }
2033
2034     efd.total = 0;
2035     SetLastError(0xdeadbeef);
2036     ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
2037     ok(ret, "EnumFontFamilies error %u\n", GetLastError());
2038     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2039     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2040           ansi_charset, symbol_charset, russian_charset,
2041           *font_name ? font_name : "<empty>");
2042     if (*font_name)
2043         ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2044     else
2045         ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
2046     for (i = 0; i < efd.total; i++)
2047     {
2048 /* FIXME: remove completely once Wine is fixed */
2049 if (efd.lf[i].lfCharSet != font_charset)
2050 {
2051 todo_wine
2052     ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2053 }
2054 else
2055         ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2056         ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2057            font_name, efd.lf[i].lfFaceName);
2058     }
2059
2060     memset(&lf, 0, sizeof(lf));
2061     lf.lfCharSet = ANSI_CHARSET;
2062     lstrcpy(lf.lfFaceName, font_name);
2063     efd.total = 0;
2064     SetLastError(0xdeadbeef);
2065     ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2066     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2067     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2068     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2069           ansi_charset, symbol_charset, russian_charset,
2070           *font_name ? font_name : "<empty>");
2071     if (font_charset == SYMBOL_CHARSET)
2072     {
2073         if (*font_name)
2074             ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
2075         else
2076             ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
2077     }
2078     else
2079     {
2080         ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
2081         for (i = 0; i < efd.total; i++)
2082         {
2083             ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2084             if (*font_name)
2085                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2086                    font_name, efd.lf[i].lfFaceName);
2087         }
2088     }
2089
2090     /* DEFAULT_CHARSET should enumerate all available charsets */
2091     memset(&lf, 0, sizeof(lf));
2092     lf.lfCharSet = DEFAULT_CHARSET;
2093     lstrcpy(lf.lfFaceName, font_name);
2094     efd.total = 0;
2095     SetLastError(0xdeadbeef);
2096     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2097     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2098     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2099     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2100           ansi_charset, symbol_charset, russian_charset,
2101           *font_name ? font_name : "<empty>");
2102     ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
2103     for (i = 0; i < efd.total; i++)
2104     {
2105         if (*font_name)
2106             ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2107                font_name, efd.lf[i].lfFaceName);
2108     }
2109     if (*font_name)
2110     {
2111         switch (font_charset)
2112         {
2113         case ANSI_CHARSET:
2114             ok(ansi_charset > 0,
2115                "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2116             ok(!symbol_charset,
2117                "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
2118             ok(russian_charset > 0,
2119                "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2120             break;
2121         case SYMBOL_CHARSET:
2122             ok(!ansi_charset,
2123                "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
2124             ok(symbol_charset,
2125                "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2126             ok(!russian_charset,
2127                "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
2128             break;
2129         case DEFAULT_CHARSET:
2130             ok(ansi_charset > 0,
2131                "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
2132             ok(symbol_charset > 0,
2133                "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
2134             ok(russian_charset > 0,
2135                "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
2136             break;
2137         }
2138     }
2139     else
2140     {
2141         ok(ansi_charset > 0,
2142            "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2143         ok(symbol_charset > 0,
2144            "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2145         ok(russian_charset > 0,
2146            "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2147     }
2148
2149     memset(&lf, 0, sizeof(lf));
2150     lf.lfCharSet = SYMBOL_CHARSET;
2151     lstrcpy(lf.lfFaceName, font_name);
2152     efd.total = 0;
2153     SetLastError(0xdeadbeef);
2154     EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
2155     ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2156     get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2157     trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2158           ansi_charset, symbol_charset, russian_charset,
2159           *font_name ? font_name : "<empty>");
2160     if (*font_name && font_charset == ANSI_CHARSET)
2161         ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2162     else
2163     {
2164         ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2165         for (i = 0; i < efd.total; i++)
2166         {
2167             ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2168             if (*font_name)
2169                 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2170                    font_name, efd.lf[i].lfFaceName);
2171         }
2172
2173         ok(!ansi_charset,
2174            "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2175         ok(symbol_charset > 0,
2176            "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2177         ok(!russian_charset,
2178            "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2179     }
2180
2181     ReleaseDC(0, hdc);
2182 }
2183
2184 static INT CALLBACK enum_font_data_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2185 {
2186     struct enum_font_data *efd = (struct enum_font_data *)lParam;
2187
2188     if (type != TRUETYPE_FONTTYPE) return 1;
2189
2190     if (efd->total < MAX_ENUM_FONTS)
2191         efd->lf[efd->total++] = *lf;
2192     else
2193         trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
2194
2195     return 1;
2196 }
2197
2198 static void test_EnumFontFamiliesEx_default_charset(void)
2199 {
2200     struct enum_font_data efd;
2201     LOGFONT gui_font, enum_font;
2202     DWORD ret;
2203     HDC hdc;
2204
2205     ret = GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(gui_font), &gui_font);
2206     ok(ret, "GetObject failed.\n");
2207     if (!ret)
2208         return;
2209
2210     efd.total = 0;
2211
2212     hdc = GetDC(0);
2213     memset(&enum_font, 0, sizeof(enum_font));
2214     lstrcpy(enum_font.lfFaceName, gui_font.lfFaceName);
2215     enum_font.lfCharSet = DEFAULT_CHARSET;
2216     EnumFontFamiliesEx(hdc, &enum_font, enum_font_data_proc, (LPARAM)&efd, 0);
2217     ReleaseDC(0, hdc);
2218
2219     if (efd.total == 0) {
2220         skip("'%s' is not found or not a TrueType font.\n", gui_font.lfFaceName);
2221         return;
2222     }
2223     trace("'%s' has %d charsets.\n", gui_font.lfFaceName, efd.total);
2224
2225     ok(efd.lf[0].lfCharSet == gui_font.lfCharSet,
2226        "(%s) got charset %d expected %d\n",
2227        efd.lf[0].lfFaceName, efd.lf[0].lfCharSet, gui_font.lfCharSet);
2228
2229     return;
2230 }
2231
2232 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2233 {
2234     HFONT hfont, hfont_prev;
2235     DWORD ret;
2236     GLYPHMETRICS gm1, gm2;
2237     LOGFONTA lf2 = *lf;
2238     WORD idx;
2239
2240     if(!pGetGlyphIndicesA)
2241         return;
2242
2243     /* negative widths are handled just as positive ones */
2244     lf2.lfWidth = -lf->lfWidth;
2245
2246     SetLastError(0xdeadbeef);
2247     hfont = CreateFontIndirectA(lf);
2248     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2249     check_font("original", lf, hfont);
2250
2251     hfont_prev = SelectObject(hdc, hfont);
2252
2253     ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2254     if (ret == GDI_ERROR || idx == 0xffff)
2255     {
2256         SelectObject(hdc, hfont_prev);
2257         DeleteObject(hfont);
2258         skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2259         return;
2260     }
2261
2262     /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2263     memset(&gm1, 0xab, sizeof(gm1));
2264     SetLastError(0xdeadbeef);
2265     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2266     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2267
2268     SelectObject(hdc, hfont_prev);
2269     DeleteObject(hfont);
2270
2271     SetLastError(0xdeadbeef);
2272     hfont = CreateFontIndirectA(&lf2);
2273     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2274     check_font("negative width", &lf2, hfont);
2275
2276     hfont_prev = SelectObject(hdc, hfont);
2277
2278     memset(&gm2, 0xbb, sizeof(gm2));
2279     SetLastError(0xdeadbeef);
2280     ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2281     ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2282
2283     SelectObject(hdc, hfont_prev);
2284     DeleteObject(hfont);
2285
2286     ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2287        gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2288        gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2289        gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2290        gm1.gmCellIncX == gm2.gmCellIncX &&
2291        gm1.gmCellIncY == gm2.gmCellIncY,
2292        "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2293        gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2294        gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2295        gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2296        gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2297 }
2298
2299 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2300 #include "pshpack2.h"
2301 typedef struct
2302 {
2303     USHORT version;
2304     SHORT xAvgCharWidth;
2305     USHORT usWeightClass;
2306     USHORT usWidthClass;
2307     SHORT fsType;
2308     SHORT ySubscriptXSize;
2309     SHORT ySubscriptYSize;
2310     SHORT ySubscriptXOffset;
2311     SHORT ySubscriptYOffset;
2312     SHORT ySuperscriptXSize;
2313     SHORT ySuperscriptYSize;
2314     SHORT ySuperscriptXOffset;
2315     SHORT ySuperscriptYOffset;
2316     SHORT yStrikeoutSize;
2317     SHORT yStrikeoutPosition;
2318     SHORT sFamilyClass;
2319     PANOSE panose;
2320     ULONG ulUnicodeRange1;
2321     ULONG ulUnicodeRange2;
2322     ULONG ulUnicodeRange3;
2323     ULONG ulUnicodeRange4;
2324     CHAR achVendID[4];
2325     USHORT fsSelection;
2326     USHORT usFirstCharIndex;
2327     USHORT usLastCharIndex;
2328     /* According to the Apple spec, original version didn't have the below fields,
2329      * version numbers were taken from the OpenType spec.
2330      */
2331     /* version 0 (TrueType 1.5) */
2332     USHORT sTypoAscender;
2333     USHORT sTypoDescender;
2334     USHORT sTypoLineGap;
2335     USHORT usWinAscent;
2336     USHORT usWinDescent;
2337     /* version 1 (TrueType 1.66) */
2338     ULONG ulCodePageRange1;
2339     ULONG ulCodePageRange2;
2340     /* version 2 (OpenType 1.2) */
2341     SHORT sxHeight;
2342     SHORT sCapHeight;
2343     USHORT usDefaultChar;
2344     USHORT usBreakChar;
2345     USHORT usMaxContext;
2346 } TT_OS2_V2;
2347 #include "poppack.h"
2348
2349 #ifdef WORDS_BIGENDIAN
2350 #define GET_BE_WORD(x) (x)
2351 #define GET_BE_DWORD(x) (x)
2352 #else
2353 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2354 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2355 #endif
2356
2357 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2358                     ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2359                     ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2360 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2361 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2362 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2363
2364 typedef struct
2365 {
2366     USHORT version;
2367     USHORT num_tables;
2368 } cmap_header;
2369
2370 typedef struct
2371 {
2372     USHORT plat_id;
2373     USHORT enc_id;
2374     ULONG offset;
2375 } cmap_encoding_record;
2376
2377 typedef struct
2378 {
2379     USHORT format;
2380     USHORT length;
2381     USHORT language;
2382
2383     BYTE glyph_ids[256];
2384 } cmap_format_0;
2385
2386 typedef struct
2387 {
2388     USHORT format;
2389     USHORT length;
2390     USHORT language;
2391
2392     USHORT seg_countx2;
2393     USHORT search_range;
2394     USHORT entry_selector;
2395     USHORT range_shift;
2396
2397     USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2398 /* Then follows:
2399     USHORT pad;
2400     USHORT start_count[seg_countx2 / 2];
2401     USHORT id_delta[seg_countx2 / 2];
2402     USHORT id_range_offset[seg_countx2 / 2];
2403     USHORT glyph_ids[];
2404 */
2405 } cmap_format_4;
2406
2407 typedef struct
2408 {
2409     USHORT end_count;
2410     USHORT start_count;
2411     USHORT id_delta;
2412     USHORT id_range_offset;
2413 } cmap_format_4_seg;
2414
2415 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2416 {
2417     ok((tmA->tmPitchAndFamily & 0xf0) == family ||
2418        broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH),
2419        "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2420        name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2421        os2->panose.bWeight, os2->panose.bProportion);
2422 }
2423
2424 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2425 {
2426     int i;
2427     cmap_format_0 *cmap = (cmap_format_0*)ptr;
2428
2429     *first = 256;
2430
2431     for(i = 0; i < 256; i++)
2432     {
2433         if(cmap->glyph_ids[i] == 0) continue;
2434         *last = i;
2435         if(*first == 256) *first = i;
2436     }
2437     if(*first == 256) return FALSE;
2438     return TRUE;
2439 }
2440
2441 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2442 {
2443     USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2444     seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2445     seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2446     seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2447     seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2448 }
2449
2450 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2451 {
2452     int i;
2453     cmap_format_4 *cmap = (cmap_format_4*)ptr;
2454     USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2455     USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2456
2457     *first = 0x10000;
2458
2459     for(i = 0; i < seg_count; i++)
2460     {
2461         DWORD code, index;
2462         cmap_format_4_seg seg;
2463
2464         get_seg4(cmap, i, &seg);
2465         for(code = seg.start_count; code <= seg.end_count; code++)
2466         {
2467             if(seg.id_range_offset == 0)
2468                 index = (seg.id_delta + code) & 0xffff;
2469             else
2470             {
2471                 index = seg.id_range_offset / 2
2472                     + code - seg.start_count
2473                     + i - seg_count;
2474
2475                 /* some fonts have broken last segment */
2476                 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2477                     index = GET_BE_WORD(glyph_ids[index]);
2478                 else
2479                 {
2480                     trace("segment %04x/%04x index %04x points to nowhere\n",
2481                           seg.start_count, seg.end_count, index);
2482                     index = 0;
2483                 }
2484                 if(index) index += seg.id_delta;
2485             }
2486             if(*first == 0x10000)
2487                 *last = *first = code;
2488             else if(index)
2489                 *last = code;
2490         }
2491     }
2492
2493     if(*first == 0x10000) return FALSE;
2494     return TRUE;
2495 }
2496
2497 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2498 {
2499     USHORT i;
2500     cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2501
2502     for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2503     {
2504         if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2505             return (BYTE *)header + GET_BE_DWORD(record->offset);
2506         record++;
2507     }
2508     return NULL;
2509 }
2510
2511 typedef enum
2512 {
2513     cmap_none,
2514     cmap_ms_unicode,
2515     cmap_ms_symbol
2516 } cmap_type;
2517
2518 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2519 {
2520     LONG size, ret;
2521     cmap_header *header;
2522     void *cmap;
2523     BOOL r = FALSE;
2524     WORD format;
2525
2526     size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2527     ok(size != GDI_ERROR, "no cmap table found\n");
2528     if(size == GDI_ERROR) return FALSE;
2529
2530     header = HeapAlloc(GetProcessHeap(), 0, size);
2531     ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2532     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2533     ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2534
2535     cmap = get_cmap(header, 3, 1);
2536     if(cmap)
2537         *cmap_type = cmap_ms_unicode;
2538     else
2539     {
2540         cmap = get_cmap(header, 3, 0);
2541         if(cmap) *cmap_type = cmap_ms_symbol;
2542     }
2543     if(!cmap)
2544     {
2545         *cmap_type = cmap_none;
2546         goto end;
2547     }
2548
2549     format = GET_BE_WORD(*(WORD *)cmap);
2550     switch(format)
2551     {
2552     case 0:
2553         r = get_first_last_from_cmap0(cmap, first, last);
2554         break;
2555     case 4:
2556         r = get_first_last_from_cmap4(cmap, first, last, size);
2557         break;
2558     default:
2559         trace("unhandled cmap format %d\n", format);
2560         break;
2561     }
2562
2563 end:
2564     HeapFree(GetProcessHeap(), 0, header);
2565     return r;
2566 }
2567
2568 #define TT_PLATFORM_MICROSOFT 3
2569 #define TT_MS_ID_UNICODE_CS 1
2570 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2571 #define TT_NAME_ID_FULL_NAME 4
2572
2573 static BOOL get_ttf_nametable_entry(HDC hdc, WORD name_id, char *out_buf, SIZE_T out_size)
2574 {
2575     struct sfnt_name_header
2576     {
2577         USHORT format;
2578         USHORT number_of_record;
2579         USHORT storage_offset;
2580     } *header;
2581     struct sfnt_name
2582     {
2583         USHORT platform_id;
2584         USHORT encoding_id;
2585         USHORT language_id;
2586         USHORT name_id;
2587         USHORT length;
2588         USHORT offset;
2589     } *entry;
2590     BOOL r = FALSE;
2591     LONG size, offset, length;
2592     LONG c, ret;
2593     WCHAR *name;
2594     BYTE *data;
2595     USHORT i;
2596
2597     size = GetFontData(hdc, MS_NAME_TAG, 0, NULL, 0);
2598     ok(size != GDI_ERROR, "no name table found\n");
2599     if(size == GDI_ERROR) return FALSE;
2600
2601     data = HeapAlloc(GetProcessHeap(), 0, size);
2602     ret = GetFontData(hdc, MS_NAME_TAG, 0, data, size);
2603     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2604
2605     header = (void *)data;
2606     header->format = GET_BE_WORD(header->format);
2607     header->number_of_record = GET_BE_WORD(header->number_of_record);
2608     header->storage_offset = GET_BE_WORD(header->storage_offset);
2609     if (header->format != 0)
2610     {
2611         trace("got format %u\n", header->format);
2612         goto out;
2613     }
2614     if (header->number_of_record == 0 || sizeof(*header) + header->number_of_record * sizeof(*entry) > size)
2615     {
2616         trace("number records out of range: %d\n", header->number_of_record);
2617         goto out;
2618     }
2619     if (header->storage_offset >= size)
2620     {
2621         trace("storage_offset %u > size %u\n", header->storage_offset, size);
2622         goto out;
2623     }
2624
2625     entry = (void *)&header[1];
2626     for (i = 0; i < header->number_of_record; i++)
2627     {
2628         if (GET_BE_WORD(entry[i].platform_id) != TT_PLATFORM_MICROSOFT ||
2629             GET_BE_WORD(entry[i].encoding_id) != TT_MS_ID_UNICODE_CS ||
2630             GET_BE_WORD(entry[i].language_id) != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
2631             GET_BE_WORD(entry[i].name_id) != name_id)
2632         {
2633             continue;
2634         }
2635
2636         offset = header->storage_offset + GET_BE_WORD(entry[i].offset);
2637         length = GET_BE_WORD(entry[i].length);
2638         if (offset + length > size)
2639         {
2640             trace("entry %d is out of range\n", i);
2641             break;
2642         }
2643         if (length >= out_size)
2644         {
2645             trace("buffer too small for entry %d\n", i);
2646             break;
2647         }
2648
2649         name = (WCHAR *)(data + offset);
2650         for (c = 0; c < length / 2; c++)
2651             out_buf[c] = GET_BE_WORD(name[c]);
2652         out_buf[c] = 0;
2653
2654         r = TRUE;
2655         break;
2656     }
2657
2658 out:
2659     HeapFree(GetProcessHeap(), 0, data);
2660     return r;
2661 }
2662
2663 static void test_text_metrics(const LOGFONTA *lf)
2664 {
2665     HDC hdc;
2666     HFONT hfont, hfont_old;
2667     TEXTMETRICA tmA;
2668     TT_OS2_V2 tt_os2;
2669     LONG size, ret;
2670     const char *font_name = lf->lfFaceName;
2671     DWORD cmap_first = 0, cmap_last = 0;
2672     cmap_type cmap_type;
2673     BOOL sys_lang_non_english;
2674
2675     sys_lang_non_english = PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH;
2676     hdc = GetDC(0);
2677
2678     SetLastError(0xdeadbeef);
2679     hfont = CreateFontIndirectA(lf);
2680     ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2681
2682     hfont_old = SelectObject(hdc, hfont);
2683
2684     size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2685     if (size == GDI_ERROR)
2686     {
2687         trace("OS/2 chunk was not found\n");
2688         goto end_of_test;
2689     }
2690     if (size > sizeof(tt_os2))
2691     {
2692         trace("got too large OS/2 chunk of size %u\n", size);
2693         size = sizeof(tt_os2);
2694     }
2695
2696     memset(&tt_os2, 0, sizeof(tt_os2));
2697     ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2698     ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2699
2700     SetLastError(0xdeadbeef);
2701     ret = GetTextMetricsA(hdc, &tmA);
2702     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2703
2704     if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2705     {
2706         skip("Unable to retrieve first and last glyphs from cmap\n");
2707     }
2708     else
2709     {
2710         USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2711         USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2712         UINT os2_first_char, os2_last_char, default_char, break_char;
2713         USHORT version;
2714         TEXTMETRICW tmW;
2715
2716         version = GET_BE_WORD(tt_os2.version);
2717
2718         os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2719         os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2720         default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2721         break_char = GET_BE_WORD(tt_os2.usBreakChar);
2722
2723         trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2724               font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2725               default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2726
2727         if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2728         {
2729             expect_first_W    = 0;
2730             switch(GetACP())
2731             {
2732             case 1257:  /* Baltic */
2733                 expect_last_W = 0xf8fd;
2734                 break;
2735             default:
2736                 expect_last_W = 0xf0ff;
2737             }
2738             expect_break_W    = 0x20;
2739             expect_default_W  = expect_break_W - 1;
2740             expect_first_A    = 0x1e;
2741             expect_last_A     = min(os2_last_char - os2_first_char + 0x20, 0xff);
2742         }
2743         else
2744         {
2745             expect_first_W    = cmap_first;
2746             expect_last_W     = min(cmap_last, os2_last_char);
2747             if(os2_first_char <= 1)
2748                 expect_break_W = os2_first_char + 2;
2749             else if(os2_first_char > 0xff)
2750                 expect_break_W = 0x20;
2751             else
2752                 expect_break_W = os2_first_char;
2753             expect_default_W  = expect_break_W - 1;
2754             expect_first_A    = expect_default_W - 1;
2755             expect_last_A     = min(expect_last_W, 0xff);
2756         }
2757         expect_break_A    = expect_break_W;
2758         expect_default_A  = expect_default_W;
2759
2760         /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2761         if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2762             todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2763                          tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2764                          "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2765         else
2766             ok(tmA.tmFirstChar == expect_first_A ||
2767                tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2768                "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2769         if (pGdiGetCodePage == NULL || ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc), tmA.tmLastChar))
2770             ok(tmA.tmLastChar == expect_last_A ||
2771                tmA.tmLastChar == 0xff /* win9x */,
2772                "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2773         else
2774            skip("tmLastChar is DBCS lead byte\n");
2775         ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2776            font_name, tmA.tmBreakChar, expect_break_A);
2777         ok(tmA.tmDefaultChar == expect_default_A || broken(sys_lang_non_english),
2778            "A: tmDefaultChar for %s got %02x expected %02x\n",
2779            font_name, tmA.tmDefaultChar, expect_default_A);
2780
2781
2782         SetLastError(0xdeadbeef);
2783         ret = GetTextMetricsW(hdc, &tmW);
2784         ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2785            "GetTextMetricsW error %u\n", GetLastError());
2786         if (ret)
2787         {
2788             /* Wine uses the os2 first char */
2789             if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2790                 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2791                              font_name, tmW.tmFirstChar, expect_first_W);
2792             else
2793                 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2794                    font_name, tmW.tmFirstChar, expect_first_W);
2795
2796             /* Wine uses the os2 last char */
2797             if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2798                 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2799                              font_name, tmW.tmLastChar, expect_last_W);
2800             else
2801                 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2802                    font_name, tmW.tmLastChar, expect_last_W);
2803             ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2804                font_name, tmW.tmBreakChar, expect_break_W);
2805             ok(tmW.tmDefaultChar == expect_default_W || broken(sys_lang_non_english),
2806                "W: tmDefaultChar for %s got %02x expected %02x\n",
2807                font_name, tmW.tmDefaultChar, expect_default_W);
2808
2809             /* Test the aspect ratio while we have tmW */
2810             ret = GetDeviceCaps(hdc, LOGPIXELSX);
2811             ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2812                tmW.tmDigitizedAspectX, ret);
2813             ret = GetDeviceCaps(hdc, LOGPIXELSY);
2814             ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2815                tmW.tmDigitizedAspectX, ret);
2816         }
2817     }
2818
2819     /* test FF_ values */
2820     switch(tt_os2.panose.bFamilyType)
2821     {
2822     case PAN_ANY:
2823     case PAN_NO_FIT:
2824     case PAN_FAMILY_TEXT_DISPLAY:
2825     case PAN_FAMILY_PICTORIAL:
2826     default:
2827         if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2828            tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2829         {
2830             expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2831             break;
2832         }
2833         switch(tt_os2.panose.bSerifStyle)
2834         {
2835         case PAN_ANY:
2836         case PAN_NO_FIT:
2837         default:
2838             expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2839             break;
2840
2841         case PAN_SERIF_COVE:
2842         case PAN_SERIF_OBTUSE_COVE:
2843         case PAN_SERIF_SQUARE_COVE:
2844         case PAN_SERIF_OBTUSE_SQUARE_COVE:
2845         case PAN_SERIF_SQUARE:
2846         case PAN_SERIF_THIN:
2847         case PAN_SERIF_BONE:
2848         case PAN_SERIF_EXAGGERATED:
2849         case PAN_SERIF_TRIANGLE:
2850             expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2851             break;
2852
2853         case PAN_SERIF_NORMAL_SANS:
2854         case PAN_SERIF_OBTUSE_SANS:
2855         case PAN_SERIF_PERP_SANS:
2856         case PAN_SERIF_FLARED:
2857         case PAN_SERIF_ROUNDED:
2858             expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2859             break;
2860         }
2861         break;
2862
2863     case PAN_FAMILY_SCRIPT:
2864         expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2865         break;
2866
2867     case PAN_FAMILY_DECORATIVE:
2868         expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2869         break;
2870     }
2871
2872     test_negative_width(hdc, lf);
2873
2874 end_of_test:
2875     SelectObject(hdc, hfont_old);
2876     DeleteObject(hfont);
2877
2878     ReleaseDC(0, hdc);
2879 }
2880
2881 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2882 {
2883     INT *enumed = (INT *)lParam;
2884
2885     if (type == TRUETYPE_FONTTYPE)
2886     {
2887         (*enumed)++;
2888         test_text_metrics(lf);
2889     }
2890     return 1;
2891 }
2892
2893 static void test_GetTextMetrics(void)
2894 {
2895     LOGFONTA lf;
2896     HDC hdc;
2897     INT enumed;
2898
2899     /* Report only once */
2900     if(!pGetGlyphIndicesA)
2901         win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2902
2903     hdc = GetDC(0);
2904
2905     memset(&lf, 0, sizeof(lf));
2906     lf.lfCharSet = DEFAULT_CHARSET;
2907     enumed = 0;
2908     EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2909     trace("Tested metrics of %d truetype fonts\n", enumed);
2910
2911     ReleaseDC(0, hdc);
2912 }
2913
2914 static void test_nonexistent_font(void)
2915 {
2916     static const struct
2917     {
2918         const char *name;
2919         int charset;
2920     } font_subst[] =
2921     {
2922         { "Times New Roman Baltic", 186 },
2923         { "Times New Roman CE", 238 },
2924         { "Times New Roman CYR", 204 },
2925         { "Times New Roman Greek", 161 },
2926         { "Times New Roman TUR", 162 }
2927     };
2928     LOGFONTA lf;
2929     HDC hdc;
2930     HFONT hfont;
2931     CHARSETINFO csi;
2932     INT cs, expected_cs, i;
2933     char buf[LF_FACESIZE];
2934
2935     if (!is_truetype_font_installed("Arial") ||
2936         !is_truetype_font_installed("Times New Roman"))
2937     {
2938         skip("Arial or Times New Roman not installed\n");
2939         return;
2940     }
2941
2942     expected_cs = GetACP();
2943     if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2944     {
2945         skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2946         return;
2947     }
2948     expected_cs = csi.ciCharset;
2949     trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2950
2951     hdc = GetDC(0);
2952
2953     memset(&lf, 0, sizeof(lf));
2954     lf.lfHeight = 100;
2955     lf.lfWeight = FW_REGULAR;
2956     lf.lfCharSet = ANSI_CHARSET;
2957     lf.lfPitchAndFamily = FF_SWISS;
2958     strcpy(lf.lfFaceName, "Nonexistent font");
2959     hfont = CreateFontIndirectA(&lf);
2960     hfont = SelectObject(hdc, hfont);
2961     GetTextFaceA(hdc, sizeof(buf), buf);
2962     ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2963     cs = GetTextCharset(hdc);
2964     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2965     DeleteObject(SelectObject(hdc, hfont));
2966
2967     memset(&lf, 0, sizeof(lf));
2968     lf.lfHeight = -13;
2969     lf.lfWeight = FW_DONTCARE;
2970     strcpy(lf.lfFaceName, "Nonexistent font");
2971     hfont = CreateFontIndirectA(&lf);
2972     hfont = SelectObject(hdc, hfont);
2973     GetTextFaceA(hdc, sizeof(buf), buf);
2974 todo_wine /* Wine uses Arial for all substitutions */
2975     ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2976        !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2977        !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2978        "Got %s\n", buf);
2979     cs = GetTextCharset(hdc);
2980     ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d\n", expected_cs, cs);
2981     DeleteObject(SelectObject(hdc, hfont));
2982
2983     memset(&lf, 0, sizeof(lf));
2984     lf.lfHeight = -13;
2985     lf.lfWeight = FW_REGULAR;
2986     strcpy(lf.lfFaceName, "Nonexistent font");
2987     hfont = CreateFontIndirectA(&lf);
2988     hfont = SelectObject(hdc, hfont);
2989     GetTextFaceA(hdc, sizeof(buf), buf);
2990     ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2991        !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2992     cs = GetTextCharset(hdc);
2993     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2994     DeleteObject(SelectObject(hdc, hfont));
2995
2996     memset(&lf, 0, sizeof(lf));
2997     lf.lfHeight = -13;
2998     lf.lfWeight = FW_DONTCARE;
2999     strcpy(lf.lfFaceName, "Times New Roman");
3000     hfont = CreateFontIndirectA(&lf);
3001     hfont = SelectObject(hdc, hfont);
3002     GetTextFaceA(hdc, sizeof(buf), buf);
3003     ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
3004     cs = GetTextCharset(hdc);
3005     ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
3006     DeleteObject(SelectObject(hdc, hfont));
3007
3008     for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
3009     {
3010         memset(&lf, 0, sizeof(lf));
3011         lf.lfHeight = -13;
3012         lf.lfWeight = FW_REGULAR;
3013         strcpy(lf.lfFaceName, font_subst[i].name);
3014         hfont = CreateFontIndirectA(&lf);
3015         hfont = SelectObject(hdc, hfont);
3016         cs = GetTextCharset(hdc);
3017         if (font_subst[i].charset == expected_cs)
3018         {
3019             ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3020             GetTextFaceA(hdc, sizeof(buf), buf);
3021             ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
3022         }
3023         else
3024         {
3025             ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
3026             GetTextFaceA(hdc, sizeof(buf), buf);
3027             ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
3028                !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
3029         }
3030         DeleteObject(SelectObject(hdc, hfont));
3031
3032         memset(&lf, 0, sizeof(lf));
3033         lf.lfHeight = -13;
3034         lf.lfWeight = FW_DONTCARE;
3035         strcpy(lf.lfFaceName, font_subst[i].name);
3036         hfont = CreateFontIndirectA(&lf);
3037         hfont = SelectObject(hdc, hfont);
3038         GetTextFaceA(hdc, sizeof(buf), buf);
3039         ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
3040            !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
3041            !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
3042            !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
3043            "got %s for font %s\n", buf, font_subst[i].name);
3044         cs = GetTextCharset(hdc);
3045         ok(cs == expected_cs || cs == ANSI_CHARSET, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
3046         DeleteObject(SelectObject(hdc, hfont));
3047     }
3048
3049     ReleaseDC(0, hdc);
3050 }
3051
3052 static void test_GdiRealizationInfo(void)
3053 {
3054     HDC hdc;
3055     DWORD info[4];
3056     BOOL r;
3057     HFONT hfont, hfont_old;
3058     LOGFONTA lf;
3059
3060     if(!pGdiRealizationInfo)
3061     {
3062         win_skip("GdiRealizationInfo not available\n");
3063         return;
3064     }
3065
3066     hdc = GetDC(0);
3067
3068     memset(info, 0xcc, sizeof(info));
3069     r = pGdiRealizationInfo(hdc, info);
3070     ok(r != 0, "ret 0\n");
3071     ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
3072     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3073
3074     if (!is_truetype_font_installed("Arial"))
3075     {
3076         skip("skipping GdiRealizationInfo with truetype font\n");
3077         goto end;
3078     }
3079
3080     memset(&lf, 0, sizeof(lf));
3081     strcpy(lf.lfFaceName, "Arial");
3082     lf.lfHeight = 20;
3083     lf.lfWeight = FW_NORMAL;
3084     hfont = CreateFontIndirectA(&lf);
3085     hfont_old = SelectObject(hdc, hfont);
3086
3087     memset(info, 0xcc, sizeof(info));
3088     r = pGdiRealizationInfo(hdc, info);
3089     ok(r != 0, "ret 0\n");
3090     ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
3091     ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3092
3093     DeleteObject(SelectObject(hdc, hfont_old));
3094
3095  end:
3096     ReleaseDC(0, hdc);
3097 }
3098
3099 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3100    the nul in the count of characters copied when the face name buffer is not
3101    NULL, whereas it does if the buffer is NULL.  Further, the Unicode version
3102    always includes it.  */
3103 static void test_GetTextFace(void)
3104 {
3105     static const char faceA[] = "Tahoma";
3106     static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
3107     LOGFONTA fA = {0};
3108     LOGFONTW fW = {0};
3109     char bufA[LF_FACESIZE];
3110     WCHAR bufW[LF_FACESIZE];
3111     HFONT f, g;
3112     HDC dc;
3113     int n;
3114
3115     if(!is_font_installed("Tahoma"))
3116     {
3117         skip("Tahoma is not installed so skipping this test\n");
3118         return;
3119     }
3120
3121     /* 'A' case.  */
3122     memcpy(fA.lfFaceName, faceA, sizeof faceA);
3123     f = CreateFontIndirectA(&fA);
3124     ok(f != NULL, "CreateFontIndirectA failed\n");
3125
3126     dc = GetDC(NULL);
3127     g = SelectObject(dc, f);
3128     n = GetTextFaceA(dc, sizeof bufA, bufA);
3129     ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
3130     ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
3131
3132     /* Play with the count arg.  */
3133     bufA[0] = 'x';
3134     n = GetTextFaceA(dc, 0, bufA);
3135     ok(n == 0, "GetTextFaceA returned %d\n", n);
3136     ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3137
3138     bufA[0] = 'x';
3139     n = GetTextFaceA(dc, 1, bufA);
3140     ok(n == 0, "GetTextFaceA returned %d\n", n);
3141     ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
3142
3143     bufA[0] = 'x'; bufA[1] = 'y';
3144     n = GetTextFaceA(dc, 2, bufA);
3145     ok(n == 1, "GetTextFaceA returned %d\n", n);
3146     ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
3147
3148     n = GetTextFaceA(dc, 0, NULL);
3149     ok(n == sizeof faceA ||
3150        broken(n == 0), /* win98, winMe */
3151        "GetTextFaceA returned %d\n", n);
3152
3153     DeleteObject(SelectObject(dc, g));
3154     ReleaseDC(NULL, dc);
3155
3156     /* 'W' case.  */
3157     memcpy(fW.lfFaceName, faceW, sizeof faceW);
3158     SetLastError(0xdeadbeef);
3159     f = CreateFontIndirectW(&fW);
3160     if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
3161     {
3162         win_skip("CreateFontIndirectW is not implemented\n");
3163         return;
3164     }
3165     ok(f != NULL, "CreateFontIndirectW failed\n");
3166
3167     dc = GetDC(NULL);
3168     g = SelectObject(dc, f);
3169     n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
3170     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3171     ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
3172
3173     /* Play with the count arg.  */
3174     bufW[0] = 'x';
3175     n = GetTextFaceW(dc, 0, bufW);
3176     ok(n == 0, "GetTextFaceW returned %d\n", n);
3177     ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3178
3179     bufW[0] = 'x';
3180     n = GetTextFaceW(dc, 1, bufW);
3181     ok(n == 1, "GetTextFaceW returned %d\n", n);
3182     ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
3183
3184     bufW[0] = 'x'; bufW[1] = 'y';
3185     n = GetTextFaceW(dc, 2, bufW);
3186     ok(n == 2, "GetTextFaceW returned %d\n", n);
3187     ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
3188
3189     n = GetTextFaceW(dc, 0, NULL);
3190     ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
3191
3192     DeleteObject(SelectObject(dc, g));
3193     ReleaseDC(NULL, dc);
3194 }
3195
3196 static void test_orientation(void)
3197 {
3198     static const char test_str[11] = "Test String";
3199     HDC hdc;
3200     LOGFONTA lf;
3201     HFONT hfont, old_hfont;
3202     SIZE size;
3203
3204     if (!is_truetype_font_installed("Arial"))
3205     {
3206         skip("Arial is not installed\n");
3207         return;
3208     }
3209
3210     hdc = CreateCompatibleDC(0);
3211     memset(&lf, 0, sizeof(lf));
3212     lstrcpyA(lf.lfFaceName, "Arial");
3213     lf.lfHeight = 72;
3214     lf.lfOrientation = lf.lfEscapement = 900;
3215     hfont = create_font("orientation", &lf);
3216     old_hfont = SelectObject(hdc, hfont);
3217     ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
3218     ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
3219     ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
3220     SelectObject(hdc, old_hfont);
3221     DeleteObject(hfont);
3222     DeleteDC(hdc);
3223 }
3224
3225 static void test_oemcharset(void)
3226 {
3227     HDC hdc;
3228     LOGFONTA lf, clf;
3229     HFONT hfont, old_hfont;
3230     int charset;
3231
3232     hdc = CreateCompatibleDC(0);
3233     ZeroMemory(&lf, sizeof(lf));
3234     lf.lfHeight = 12;
3235     lf.lfCharSet = OEM_CHARSET;
3236     lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
3237     lstrcpyA(lf.lfFaceName, "Terminal");
3238     hfont = CreateFontIndirectA(&lf);
3239     old_hfont = SelectObject(hdc, hfont);
3240     charset = GetTextCharset(hdc);
3241 todo_wine
3242     ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
3243     hfont = SelectObject(hdc, old_hfont);
3244     GetObjectA(hfont, sizeof(clf), &clf);
3245     ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
3246     ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
3247     ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
3248     ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
3249     DeleteObject(hfont);
3250     DeleteDC(hdc);
3251 }
3252
3253 static void test_GetGlyphOutline(void)
3254 {
3255     HDC hdc;
3256     GLYPHMETRICS gm, gm2;
3257     LOGFONTA lf;
3258     HFONT hfont, old_hfont;
3259     INT ret, ret2;
3260     static const struct
3261     {
3262         UINT cs;
3263         UINT a;
3264         UINT w;
3265     } c[] =
3266     {
3267         {ANSI_CHARSET, 0x30, 0x30},
3268         {SHIFTJIS_CHARSET, 0x82a0, 0x3042},
3269         {HANGEUL_CHARSET, 0x8141, 0xac02},
3270         {JOHAB_CHARSET, 0x8446, 0x3135},
3271         {GB2312_CHARSET, 0x8141, 0x4e04},
3272         {CHINESEBIG5_CHARSET, 0xa142, 0x3001}
3273     };
3274     UINT i;
3275
3276     if (!is_truetype_font_installed("Tahoma"))
3277     {
3278         skip("Tahoma is not installed\n");
3279         return;
3280     }
3281
3282     hdc = CreateCompatibleDC(0);
3283     memset(&lf, 0, sizeof(lf));
3284     lf.lfHeight = 72;
3285     lstrcpyA(lf.lfFaceName, "Tahoma");
3286     SetLastError(0xdeadbeef);
3287     hfont = CreateFontIndirectA(&lf);
3288     ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
3289     old_hfont = SelectObject(hdc, hfont);
3290
3291     memset(&gm, 0, sizeof(gm));
3292     SetLastError(0xdeadbeef);
3293     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3294     ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
3295
3296     memset(&gm, 0, sizeof(gm));
3297     SetLastError(0xdeadbeef);
3298     ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3299     ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
3300     ok(GetLastError() == 0xdeadbeef ||
3301        GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
3302        "expected 0xdeadbeef, got %u\n", GetLastError());
3303
3304     memset(&gm, 0, sizeof(gm));
3305     SetLastError(0xdeadbeef);
3306     ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
3307     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3308         ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
3309
3310     memset(&gm, 0, sizeof(gm));
3311     SetLastError(0xdeadbeef);
3312     ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
3313     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3314     {
3315        ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
3316        ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3317     }
3318
3319     /* test for needed buffer size request on space char */
3320     memset(&gm, 0, sizeof(gm));
3321     SetLastError(0xdeadbeef);
3322     ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3323     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3324         ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3325
3326     /* requesting buffer size for space char + error */
3327     memset(&gm, 0, sizeof(gm));
3328     SetLastError(0xdeadbeef);
3329     ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3330     if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3331     {
3332        ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3333        ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3334     }
3335
3336     SelectObject(hdc, old_hfont);
3337     DeleteObject(hfont);
3338
3339     for (i = 0; i < sizeof c / sizeof c[0]; ++i)
3340     {
3341         lf.lfFaceName[0] = '\0';
3342         lf.lfCharSet = c[i].cs;
3343         lf.lfPitchAndFamily = 0;
3344         if (EnumFontFamiliesEx(hdc, &lf, create_font_proc, (LPARAM)&hfont, 0))
3345         {
3346             skip("TrueType font for charset %u is not installed\n", c[i].cs);
3347             continue;
3348         }
3349
3350         old_hfont = SelectObject(hdc, hfont);
3351
3352         /* expected to ignore superfluous bytes (sigle-byte character) */
3353         ret = GetGlyphOutlineA(hdc, 0x8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3354         ret2 = GetGlyphOutlineA(hdc, 0x41, GGO_BITMAP, &gm2, 0, NULL, &mat);
3355         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3356
3357         ret = GetGlyphOutlineA(hdc, 0xcc8041, GGO_BITMAP, &gm, 0, NULL, &mat);
3358         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3359            "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3360
3361         /* expected to ignore superfluous bytes (double-byte character) */
3362         ret = GetGlyphOutlineA(hdc, c[i].a, GGO_BITMAP, &gm, 0, NULL, &mat);
3363         ret2 = GetGlyphOutlineA(hdc, c[i].a | 0xdead0000, GGO_BITMAP, &gm2, 0, NULL, &mat);
3364         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0,
3365            "Expected to ignore superfluous bytes, got %d %d\n", ret, ret2);
3366
3367         /* expected to match wide-char version results */
3368         ret2 = GetGlyphOutlineW(hdc, c[i].w, GGO_BITMAP, &gm2, 0, NULL, &mat);
3369         ok(ret == ret2 && memcmp(&gm, &gm2, sizeof gm) == 0, "%d %d\n", ret, ret2);
3370
3371         hfont = SelectObject(hdc, old_hfont);
3372         DeleteObject(hfont);
3373     }
3374
3375     DeleteDC(hdc);
3376 }
3377
3378 /* bug #9995: there is a limit to the character width that can be specified */
3379 static void test_GetTextMetrics2(const char *fontname, int font_height)
3380 {
3381     HFONT of, hf;
3382     HDC hdc;
3383     TEXTMETRICA tm;
3384     BOOL ret;
3385     int ave_width, height, width, ratio, scale;
3386
3387     if (!is_truetype_font_installed( fontname)) {
3388         skip("%s is not installed\n", fontname);
3389         return;
3390     }
3391     hdc = CreateCompatibleDC(0);
3392     ok( hdc != NULL, "CreateCompatibleDC failed\n");
3393     /* select width = 0 */
3394     hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3395             DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3396             DEFAULT_QUALITY, VARIABLE_PITCH,
3397             fontname);
3398     ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3399     of = SelectObject( hdc, hf);
3400     ret = GetTextMetricsA( hdc, &tm);
3401     ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3402     height = tm.tmHeight;
3403     ave_width = tm.tmAveCharWidth;
3404     SelectObject( hdc, of);
3405     DeleteObject( hf);
3406
3407     trace("height %d, ave width %d\n", height, ave_width);
3408
3409     for (width = ave_width * 2; /* nothing*/; width += ave_width)
3410     {
3411         hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3412                         DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3413                         DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3414         ok(hf != 0, "CreateFont failed\n");
3415         of = SelectObject(hdc, hf);
3416         ret = GetTextMetrics(hdc, &tm);
3417         ok(ret, "GetTextMetrics error %u\n", GetLastError());
3418         SelectObject(hdc, of);
3419         DeleteObject(hf);
3420
3421         if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3422             break;
3423     }
3424
3425     DeleteDC(hdc);
3426
3427     ratio = width / height;
3428     scale = width / ave_width;
3429
3430     trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3431           width, height, ratio, width, ave_width, scale);
3432
3433     ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3434 }
3435
3436 static void test_CreateFontIndirect(void)
3437 {
3438     LOGFONTA lf, getobj_lf;
3439     int ret, i;
3440     HFONT hfont;
3441     char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3442
3443     memset(&lf, 0, sizeof(lf));
3444     lf.lfCharSet = ANSI_CHARSET;
3445     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3446     lf.lfHeight = 16;
3447     lf.lfWidth = 16;
3448     lf.lfQuality = DEFAULT_QUALITY;
3449     lf.lfItalic = FALSE;
3450     lf.lfWeight = FW_DONTCARE;
3451
3452     for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3453     {
3454         lstrcpyA(lf.lfFaceName, TestName[i]);
3455         hfont = CreateFontIndirectA(&lf);
3456         ok(hfont != 0, "CreateFontIndirectA failed\n");
3457         SetLastError(0xdeadbeef);
3458         ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3459         ok(ret, "GetObject failed: %d\n", GetLastError());
3460         ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3461         ok(lf.lfWeight == getobj_lf.lfWeight ||
3462            broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3463            "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3464         ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3465            broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3466            "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3467         DeleteObject(hfont);
3468     }
3469 }
3470
3471 static void test_CreateFontIndirectEx(void)
3472 {
3473     ENUMLOGFONTEXDVA lfex;
3474     HFONT hfont;
3475
3476     if (!pCreateFontIndirectExA)
3477     {
3478         win_skip("CreateFontIndirectExA is not available\n");
3479         return;
3480     }
3481
3482     if (!is_truetype_font_installed("Arial"))
3483     {
3484         skip("Arial is not installed\n");
3485         return;
3486     }
3487
3488     SetLastError(0xdeadbeef);
3489     hfont = pCreateFontIndirectExA(NULL);
3490     ok(hfont == NULL, "got %p\n", hfont);
3491     ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3492
3493     memset(&lfex, 0, sizeof(lfex));
3494     lstrcpyA(lfex.elfEnumLogfontEx.elfLogFont.lfFaceName, "Arial");
3495     hfont = pCreateFontIndirectExA(&lfex);
3496     ok(hfont != 0, "CreateFontIndirectEx failed\n");
3497     if (hfont)
3498         check_font("Arial", &lfex.elfEnumLogfontEx.elfLogFont, hfont);
3499     DeleteObject(hfont);
3500 }
3501
3502 static void free_font(void *font)
3503 {
3504     UnmapViewOfFile(font);
3505 }
3506
3507 static void *load_font(const char *font_name, DWORD *font_size)
3508 {
3509     char file_name[MAX_PATH];
3510     HANDLE file, mapping;
3511     void *font;
3512
3513     if (!GetWindowsDirectory(file_name, sizeof(file_name))) return NULL;
3514     strcat(file_name, "\\fonts\\");
3515     strcat(file_name, font_name);
3516
3517     file = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
3518     if (file == INVALID_HANDLE_VALUE) return NULL;
3519
3520     *font_size = GetFileSize(file, NULL);
3521
3522     mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
3523     if (!mapping)
3524     {
3525         CloseHandle(file);
3526         return NULL;
3527     }
3528
3529     font = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
3530
3531     CloseHandle(file);
3532     CloseHandle(mapping);
3533     return font;
3534 }
3535
3536 static void test_AddFontMemResource(void)
3537 {
3538     void *font;
3539     DWORD font_size, num_fonts;
3540     HANDLE ret;
3541     BOOL bRet;
3542
3543     if (!pAddFontMemResourceEx || !pRemoveFontMemResourceEx)
3544     {
3545         win_skip("AddFontMemResourceEx is not available on this platform\n");
3546         return;
3547     }
3548
3549     font = load_font("sserife.fon", &font_size);
3550     if (!font)
3551     {
3552         skip("Unable to locate and load font sserife.fon\n");
3553         return;
3554     }
3555
3556     SetLastError(0xdeadbeef);
3557     ret = pAddFontMemResourceEx(NULL, 0, NULL, NULL);
3558     ok(!ret, "AddFontMemResourceEx should fail\n");
3559     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3560        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3561        GetLastError());
3562
3563     SetLastError(0xdeadbeef);
3564     ret = pAddFontMemResourceEx(NULL, 10, NULL, NULL);
3565     ok(!ret, "AddFontMemResourceEx should fail\n");
3566     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3567        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3568        GetLastError());
3569
3570     SetLastError(0xdeadbeef);
3571     ret = pAddFontMemResourceEx(NULL, 0, NULL, &num_fonts);
3572     ok(!ret, "AddFontMemResourceEx should fail\n");
3573     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3574        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3575        GetLastError());
3576
3577     SetLastError(0xdeadbeef);
3578     ret = pAddFontMemResourceEx(NULL, 10, NULL, &num_fonts);
3579     ok(!ret, "AddFontMemResourceEx should fail\n");
3580     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3581        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3582        GetLastError());
3583
3584     SetLastError(0xdeadbeef);
3585     ret = pAddFontMemResourceEx(font, 0, NULL, NULL);
3586     ok(!ret, "AddFontMemResourceEx should fail\n");
3587     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3588        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3589        GetLastError());
3590
3591     SetLastError(0xdeadbeef);
3592     ret = pAddFontMemResourceEx(font, 10, NULL, NULL);
3593     ok(!ret, "AddFontMemResourceEx should fail\n");
3594     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3595        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3596        GetLastError());
3597
3598     num_fonts = 0xdeadbeef;
3599     SetLastError(0xdeadbeef);
3600     ret = pAddFontMemResourceEx(font, 0, NULL, &num_fonts);
3601     ok(!ret, "AddFontMemResourceEx should fail\n");
3602     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3603        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3604        GetLastError());
3605     ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3606
3607     if (0) /* hangs under windows 2000 */
3608     {
3609         num_fonts = 0xdeadbeef;
3610         SetLastError(0xdeadbeef);
3611         ret = pAddFontMemResourceEx(font, 10, NULL, &num_fonts);
3612         ok(!ret, "AddFontMemResourceEx should fail\n");
3613         ok(GetLastError() == 0xdeadbeef,
3614            "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3615            GetLastError());
3616         ok(num_fonts == 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3617     }
3618
3619     num_fonts = 0xdeadbeef;
3620     SetLastError(0xdeadbeef);
3621     ret = pAddFontMemResourceEx(font, font_size, NULL, &num_fonts);
3622     ok(ret != 0, "AddFontMemResourceEx error %d\n", GetLastError());
3623     ok(num_fonts != 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3624     ok(num_fonts != 0, "number of loaded fonts should not be 0\n");
3625
3626     free_font(font);
3627
3628     SetLastError(0xdeadbeef);
3629     bRet = pRemoveFontMemResourceEx(ret);
3630     ok(bRet, "RemoveFontMemResourceEx error %d\n", GetLastError());
3631
3632     /* test invalid pointer to number of loaded fonts */
3633     font = load_font("sserife.fon", &font_size);
3634     ok(font != NULL, "Unable to locate and load font sserife.fon\n");
3635
3636     SetLastError(0xdeadbeef);
3637     ret = pAddFontMemResourceEx(font, font_size, NULL, (void *)0xdeadbeef);
3638     ok(!ret, "AddFontMemResourceEx should fail\n");
3639     ok(GetLastError() == 0xdeadbeef,
3640        "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3641        GetLastError());
3642
3643     SetLastError(0xdeadbeef);
3644     ret = pAddFontMemResourceEx(font, font_size, NULL, NULL);
3645     ok(!ret, "AddFontMemResourceEx should fail\n");
3646     ok(GetLastError() == ERROR_INVALID_PARAMETER,
3647        "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3648        GetLastError());
3649
3650     free_font(font);
3651 }
3652
3653 static INT CALLBACK enum_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3654 {
3655     LOGFONT *lf;
3656
3657     if (type != TRUETYPE_FONTTYPE) return 1;
3658
3659     ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3660
3661     lf = (LOGFONT *)lparam;
3662     *lf = *elf;
3663     return 0;
3664 }
3665
3666 static INT CALLBACK enum_all_fonts_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lparam)
3667 {
3668     int ret;
3669     LOGFONT *lf;
3670
3671     if (type != TRUETYPE_FONTTYPE) return 1;
3672
3673     lf = (LOGFONT *)lparam;
3674     ret = strcmp(lf->lfFaceName, elf->lfFaceName);
3675     if(ret == 0)
3676     {
3677         ok(ntm->tmWeight == elf->lfWeight, "expected %d got %d\n", ntm->tmWeight, elf->lfWeight);
3678         *lf = *elf;
3679         return 0;
3680     }
3681     return 1;
3682 }
3683
3684 static void test_EnumFonts(void)
3685 {
3686     int ret;
3687     LOGFONT lf;
3688     HDC hdc;
3689
3690     if (!is_truetype_font_installed("Arial"))
3691     {
3692         skip("Arial is not installed\n");
3693         return;
3694     }
3695
3696     /* Windows uses localized font face names, so Arial Bold won't be found */
3697     if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
3698     {
3699         skip("User locale is not English, skipping the test\n");
3700         return;
3701     }
3702
3703     hdc = CreateCompatibleDC(0);
3704
3705     ret = EnumFontFamilies(hdc, "Arial", enum_fonts_proc, (LPARAM)&lf);
3706     ok(!ret, "font Arial is not enumerated\n");
3707     ret = strcmp(lf.lfFaceName, "Arial");
3708     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3709     ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3710
3711     lstrcpy(lf.lfFaceName, "Arial");
3712     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3713     ok(!ret, "font Arial is not enumerated\n");
3714     ret = strcmp(lf.lfFaceName, "Arial");
3715     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3716     ok(lf.lfWeight == FW_NORMAL, "expected FW_NORMAL got %d\n", lf.lfWeight);
3717
3718     ret = EnumFontFamilies(hdc, "Arial Bold", enum_fonts_proc, (LPARAM)&lf);
3719     ok(!ret, "font Arial Bold is not enumerated\n");
3720     ret = strcmp(lf.lfFaceName, "Arial");
3721     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3722     ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3723
3724     lstrcpy(lf.lfFaceName, "Arial Bold");
3725     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3726     ok(ret, "font Arial Bold should not be enumerated\n");
3727
3728     ret = EnumFontFamilies(hdc, "Arial Bold Italic", enum_fonts_proc, (LPARAM)&lf);
3729     ok(!ret, "font Arial Bold Italic is not enumerated\n");
3730     ret = strcmp(lf.lfFaceName, "Arial");
3731     ok(!ret, "expected Arial got %s\n", lf.lfFaceName);
3732     ok(lf.lfWeight == FW_BOLD, "expected FW_BOLD got %d\n", lf.lfWeight);
3733
3734     lstrcpy(lf.lfFaceName, "Arial Bold Italic");
3735     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3736     ok(ret, "font Arial Bold Italic should not be enumerated\n");
3737
3738     ret = EnumFontFamilies(hdc, "Arial Italic Bold", enum_fonts_proc, (LPARAM)&lf);
3739     ok(ret, "font Arial Italic Bold  should not be enumerated\n");
3740
3741     lstrcpy(lf.lfFaceName, "Arial Italic Bold");
3742     ret = EnumFontFamilies(hdc, NULL, enum_all_fonts_proc, (LPARAM)&lf);
3743     ok(ret, "font Arial Italic Bold should not be enumerated\n");
3744
3745     DeleteDC(hdc);
3746 }
3747
3748 static INT CALLBACK is_font_installed_fullname_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
3749 {
3750     const ENUMLOGFONT *elf = (const ENUMLOGFONT *)lf;
3751     const char *fullname = (const char *)lParam;
3752
3753     if (!strcmp((const char *)elf->elfFullName, fullname)) return 0;
3754
3755     return 1;
3756 }
3757
3758 static BOOL is_font_installed_fullname(const char *family, const char *fullname)
3759 {
3760     HDC hdc = GetDC(0);
3761     BOOL ret = FALSE;
3762
3763     if(!EnumFontFamiliesA(hdc, family, is_font_installed_fullname_proc, (LPARAM)fullname))
3764         ret = TRUE;
3765
3766     ReleaseDC(0, hdc);
3767     return ret;
3768 }
3769
3770 static void test_fullname(void)
3771 {
3772     static const char *TestName[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
3773     char buf[LF_FULLFACESIZE];
3774     HFONT hfont, of;
3775     LOGFONTA lf;
3776     HDC hdc;
3777     int i;
3778
3779     hdc = CreateCompatibleDC(0);
3780     ok(hdc != NULL, "CreateCompatibleDC failed\n");
3781
3782     memset(&lf, 0, sizeof(lf));
3783     lf.lfCharSet = ANSI_CHARSET;
3784     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3785     lf.lfHeight = 16;
3786     lf.lfWidth = 16;
3787     lf.lfQuality = DEFAULT_QUALITY;
3788     lf.lfItalic = FALSE;
3789     lf.lfWeight = FW_DONTCARE;
3790
3791     for (i = 0; i < sizeof(TestName) / sizeof(TestName[0]); i++)
3792     {
3793         if (!is_font_installed_fullname("Lucida Sans", TestName[i]))
3794         {
3795             skip("%s is not installed\n", TestName[i]);
3796             continue;
3797         }
3798
3799         lstrcpyA(lf.lfFaceName, TestName[i]);
3800         hfont = CreateFontIndirectA(&lf);
3801         ok(hfont != 0, "CreateFontIndirectA failed\n");
3802
3803         of = SelectObject(hdc, hfont);
3804         buf[0] = 0;
3805         ok(get_ttf_nametable_entry(hdc, TT_NAME_ID_FULL_NAME, buf, sizeof(buf)),
3806            "face full name could not be read\n");
3807         ok(!lstrcmpA(buf, TestName[i]), "font full names don't match: %s != %s\n", TestName[i], buf);
3808         SelectObject(hdc, of);
3809         DeleteObject(hfont);
3810     }
3811     DeleteDC(hdc);
3812 }
3813
3814 static BOOL write_ttf_file(char *tmp_name)
3815 {
3816     char tmp_path[MAX_PATH];
3817     HRSRC rsrc;
3818     void *rsrc_data;
3819     DWORD rsrc_size;
3820     HANDLE hfile;
3821     BOOL ret;
3822
3823     SetLastError(0xdeadbeef);
3824     rsrc = FindResource(GetModuleHandle(0), "wine_test.ttf", RT_RCDATA);
3825     ok(rsrc != 0, "FindResource error %d\n", GetLastError());
3826     if (!rsrc) return FALSE;
3827     SetLastError(0xdeadbeef);
3828     rsrc_data = LockResource(LoadResource(GetModuleHandle(0), rsrc));
3829     ok(rsrc_data != 0, "LockResource error %d\n", GetLastError());
3830     if (!rsrc_data) return FALSE;
3831     SetLastError(0xdeadbeef);
3832     rsrc_size = SizeofResource(GetModuleHandle(0), rsrc);
3833     ok(rsrc_size != 0, "SizeofResource error %d\n", GetLastError());
3834     if (!rsrc_size) return FALSE;
3835
3836     SetLastError(0xdeadbeef);
3837     ret = GetTempPath(MAX_PATH, tmp_path);
3838     ok(ret, "GetTempPath() error %d\n", GetLastError());
3839     SetLastError(0xdeadbeef);
3840     ret = GetTempFileName(tmp_path, "ttf", 0, tmp_name);
3841     ok(ret, "GetTempFileName() error %d\n", GetLastError());
3842
3843     SetLastError(0xdeadbeef);
3844     hfile = CreateFile(tmp_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
3845     ok(hfile != INVALID_HANDLE_VALUE, "CreateFile() error %d\n", GetLastError());
3846     if (hfile == INVALID_HANDLE_VALUE) return FALSE;
3847
3848     SetLastError(0xdeadbeef);
3849     ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL);
3850     ok(ret, "WriteFile() error %d\n", GetLastError());
3851
3852     CloseHandle(hfile);
3853     return ret;
3854 }
3855
3856 static void test_CreateScalableFontResource(void)
3857 {
3858     char ttf_name[MAX_PATH];
3859     char tmp_path[MAX_PATH];
3860     char fot_name[MAX_PATH];
3861     char *file_part;
3862     DWORD ret;
3863
3864     if (!pAddFontResourceExA || !pRemoveFontResourceExA)
3865     {
3866         win_skip("AddFontResourceExA is not available on this platform\n");
3867         return;
3868     }
3869
3870     if (!write_ttf_file(ttf_name))
3871     {
3872         skip("Failed to create ttf file for testing\n");
3873         return;
3874     }
3875
3876     trace("created %s\n", ttf_name);
3877
3878     ret = is_truetype_font_installed("wine_test");
3879     ok(!ret, "font wine_test should not be enumerated\n");
3880
3881     ret = GetTempPath(MAX_PATH, tmp_path);
3882     ok(ret, "GetTempPath() error %d\n", GetLastError());
3883     ret = GetTempFileName(tmp_path, "fot", 0, fot_name);
3884     ok(ret, "GetTempFileName() error %d\n", GetLastError());
3885
3886     ret = GetFileAttributes(fot_name);
3887     ok(ret != INVALID_FILE_ATTRIBUTES, "file %s does not exist\n", fot_name);
3888
3889     SetLastError(0xdeadbeef);
3890     ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3891     ok(!ret, "CreateScalableFontResource() should fail\n");
3892     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3893
3894     SetLastError(0xdeadbeef);
3895     ret = CreateScalableFontResource(0, fot_name, ttf_name, "");
3896     ok(!ret, "CreateScalableFontResource() should fail\n");
3897     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3898
3899     file_part = strrchr(ttf_name, '\\');
3900     SetLastError(0xdeadbeef);
3901     ret = CreateScalableFontResource(0, fot_name, file_part, tmp_path);
3902     ok(!ret, "CreateScalableFontResource() should fail\n");
3903     ok(GetLastError() == ERROR_FILE_EXISTS, "not expected error %d\n", GetLastError());
3904
3905     SetLastError(0xdeadbeef);
3906     ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path);
3907     ok(!ret, "CreateScalableFontResource() should fail\n");
3908 todo_wine
3909     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3910
3911     SetLastError(0xdeadbeef);
3912     ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name);
3913     ok(!ret, "CreateScalableFontResource() should fail\n");
3914 todo_wine
3915     ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError());
3916
3917     ret = DeleteFile(fot_name);
3918     ok(ret, "DeleteFile() error %d\n", GetLastError());
3919
3920     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3921 todo_wine
3922     ok(!ret, "RemoveFontResourceEx() should fail\n");
3923
3924     /* FIXME: since CreateScalableFontResource is a stub further testing is impossible */
3925     if (ret) return;
3926
3927     /* test public font resource */
3928     SetLastError(0xdeadbeef);
3929     ret = CreateScalableFontResource(0, fot_name, ttf_name, NULL);
3930     ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3931
3932     ret = is_truetype_font_installed("wine_test");
3933     ok(!ret, "font wine_test should not be enumerated\n");
3934
3935     SetLastError(0xdeadbeef);
3936     ret = pAddFontResourceExA(fot_name, 0, 0);
3937     ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3938
3939     ret = is_truetype_font_installed("wine_test");
3940     ok(ret, "font wine_test should be enumerated\n");
3941
3942     ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3943     ok(!ret, "RemoveFontResourceEx() with not matching flags should fail\n");
3944
3945     SetLastError(0xdeadbeef);
3946     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3947 todo_wine
3948     ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3949
3950     ret = is_truetype_font_installed("wine_test");
3951 todo_wine
3952     ok(!ret, "font wine_test should not be enumerated\n");
3953
3954     /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
3955     if (ret)
3956     {
3957         /* remove once RemoveFontResource is implemented */
3958         DeleteFile(fot_name);
3959         DeleteFile(ttf_name);
3960         return;
3961     }
3962
3963     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3964     ok(!ret, "RemoveFontResourceEx() should fail\n");
3965
3966     DeleteFile(fot_name);
3967
3968     /* test hidden font resource */
3969     SetLastError(0xdeadbeef);
3970     ret = CreateScalableFontResource(1, fot_name, ttf_name, NULL);
3971     ok(ret, "CreateScalableFontResource() error %d\n", GetLastError());
3972
3973     ret = is_truetype_font_installed("wine_test");
3974     ok(!ret, "font wine_test should not be enumerated\n");
3975
3976     SetLastError(0xdeadbeef);
3977     ret = pAddFontResourceExA(fot_name, 0, 0);
3978     ok(ret, "AddFontResourceEx() error %d\n", GetLastError());
3979
3980     ret = is_truetype_font_installed("wine_test");
3981     ok(!ret, "font wine_test should not be enumerated\n");
3982
3983     /* XP allows removing a private font added with 0 flags */
3984     SetLastError(0xdeadbeef);
3985     ret = pRemoveFontResourceExA(fot_name, FR_PRIVATE, 0);
3986     ok(ret, "RemoveFontResourceEx() error %d\n", GetLastError());
3987
3988     ret = is_truetype_font_installed("wine_test");
3989     ok(!ret, "font wine_test should not be enumerated\n");
3990
3991     ret = pRemoveFontResourceExA(fot_name, 0, 0);
3992     ok(!ret, "RemoveFontResourceEx() should fail\n");
3993
3994     DeleteFile(fot_name);
3995     DeleteFile(ttf_name);
3996 }
3997
3998 START_TEST(font)
3999 {
4000     init();
4001
4002     test_logfont();
4003     test_bitmap_font();
4004     test_outline_font();
4005     test_bitmap_font_metrics();
4006     test_GdiGetCharDimensions();
4007     test_GetCharABCWidths();
4008     test_text_extents();
4009     test_GetGlyphIndices();
4010     test_GetKerningPairs();
4011     test_GetOutlineTextMetrics();
4012     test_SetTextJustification();
4013     test_font_charset();
4014     test_GetFontUnicodeRanges();
4015     test_nonexistent_font();
4016     test_orientation();
4017     test_height_selection();
4018     test_AddFontMemResource();
4019     test_EnumFonts();
4020
4021     /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4022      * I'd like to avoid them in this test.
4023      */
4024     test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
4025     test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
4026     if (is_truetype_font_installed("Arial Black") &&
4027         (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4028     {
4029         test_EnumFontFamilies("", ANSI_CHARSET);
4030         test_EnumFontFamilies("", SYMBOL_CHARSET);
4031         test_EnumFontFamilies("", DEFAULT_CHARSET);
4032     }
4033     else
4034         skip("Arial Black or Symbol/Wingdings is not installed\n");
4035     test_EnumFontFamiliesEx_default_charset();
4036     test_GetTextMetrics();
4037     test_GdiRealizationInfo();
4038     test_GetTextFace();
4039     test_GetGlyphOutline();
4040     test_GetTextMetrics2("Tahoma", -11);
4041     test_GetTextMetrics2("Tahoma", -55);
4042     test_GetTextMetrics2("Tahoma", -110);
4043     test_GetTextMetrics2("Arial", -11);
4044     test_GetTextMetrics2("Arial", -55);
4045     test_GetTextMetrics2("Arial", -110);
4046     test_CreateFontIndirect();
4047     test_CreateFontIndirectEx();
4048     test_oemcharset();
4049     test_fullname();
4050
4051     /* CreateScalableFontResource should be last test until RemoveFontResource
4052      * is properly implemented.
4053      */
4054     test_CreateScalableFontResource();
4055 }