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