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