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