2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
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.
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.
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
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
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)
39 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
40 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
41 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
42 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
43 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
44 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
45 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
47 static HMODULE hgdi32 = 0;
49 static void init(void)
51 hgdi32 = GetModuleHandleA("gdi32.dll");
53 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
54 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
55 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
56 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
57 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
58 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
59 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
62 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
64 if (type != TRUETYPE_FONTTYPE) return 1;
69 static BOOL is_truetype_font_installed(const char *name)
74 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
81 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
86 static BOOL is_font_installed(const char *name)
91 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
98 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
106 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
107 /* NT4 tries to be clever and only returns the minimum length */
108 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
110 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
111 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
112 ok(lf->lfHeight == getobj_lf.lfHeight ||
113 broken((SHORT)lf->lfHeight == getobj_lf.lfHeight), /* win9x */
114 "lfHeight: expect %08x got %08x\n", lf->lfHeight, getobj_lf.lfHeight);
115 ok(lf->lfWidth == getobj_lf.lfWidth ||
116 broken((SHORT)lf->lfWidth == getobj_lf.lfWidth), /* win9x */
117 "lfWidth: expect %08x got %08x\n", lf->lfWidth, getobj_lf.lfWidth);
118 ok(lf->lfEscapement == getobj_lf.lfEscapement ||
119 broken((SHORT)lf->lfEscapement == getobj_lf.lfEscapement), /* win9x */
120 "lfEscapement: expect %08x got %08x\n", lf->lfEscapement, getobj_lf.lfEscapement);
121 ok(lf->lfOrientation == getobj_lf.lfOrientation ||
122 broken((SHORT)lf->lfOrientation == getobj_lf.lfOrientation), /* win9x */
123 "lfOrientation: expect %08x got %08x\n", lf->lfOrientation, getobj_lf.lfOrientation);
124 ok(lf->lfWeight == getobj_lf.lfWeight ||
125 broken((SHORT)lf->lfWeight == getobj_lf.lfWeight), /* win9x */
126 "lfWeight: expect %08x got %08x\n", lf->lfWeight, getobj_lf.lfWeight);
127 ok(lf->lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf->lfItalic, getobj_lf.lfItalic);
128 ok(lf->lfUnderline == getobj_lf.lfUnderline, "lfUnderline: expect %02x got %02x\n", lf->lfUnderline, getobj_lf.lfUnderline);
129 ok(lf->lfStrikeOut == getobj_lf.lfStrikeOut, "lfStrikeOut: expect %02x got %02x\n", lf->lfStrikeOut, getobj_lf.lfStrikeOut);
130 ok(lf->lfCharSet == getobj_lf.lfCharSet, "lfCharSet: expect %02x got %02x\n", lf->lfCharSet, getobj_lf.lfCharSet);
131 ok(lf->lfOutPrecision == getobj_lf.lfOutPrecision, "lfOutPrecision: expect %02x got %02x\n", lf->lfOutPrecision, getobj_lf.lfOutPrecision);
132 ok(lf->lfClipPrecision == getobj_lf.lfClipPrecision, "lfClipPrecision: expect %02x got %02x\n", lf->lfClipPrecision, getobj_lf.lfClipPrecision);
133 ok(lf->lfQuality == getobj_lf.lfQuality, "lfQuality: expect %02x got %02x\n", lf->lfQuality, getobj_lf.lfQuality);
134 ok(lf->lfPitchAndFamily == getobj_lf.lfPitchAndFamily, "lfPitchAndFamily: expect %02x got %02x\n", lf->lfPitchAndFamily, getobj_lf.lfPitchAndFamily);
135 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName) ||
136 broken(!memcmp(lf->lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
137 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
140 static HFONT create_font(const char* test, const LOGFONTA* lf)
142 HFONT hfont = CreateFontIndirectA(lf);
143 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
145 check_font(test, lf, hfont);
149 static void test_logfont(void)
154 memset(&lf, 0, sizeof lf);
156 lf.lfCharSet = ANSI_CHARSET;
157 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
158 lf.lfWeight = FW_DONTCARE;
161 lf.lfQuality = DEFAULT_QUALITY;
163 lstrcpyA(lf.lfFaceName, "Arial");
164 hfont = create_font("Arial", &lf);
167 memset(&lf, 'A', sizeof(lf));
168 hfont = CreateFontIndirectA(&lf);
169 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
171 lf.lfFaceName[LF_FACESIZE - 1] = 0;
172 check_font("AAA...", &lf, hfont);
176 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
178 if (type & RASTER_FONTTYPE)
180 LOGFONT *lf = (LOGFONT *)lParam;
182 return 0; /* stop enumeration */
185 return 1; /* continue enumeration */
188 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
190 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
191 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
192 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
193 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
194 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
195 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
196 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
197 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
198 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
199 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
200 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
201 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
202 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
203 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
204 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
205 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
206 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
207 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
208 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
209 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
212 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
213 LONG lfWidth, const char *test_str,
214 INT test_str_len, const TEXTMETRICA *tm_orig,
215 const SIZE *size_orig, INT width_of_A_orig,
216 INT scale_x, INT scale_y)
219 OUTLINETEXTMETRIC otm;
222 INT width_of_A, cx, cy;
228 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
230 GetObjectA(hfont, sizeof(lf), &lf);
232 if (GetOutlineTextMetricsA(hdc, 0, NULL))
234 otm.otmSize = sizeof(otm) / 2;
235 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
236 ok(ret == sizeof(otm)/2 /* XP */ ||
237 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
239 memset(&otm, 0x1, sizeof(otm));
240 otm.otmSize = sizeof(otm);
241 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
242 ok(ret == sizeof(otm) /* XP */ ||
243 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
245 memset(&tm, 0x2, sizeof(tm));
246 ret = GetTextMetricsA(hdc, &tm);
247 ok(ret, "GetTextMetricsA failed\n");
248 /* the structure size is aligned */
249 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
251 ok(0, "tm != otm\n");
252 compare_tm(&tm, &otm.otmTextMetrics);
255 tm = otm.otmTextMetrics;
256 if (0) /* these metrics are scaled too, but with rounding errors */
258 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
259 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
261 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
262 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
263 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
264 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
265 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
266 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
270 ret = GetTextMetricsA(hdc, &tm);
271 ok(ret, "GetTextMetricsA failed\n");
274 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
275 cy = tm.tmHeight / tm_orig->tmHeight;
276 ok(cx == scale_x && cy == scale_y, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
277 lfHeight, scale_x, scale_y, cx, cy);
278 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
279 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
280 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
281 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
282 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
284 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
288 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
291 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
293 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
295 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
296 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
298 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
300 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
303 /* Test how GDI scales bitmap font metrics */
304 static void test_bitmap_font(void)
306 static const char test_str[11] = "Test String";
309 HFONT hfont, old_hfont;
312 INT ret, i, width_orig, height_orig, scale, lfWidth;
316 /* "System" has only 1 pixel size defined, otherwise the test breaks */
317 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
321 trace("no bitmap fonts were found, skipping the test\n");
325 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
327 height_orig = bitmap_lf.lfHeight;
328 lfWidth = bitmap_lf.lfWidth;
330 hfont = create_font("bitmap", &bitmap_lf);
331 old_hfont = SelectObject(hdc, hfont);
332 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
333 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
334 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
335 SelectObject(hdc, old_hfont);
338 bitmap_lf.lfHeight = 0;
339 bitmap_lf.lfWidth = 4;
340 hfont = create_font("bitmap", &bitmap_lf);
341 old_hfont = SelectObject(hdc, hfont);
342 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
343 SelectObject(hdc, old_hfont);
346 bitmap_lf.lfHeight = height_orig;
347 bitmap_lf.lfWidth = lfWidth;
349 /* test fractional scaling */
350 for (i = 1; i <= height_orig * 6; i++)
354 bitmap_lf.lfHeight = i;
355 hfont = create_font("fractional", &bitmap_lf);
356 scale = (i + height_orig - 1) / height_orig;
357 nearest_height = scale * height_orig;
358 /* Only jump to the next height if the difference <= 25% original height */
359 if (scale > 2 && nearest_height - i > height_orig / 4) scale--;
360 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
361 so we'll not test this particular height. */
362 else if(scale == 2 && nearest_height - i == (height_orig / 4)) continue;
363 else if(scale == 2 && nearest_height - i > (height_orig / 4 - 1)) scale--;
364 old_hfont = SelectObject(hdc, hfont);
365 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
366 SelectObject(hdc, old_hfont);
370 /* test integer scaling 3x2 */
371 bitmap_lf.lfHeight = height_orig * 2;
372 bitmap_lf.lfWidth *= 3;
373 hfont = create_font("3x2", &bitmap_lf);
374 old_hfont = SelectObject(hdc, hfont);
375 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
376 SelectObject(hdc, old_hfont);
379 /* test integer scaling 3x3 */
380 bitmap_lf.lfHeight = height_orig * 3;
381 bitmap_lf.lfWidth = 0;
382 hfont = create_font("3x3", &bitmap_lf);
383 old_hfont = SelectObject(hdc, hfont);
384 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
385 SelectObject(hdc, old_hfont);
391 /* Test how GDI scales outline font metrics */
392 static void test_outline_font(void)
394 static const char test_str[11] = "Test String";
397 HFONT hfont, old_hfont, old_hfont_2;
398 OUTLINETEXTMETRICA otm;
400 INT width_orig, height_orig, lfWidth;
403 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
404 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
408 if (!is_truetype_font_installed("Arial"))
410 skip("Arial is not installed\n");
414 hdc = CreateCompatibleDC(0);
416 memset(&lf, 0, sizeof(lf));
417 strcpy(lf.lfFaceName, "Arial");
419 hfont = create_font("outline", &lf);
420 old_hfont = SelectObject(hdc, hfont);
421 otm.otmSize = sizeof(otm);
422 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
423 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
424 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
426 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
427 SelectObject(hdc, old_hfont);
430 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
431 lf.lfHeight = otm.otmEMSquare;
432 lf.lfHeight = -lf.lfHeight;
433 hfont = create_font("outline", &lf);
434 old_hfont = SelectObject(hdc, hfont);
435 otm.otmSize = sizeof(otm);
436 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
437 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
438 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
439 SelectObject(hdc, old_hfont);
442 height_orig = otm.otmTextMetrics.tmHeight;
443 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
445 /* test integer scaling 3x2 */
446 lf.lfHeight = height_orig * 2;
447 lf.lfWidth = lfWidth * 3;
448 hfont = create_font("3x2", &lf);
449 old_hfont = SelectObject(hdc, hfont);
450 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
451 SelectObject(hdc, old_hfont);
454 /* test integer scaling 3x3 */
455 lf.lfHeight = height_orig * 3;
456 lf.lfWidth = lfWidth * 3;
457 hfont = create_font("3x3", &lf);
458 old_hfont = SelectObject(hdc, hfont);
459 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
460 SelectObject(hdc, old_hfont);
463 /* test integer scaling 1x1 */
464 lf.lfHeight = height_orig * 1;
465 lf.lfWidth = lfWidth * 1;
466 hfont = create_font("1x1", &lf);
467 old_hfont = SelectObject(hdc, hfont);
468 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
469 SelectObject(hdc, old_hfont);
472 /* test integer scaling 1x1 */
473 lf.lfHeight = height_orig;
475 hfont = create_font("1x1", &lf);
476 old_hfont = SelectObject(hdc, hfont);
477 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
479 /* with an identity matrix */
480 memset(&gm, 0, sizeof(gm));
481 SetLastError(0xdeadbeef);
482 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
483 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
484 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
485 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
486 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
487 /* with a custom matrix */
488 memset(&gm, 0, sizeof(gm));
489 SetLastError(0xdeadbeef);
490 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
491 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
492 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
493 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
494 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
496 /* Test that changing the DC transformation affects only the font
497 * selected on this DC and doesn't affect the same font selected on
500 hdc_2 = CreateCompatibleDC(0);
501 old_hfont_2 = SelectObject(hdc_2, hfont);
502 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
504 SetMapMode(hdc, MM_ANISOTROPIC);
506 /* font metrics on another DC should be unchanged */
507 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
509 /* test restrictions of compatibility mode GM_COMPATIBLE */
510 /* part 1: rescaling only X should not change font scaling on screen.
511 So compressing the X axis by 2 is not done, and this
512 appears as X scaling of 2 that no one requested. */
513 SetWindowExtEx(hdc, 100, 100, NULL);
514 SetViewportExtEx(hdc, 50, 100, NULL);
515 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
516 /* font metrics on another DC should be unchanged */
517 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
519 /* part 2: rescaling only Y should change font scaling.
520 As also X is scaled by a factor of 2, but this is not
521 requested by the DC transformation, we get a scaling factor
522 of 2 in the X coordinate. */
523 SetViewportExtEx(hdc, 100, 200, NULL);
524 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
525 /* font metrics on another DC should be unchanged */
526 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
528 /* restore scaling */
529 SetMapMode(hdc, MM_TEXT);
531 /* font metrics on another DC should be unchanged */
532 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
534 SelectObject(hdc_2, old_hfont_2);
537 if (!SetGraphicsMode(hdc, GM_ADVANCED))
539 SelectObject(hdc, old_hfont);
542 skip("GM_ADVANCED is not supported on this platform\n");
553 SetLastError(0xdeadbeef);
554 ret = SetWorldTransform(hdc, &xform);
555 ok(ret, "SetWorldTransform error %u\n", GetLastError());
557 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
559 /* with an identity matrix */
560 memset(&gm, 0, sizeof(gm));
561 SetLastError(0xdeadbeef);
562 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
563 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
564 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
565 pt.x = width_orig; pt.y = 0;
567 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
568 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
569 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
570 /* with a custom matrix */
571 memset(&gm, 0, sizeof(gm));
572 SetLastError(0xdeadbeef);
573 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
574 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
575 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
576 pt.x = width_orig; pt.y = 0;
578 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
579 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
580 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
582 SetLastError(0xdeadbeef);
583 ret = SetMapMode(hdc, MM_LOMETRIC);
584 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
586 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
588 /* with an identity matrix */
589 memset(&gm, 0, sizeof(gm));
590 SetLastError(0xdeadbeef);
591 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
592 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
593 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
594 pt.x = width_orig; pt.y = 0;
596 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
597 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
598 /* with a custom matrix */
599 memset(&gm, 0, sizeof(gm));
600 SetLastError(0xdeadbeef);
601 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
602 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
604 pt.x = width_orig; pt.y = 0;
606 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
607 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
609 SetLastError(0xdeadbeef);
610 ret = SetMapMode(hdc, MM_TEXT);
611 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
613 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
615 /* with an identity matrix */
616 memset(&gm, 0, sizeof(gm));
617 SetLastError(0xdeadbeef);
618 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
619 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
620 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
621 pt.x = width_orig; pt.y = 0;
623 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
624 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
625 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
626 /* with a custom matrix */
627 memset(&gm, 0, sizeof(gm));
628 SetLastError(0xdeadbeef);
629 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
630 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
631 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
632 pt.x = width_orig; pt.y = 0;
634 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
635 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
636 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
638 SelectObject(hdc, old_hfont);
643 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
645 LOGFONT *lf = (LOGFONT *)lParam;
647 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
650 return 0; /* stop enumeration */
652 return 1; /* continue enumeration */
655 static void test_bitmap_font_metrics(void)
657 static const struct font_data
659 const char face_name[LF_FACESIZE];
660 int weight, height, ascent, descent, int_leading, ext_leading;
661 int ave_char_width, max_char_width, dpi;
665 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
666 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
667 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1 | FS_CYRILLIC },
668 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2 },
669 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1 },
670 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2 },
671 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC },
672 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1 },
673 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2 },
674 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC },
675 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
677 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
678 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_LATIN2 },
679 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC },
680 { "MS Sans Serif", FW_NORMAL, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
681 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1 | FS_LATIN2 },
682 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC },
683 { "MS Sans Serif", FW_NORMAL, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
684 { "MS Sans Serif", FW_NORMAL, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
686 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
687 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
688 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
689 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1 },
690 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2 | FS_CYRILLIC },
691 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1 | FS_LATIN2 },
692 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC },
693 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1 | FS_LATIN2 },
694 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC },
695 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1 },
696 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2 },
697 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC },
698 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1 },
699 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2 },
700 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC },
701 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1 | FS_LATIN2 },
702 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC },
704 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1 | FS_CYRILLIC },
705 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2 },
706 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1 | FS_CYRILLIC },
707 { "MS Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2 },
708 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1 | FS_CYRILLIC },
709 { "MS Serif", FW_NORMAL, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2 },
710 { "MS Serif", FW_NORMAL, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1 | FS_LATIN2 },
711 { "MS Serif", FW_MEDIUM, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC },
712 { "MS Serif", FW_NORMAL, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1 | FS_LATIN2 },
713 { "MS Serif", FW_MEDIUM, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC },
714 { "MS Serif", FW_NORMAL, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
716 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
717 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
718 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
720 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
721 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
722 { "Courier", FW_NORMAL, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
724 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1 },
725 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2 | FS_CYRILLIC },
727 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
728 * require a new system.sfd for that font
730 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN },
732 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1 },
733 { "System", FW_BOLD, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2 | FS_CYRILLIC },
735 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1 },
736 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2 | FS_CYRILLIC },
737 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN },
738 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1 },
739 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2 | FS_CYRILLIC },
740 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN },
741 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1 },
742 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2 | FS_CYRILLIC },
743 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN },
744 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1 },
745 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2 | FS_CYRILLIC },
746 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN },
747 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1 | FS_LATIN2 },
748 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC },
749 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN },
750 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
751 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN },
753 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1 | FS_JISJAPAN },
754 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2 | FS_CYRILLIC },
755 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1 | FS_JISJAPAN },
756 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2 | FS_CYRILLIC },
757 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1 | FS_JISJAPAN },
758 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2 | FS_CYRILLIC },
759 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
760 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC },
761 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
762 { "Small Fonts", FW_NORMAL, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC },
763 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1 | FS_LATIN2 | FS_JISJAPAN },
764 { "Small Fonts", FW_NORMAL, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC },
766 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1 | FS_LATIN2 },
767 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC },
768 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN },
770 /* The 120dpi version still has its dpi marked as 96 */
771 { "Fixedsys", FW_NORMAL, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC }
773 /* FIXME: add "Terminal" */
777 HFONT hfont, old_hfont;
781 hdc = CreateCompatibleDC(0);
784 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
788 memset(&lf, 0, sizeof(lf));
790 lf.lfHeight = fd[i].height;
791 strcpy(lf.lfFaceName, fd[i].face_name);
793 for(bit = 0; bit < 32; bit++)
800 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
801 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
803 lf.lfCharSet = csi.ciCharset;
804 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
807 hfont = create_font(lf.lfFaceName, &lf);
808 old_hfont = SelectObject(hdc, hfont);
809 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
810 if(fd[i].dpi == tm.tmDigitizedAspectX)
812 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
813 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
814 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
815 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
816 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
817 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
818 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
819 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
821 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
822 that make the max width bigger */
823 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
824 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
826 SelectObject(hdc, old_hfont);
834 static void test_GdiGetCharDimensions(void)
840 LONG avgwidth, height;
841 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
843 if (!pGdiGetCharDimensions)
845 win_skip("GdiGetCharDimensions not available on this platform\n");
849 hdc = CreateCompatibleDC(NULL);
851 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
852 avgwidth = ((size.cx / 26) + 1) / 2;
854 ret = pGdiGetCharDimensions(hdc, &tm, &height);
855 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
856 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
858 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
859 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
861 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
862 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
865 ret = pGdiGetCharDimensions(hdc, NULL, &height);
866 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
867 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
872 static void test_GetCharABCWidths(void)
874 static const WCHAR str[] = {'a',0};
883 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
885 win_skip("GetCharABCWidthsW/I not available on this platform\n");
889 memset(&lf, 0, sizeof(lf));
890 strcpy(lf.lfFaceName, "System");
893 hfont = CreateFontIndirectA(&lf);
895 hfont = SelectObject(hdc, hfont);
897 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
898 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
900 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
901 ok(!ret, "GetCharABCWidthsI should have failed\n");
903 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
904 ok(!ret, "GetCharABCWidthsI should have failed\n");
906 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
907 ok(ret, "GetCharABCWidthsI should have succeeded\n");
909 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
910 ok(!ret, "GetCharABCWidthsW should have failed\n");
912 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
913 ok(!ret, "GetCharABCWidthsW should have failed\n");
915 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
916 ok(!ret, "GetCharABCWidthsW should have failed\n");
918 hfont = SelectObject(hdc, hfont);
920 ReleaseDC(NULL, hdc);
923 static void test_text_extents(void)
925 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
927 INT i, len, fit1, fit2;
935 memset(&lf, 0, sizeof(lf));
936 strcpy(lf.lfFaceName, "Arial");
939 hfont = CreateFontIndirectA(&lf);
941 hfont = SelectObject(hdc, hfont);
942 GetTextMetricsA(hdc, &tm);
943 GetTextExtentPointA(hdc, "o", 1, &sz);
944 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
946 SetLastError(0xdeadbeef);
947 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
948 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
950 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
951 hfont = SelectObject(hdc, hfont);
958 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
959 extents[0] = 1; /* So that the increasing sequence test will fail
960 if the extents array is untouched. */
961 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
962 GetTextExtentPointW(hdc, wt, len, &sz2);
964 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
965 /* Because of the '\n' in the string GetTextExtentExPoint and
966 GetTextExtentPoint return different widths under Win2k, but
967 under WinXP they return the same width. So we don't test that
970 for (i = 1; i < len; ++i)
971 ok(extents[i-1] <= extents[i],
972 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
974 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
975 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
976 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
977 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
978 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
979 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
980 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
981 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
982 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
983 ok(extents[0] == extents[2] && extents[1] == extents[3],
984 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
985 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
986 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
987 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
988 HeapFree(GetProcessHeap(), 0, extents);
990 hfont = SelectObject(hdc, hfont);
992 ReleaseDC(NULL, hdc);
995 static void test_GetGlyphIndices(void)
1002 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
1003 WORD glyphs[(sizeof(testtext)/2)-1];
1007 if (!pGetGlyphIndicesW) {
1008 win_skip("GetGlyphIndicesW not available on platform\n");
1014 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1015 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1016 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1017 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1018 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
1020 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1021 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1022 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1023 textm.tmDefaultChar, glyphs[4]);
1025 if(!is_font_installed("Tahoma"))
1027 skip("Tahoma is not installed so skipping this test\n");
1030 memset(&lf, 0, sizeof(lf));
1031 strcpy(lf.lfFaceName, "Tahoma");
1034 hfont = CreateFontIndirectA(&lf);
1035 hOldFont = SelectObject(hdc, hfont);
1036 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
1037 flags |= GGI_MARK_NONEXISTING_GLYPHS;
1038 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1039 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1040 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
1042 testtext[0] = textm.tmDefaultChar;
1043 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
1044 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
1045 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
1046 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
1047 DeleteObject(SelectObject(hdc, hOldFont));
1050 static void test_GetKerningPairs(void)
1052 static const struct kerning_data
1054 const char face_name[LF_FACESIZE];
1056 /* some interesting fields from OUTLINETEXTMETRIC */
1057 LONG tmHeight, tmAscent, tmDescent;
1062 UINT otmsCapEmHeight;
1067 UINT otmusMinimumPPEM;
1068 /* small subset of kerning pairs to test */
1069 DWORD total_kern_pairs;
1070 const KERNINGPAIR kern_pair[26];
1073 {"Arial", 12, 12, 9, 3,
1074 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1077 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1078 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1079 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1080 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1081 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1082 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1083 {933,970,+1},{933,972,-1}
1086 {"Arial", -34, 39, 32, 7,
1087 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1090 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1091 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1092 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1093 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1094 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1095 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1096 {933,970,+2},{933,972,-3}
1099 { "Arial", 120, 120, 97, 23,
1100 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1103 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1104 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1105 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1106 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1107 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1108 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1109 {933,970,+6},{933,972,-10}
1112 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1113 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1114 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1117 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1118 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1119 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1120 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1121 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1122 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1123 {933,970,+54},{933,972,-83}
1129 HFONT hfont, hfont_old;
1130 KERNINGPAIR *kern_pair;
1132 DWORD total_kern_pairs, ret, i, n, matches;
1136 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1137 * which may render this test unusable, so we're trying to avoid that.
1139 SetLastError(0xdeadbeef);
1140 GetKerningPairsW(hdc, 0, NULL);
1141 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1143 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1148 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1150 OUTLINETEXTMETRICW otm;
1152 if (!is_font_installed(kd[i].face_name))
1154 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1158 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1160 memset(&lf, 0, sizeof(lf));
1161 strcpy(lf.lfFaceName, kd[i].face_name);
1162 lf.lfHeight = kd[i].height;
1163 hfont = CreateFontIndirect(&lf);
1166 hfont_old = SelectObject(hdc, hfont);
1168 SetLastError(0xdeadbeef);
1169 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1170 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1172 ok(match_off_by_1(kd[i].tmHeight, otm.otmTextMetrics.tmHeight), "expected %d, got %d\n",
1173 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1174 ok(match_off_by_1(kd[i].tmAscent, otm.otmTextMetrics.tmAscent), "expected %d, got %d\n",
1175 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1176 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1177 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1179 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1180 kd[i].otmEMSquare, otm.otmEMSquare);
1181 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1182 kd[i].otmAscent, otm.otmAscent);
1183 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1184 kd[i].otmDescent, otm.otmDescent);
1185 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1186 kd[i].otmLineGap, otm.otmLineGap);
1187 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1188 kd[i].otmMacDescent, otm.otmMacDescent);
1189 ok(near_match(kd[i].otmMacAscent, otm.otmMacAscent), "expected %d, got %d\n",
1190 kd[i].otmMacAscent, otm.otmMacAscent);
1192 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1193 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1194 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1195 kd[i].otmsXHeight, otm.otmsXHeight);
1196 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1197 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1198 kd[i].otmMacLineGap, otm.otmMacLineGap);
1199 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1200 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1203 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1204 trace("total_kern_pairs %u\n", total_kern_pairs);
1205 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1207 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1208 SetLastError(0xdeadbeef);
1209 ret = GetKerningPairsW(hdc, 0, kern_pair);
1210 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1211 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1212 ok(ret == 0, "got %lu, expected 0\n", ret);
1215 ret = GetKerningPairsW(hdc, 100, NULL);
1216 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1218 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1219 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1221 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1222 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1226 for (n = 0; n < ret; n++)
1230 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1231 trace("{'%c','%c',%d},\n",
1232 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1234 for (j = 0; j < kd[i].total_kern_pairs; j++)
1236 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1237 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1239 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1240 "pair %d:%d got %d, expected %d\n",
1241 kern_pair[n].wFirst, kern_pair[n].wSecond,
1242 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1248 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1249 matches, kd[i].total_kern_pairs);
1251 HeapFree(GetProcessHeap(), 0, kern_pair);
1253 SelectObject(hdc, hfont_old);
1254 DeleteObject(hfont);
1260 static void test_height_selection(void)
1262 static const struct font_data
1264 const char face_name[LF_FACESIZE];
1265 int requested_height;
1266 int weight, height, ascent, descent, int_leading, ext_leading, dpi;
1269 {"Tahoma", -12, FW_NORMAL, 14, 12, 2, 2, 0, 96 },
1270 {"Tahoma", -24, FW_NORMAL, 29, 24, 5, 5, 0, 96 },
1271 {"Tahoma", -48, FW_NORMAL, 58, 48, 10, 10, 0, 96 },
1272 {"Tahoma", -96, FW_NORMAL, 116, 96, 20, 20, 0, 96 },
1273 {"Tahoma", -192, FW_NORMAL, 232, 192, 40, 40, 0, 96 },
1274 {"Tahoma", 12, FW_NORMAL, 12, 10, 2, 2, 0, 96 },
1275 {"Tahoma", 24, FW_NORMAL, 24, 20, 4, 4, 0, 96 },
1276 {"Tahoma", 48, FW_NORMAL, 48, 40, 8, 8, 0, 96 },
1277 {"Tahoma", 96, FW_NORMAL, 96, 80, 16, 17, 0, 96 },
1278 {"Tahoma", 192, FW_NORMAL, 192, 159, 33, 33, 0, 96 }
1282 HFONT hfont, old_hfont;
1286 hdc = CreateCompatibleDC(0);
1289 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
1291 if (!is_truetype_font_installed(fd[i].face_name))
1293 skip("%s is not installed\n", fd[i].face_name);
1297 memset(&lf, 0, sizeof(lf));
1298 lf.lfHeight = fd[i].requested_height;
1299 lf.lfWeight = fd[i].weight;
1300 strcpy(lf.lfFaceName, fd[i].face_name);
1302 hfont = CreateFontIndirect(&lf);
1305 old_hfont = SelectObject(hdc, hfont);
1306 ret = GetTextMetrics(hdc, &tm);
1307 ok(ret, "GetTextMetrics error %d\n", GetLastError());
1308 if(fd[i].dpi == tm.tmDigitizedAspectX)
1310 trace("found font %s, height %d charset %x dpi %d\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet, fd[i].dpi);
1311 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmWeight, fd[i].weight);
1312 ok(match_off_by_1(tm.tmHeight, fd[i].height), "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmHeight, fd[i].height);
1313 ok(match_off_by_1(tm.tmAscent, fd[i].ascent), "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmAscent, fd[i].ascent);
1314 ok(match_off_by_1(tm.tmDescent, fd[i].descent), "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmDescent, fd[i].descent);
1315 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1316 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmInternalLeading, fd[i].int_leading);
1318 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].requested_height, tm.tmExternalLeading, fd[i].ext_leading);
1321 SelectObject(hdc, old_hfont);
1322 DeleteObject(hfont);
1328 static void test_GetOutlineTextMetrics(void)
1330 OUTLINETEXTMETRIC *otm;
1332 HFONT hfont, hfont_old;
1334 DWORD ret, otm_size;
1337 if (!is_font_installed("Arial"))
1339 skip("Arial is not installed\n");
1345 memset(&lf, 0, sizeof(lf));
1346 strcpy(lf.lfFaceName, "Arial");
1348 lf.lfWeight = FW_NORMAL;
1349 lf.lfPitchAndFamily = DEFAULT_PITCH;
1350 lf.lfQuality = PROOF_QUALITY;
1351 hfont = CreateFontIndirect(&lf);
1354 hfont_old = SelectObject(hdc, hfont);
1355 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1356 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1358 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1360 memset(otm, 0xAA, otm_size);
1361 SetLastError(0xdeadbeef);
1362 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1363 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1364 ok(ret == 1 /* Win9x */ ||
1365 ret == otm->otmSize /* XP*/,
1366 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1367 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1369 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1370 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1371 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1372 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1375 memset(otm, 0xAA, otm_size);
1376 SetLastError(0xdeadbeef);
1377 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1378 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1379 ok(ret == 1 /* Win9x */ ||
1380 ret == otm->otmSize /* XP*/,
1381 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1382 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1384 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1385 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1386 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1387 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1390 /* ask about truncated data */
1391 memset(otm, 0xAA, otm_size);
1392 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1393 SetLastError(0xdeadbeef);
1394 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1395 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1396 ok(ret == 1 /* Win9x */ ||
1397 ret == otm->otmSize /* XP*/,
1398 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1399 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1401 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1402 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1403 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1405 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1407 HeapFree(GetProcessHeap(), 0, otm);
1409 SelectObject(hdc, hfont_old);
1410 DeleteObject(hfont);
1415 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1419 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1420 areaWidth = clientArea->right - clientArea->left,
1422 BOOL lastExtent = FALSE;
1423 PSTR pFirstChar, pLastChar;
1429 int GetTextExtentExPointWWidth;
1432 GetTextMetricsA(hdc, &tm);
1433 y = clientArea->top;
1436 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1442 /* if not at the end of the string, ... */
1443 if (*str == '\0') break;
1444 /* ... add the next word to the current extent */
1445 while (*str != '\0' && *str++ != tm.tmBreakChar);
1447 SetTextJustification(hdc, 0, 0);
1448 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1449 } while ((int) size.cx < areaWidth);
1451 /* ignore trailing break chars */
1453 while (*(pLastChar - 1) == tm.tmBreakChar)
1459 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1461 SetTextJustification(hdc, 0, 0);
1462 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1464 /* do not justify the last extent */
1465 if (*str != '\0' && breakCount > 0)
1467 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1468 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1469 justifiedWidth = size.cx;
1471 else lastExtent = TRUE;
1473 /* catch errors and report them */
1474 if (!lastExtent && (justifiedWidth != areaWidth))
1476 memset(error[nErrors].extent, 0, 100);
1477 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1478 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1484 } while (*str && y < clientArea->bottom);
1486 for (e = 0; e < nErrors; e++)
1488 /* The width returned by GetTextExtentPoint32() is exactly the same
1489 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1490 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1491 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1492 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1496 static void test_SetTextJustification(void)
1503 static char testText[] =
1504 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1505 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1506 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1507 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1508 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1509 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1510 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1512 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1513 GetClientRect( hwnd, &clientArea );
1514 hdc = GetDC( hwnd );
1516 memset(&lf, 0, sizeof lf);
1517 lf.lfCharSet = ANSI_CHARSET;
1518 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1519 lf.lfWeight = FW_DONTCARE;
1521 lf.lfQuality = DEFAULT_QUALITY;
1522 lstrcpyA(lf.lfFaceName, "Times New Roman");
1523 hfont = create_font("Times New Roman", &lf);
1524 SelectObject(hdc, hfont);
1526 testJustification(hdc, testText, &clientArea);
1528 DeleteObject(hfont);
1529 ReleaseDC(hwnd, hdc);
1530 DestroyWindow(hwnd);
1533 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1537 HFONT hfont, hfont_old;
1544 assert(count <= 128);
1546 memset(&lf, 0, sizeof(lf));
1548 lf.lfCharSet = charset;
1550 lstrcpyA(lf.lfFaceName, "Arial");
1551 SetLastError(0xdeadbeef);
1552 hfont = CreateFontIndirectA(&lf);
1553 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1556 hfont_old = SelectObject(hdc, hfont);
1558 cs = GetTextCharsetInfo(hdc, &fs, 0);
1559 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1561 SetLastError(0xdeadbeef);
1562 ret = GetTextFaceA(hdc, sizeof(name), name);
1563 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1565 if (charset == SYMBOL_CHARSET)
1567 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1568 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1572 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1573 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1576 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1578 trace("Can't find codepage for charset %d\n", cs);
1582 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1587 WCHAR unicode_buf[128];
1589 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1591 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1593 SetLastError(0xdeadbeef);
1594 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1595 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1601 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1603 SetLastError(0xdeadbeef);
1604 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1605 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1608 SelectObject(hdc, hfont_old);
1609 DeleteObject(hfont);
1616 static void test_font_charset(void)
1618 static struct charset_data
1622 WORD font_idxA[128], font_idxW[128];
1625 { ANSI_CHARSET, 1252 },
1626 { RUSSIAN_CHARSET, 1251 },
1627 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1631 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1633 win_skip("Skipping the font charset test on a Win9x platform\n");
1637 if (!is_font_installed("Arial"))
1639 skip("Arial is not installed\n");
1643 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1645 if (cd[i].charset == SYMBOL_CHARSET)
1647 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1649 skip("Symbol or Wingdings is not installed\n");
1653 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1654 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1655 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1658 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1661 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1662 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1665 skip("Symbol or Wingdings is not installed\n");
1668 static void test_GetFontUnicodeRanges(void)
1672 HFONT hfont, hfont_old;
1676 if (!pGetFontUnicodeRanges)
1678 win_skip("GetFontUnicodeRanges not available before W2K\n");
1682 memset(&lf, 0, sizeof(lf));
1683 lstrcpyA(lf.lfFaceName, "Arial");
1684 hfont = create_font("Arial", &lf);
1687 hfont_old = SelectObject(hdc, hfont);
1689 size = pGetFontUnicodeRanges(NULL, NULL);
1690 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1692 size = pGetFontUnicodeRanges(hdc, NULL);
1693 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1695 gs = HeapAlloc(GetProcessHeap(), 0, size);
1697 size = pGetFontUnicodeRanges(hdc, gs);
1698 ok(size, "GetFontUnicodeRanges failed\n");
1700 for (i = 0; i < gs->cRanges; i++)
1701 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1703 trace("found %u ranges\n", gs->cRanges);
1705 HeapFree(GetProcessHeap(), 0, gs);
1707 SelectObject(hdc, hfont_old);
1708 DeleteObject(hfont);
1709 ReleaseDC(NULL, hdc);
1712 #define MAX_ENUM_FONTS 4096
1714 struct enum_font_data
1717 LOGFONT lf[MAX_ENUM_FONTS];
1720 struct enum_font_dataW
1723 LOGFONTW lf[MAX_ENUM_FONTS];
1726 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1728 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1730 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1732 if (type != TRUETYPE_FONTTYPE) return 1;
1734 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1735 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1737 if (efd->total < MAX_ENUM_FONTS)
1738 efd->lf[efd->total++] = *lf;
1740 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1745 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1747 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1749 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1751 if (type != TRUETYPE_FONTTYPE) return 1;
1753 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1754 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1756 if (efd->total < MAX_ENUM_FONTS)
1757 efd->lf[efd->total++] = *lf;
1759 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1764 static void get_charset_stats(struct enum_font_data *efd,
1765 int *ansi_charset, int *symbol_charset,
1766 int *russian_charset)
1771 *symbol_charset = 0;
1772 *russian_charset = 0;
1774 for (i = 0; i < efd->total; i++)
1776 switch (efd->lf[i].lfCharSet)
1781 case SYMBOL_CHARSET:
1782 (*symbol_charset)++;
1784 case RUSSIAN_CHARSET:
1785 (*russian_charset)++;
1791 static void get_charset_statsW(struct enum_font_dataW *efd,
1792 int *ansi_charset, int *symbol_charset,
1793 int *russian_charset)
1798 *symbol_charset = 0;
1799 *russian_charset = 0;
1801 for (i = 0; i < efd->total; i++)
1803 switch (efd->lf[i].lfCharSet)
1808 case SYMBOL_CHARSET:
1809 (*symbol_charset)++;
1811 case RUSSIAN_CHARSET:
1812 (*russian_charset)++;
1818 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1820 struct enum_font_data efd;
1821 struct enum_font_dataW efdw;
1824 int i, ret, ansi_charset, symbol_charset, russian_charset;
1826 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1828 if (*font_name && !is_truetype_font_installed(font_name))
1830 skip("%s is not installed\n", font_name);
1836 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1837 * while EnumFontFamiliesEx doesn't.
1839 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1842 * Use EnumFontFamiliesW since win98 crashes when the
1843 * second parameter is NULL using EnumFontFamilies
1846 SetLastError(0xdeadbeef);
1847 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1848 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1851 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1852 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1853 ansi_charset, symbol_charset, russian_charset);
1854 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1855 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1856 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1857 ok(russian_charset > 0 ||
1858 broken(russian_charset == 0), /* NT4 */
1859 "NULL family should enumerate RUSSIAN_CHARSET\n");
1863 SetLastError(0xdeadbeef);
1864 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1865 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1868 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1869 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1870 ansi_charset, symbol_charset, russian_charset);
1871 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1872 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1873 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1874 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1879 SetLastError(0xdeadbeef);
1880 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1881 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1882 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1883 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1884 ansi_charset, symbol_charset, russian_charset,
1885 *font_name ? font_name : "<empty>");
1887 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1889 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1890 for (i = 0; i < efd.total; i++)
1892 /* FIXME: remove completely once Wine is fixed */
1893 if (efd.lf[i].lfCharSet != font_charset)
1896 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1899 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1900 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1901 font_name, efd.lf[i].lfFaceName);
1904 memset(&lf, 0, sizeof(lf));
1905 lf.lfCharSet = ANSI_CHARSET;
1906 lstrcpy(lf.lfFaceName, font_name);
1908 SetLastError(0xdeadbeef);
1909 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1910 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1911 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1912 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1913 ansi_charset, symbol_charset, russian_charset,
1914 *font_name ? font_name : "<empty>");
1915 if (font_charset == SYMBOL_CHARSET)
1918 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1920 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1924 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1925 for (i = 0; i < efd.total; i++)
1927 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1929 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1930 font_name, efd.lf[i].lfFaceName);
1934 /* DEFAULT_CHARSET should enumerate all available charsets */
1935 memset(&lf, 0, sizeof(lf));
1936 lf.lfCharSet = DEFAULT_CHARSET;
1937 lstrcpy(lf.lfFaceName, font_name);
1939 SetLastError(0xdeadbeef);
1940 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1941 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1942 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1943 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1944 ansi_charset, symbol_charset, russian_charset,
1945 *font_name ? font_name : "<empty>");
1946 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1947 for (i = 0; i < efd.total; i++)
1950 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1951 font_name, efd.lf[i].lfFaceName);
1955 switch (font_charset)
1958 ok(ansi_charset > 0,
1959 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1961 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1962 ok(russian_charset > 0,
1963 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1965 case SYMBOL_CHARSET:
1967 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1969 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1970 ok(!russian_charset,
1971 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1973 case DEFAULT_CHARSET:
1974 ok(ansi_charset > 0,
1975 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1976 ok(symbol_charset > 0,
1977 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1978 ok(russian_charset > 0,
1979 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1985 ok(ansi_charset > 0,
1986 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1987 ok(symbol_charset > 0,
1988 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1989 ok(russian_charset > 0,
1990 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1993 memset(&lf, 0, sizeof(lf));
1994 lf.lfCharSet = SYMBOL_CHARSET;
1995 lstrcpy(lf.lfFaceName, font_name);
1997 SetLastError(0xdeadbeef);
1998 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1999 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
2000 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
2001 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2002 ansi_charset, symbol_charset, russian_charset,
2003 *font_name ? font_name : "<empty>");
2004 if (*font_name && font_charset == ANSI_CHARSET)
2005 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
2008 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
2009 for (i = 0; i < efd.total; i++)
2011 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
2013 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
2014 font_name, efd.lf[i].lfFaceName);
2018 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2019 ok(symbol_charset > 0,
2020 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2021 ok(!russian_charset,
2022 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
2028 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
2030 HFONT hfont, hfont_prev;
2032 GLYPHMETRICS gm1, gm2;
2035 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2037 if(!pGetGlyphIndicesA)
2040 /* negative widths are handled just as positive ones */
2041 lf2.lfWidth = -lf->lfWidth;
2043 SetLastError(0xdeadbeef);
2044 hfont = CreateFontIndirectA(lf);
2045 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2046 check_font("original", lf, hfont);
2048 hfont_prev = SelectObject(hdc, hfont);
2050 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
2051 if (ret == GDI_ERROR || idx == 0xffff)
2053 SelectObject(hdc, hfont_prev);
2054 DeleteObject(hfont);
2055 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
2059 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2060 memset(&gm1, 0xab, sizeof(gm1));
2061 SetLastError(0xdeadbeef);
2062 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
2063 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2065 SelectObject(hdc, hfont_prev);
2066 DeleteObject(hfont);
2068 SetLastError(0xdeadbeef);
2069 hfont = CreateFontIndirectA(&lf2);
2070 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2071 check_font("negative width", &lf2, hfont);
2073 hfont_prev = SelectObject(hdc, hfont);
2075 memset(&gm2, 0xbb, sizeof(gm2));
2076 SetLastError(0xdeadbeef);
2077 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
2078 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
2080 SelectObject(hdc, hfont_prev);
2081 DeleteObject(hfont);
2083 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
2084 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
2085 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
2086 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
2087 gm1.gmCellIncX == gm2.gmCellIncX &&
2088 gm1.gmCellIncY == gm2.gmCellIncY,
2089 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2090 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
2091 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
2092 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
2093 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
2096 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2097 #include "pshpack2.h"
2101 SHORT xAvgCharWidth;
2102 USHORT usWeightClass;
2103 USHORT usWidthClass;
2105 SHORT ySubscriptXSize;
2106 SHORT ySubscriptYSize;
2107 SHORT ySubscriptXOffset;
2108 SHORT ySubscriptYOffset;
2109 SHORT ySuperscriptXSize;
2110 SHORT ySuperscriptYSize;
2111 SHORT ySuperscriptXOffset;
2112 SHORT ySuperscriptYOffset;
2113 SHORT yStrikeoutSize;
2114 SHORT yStrikeoutPosition;
2117 ULONG ulUnicodeRange1;
2118 ULONG ulUnicodeRange2;
2119 ULONG ulUnicodeRange3;
2120 ULONG ulUnicodeRange4;
2123 USHORT usFirstCharIndex;
2124 USHORT usLastCharIndex;
2125 /* According to the Apple spec, original version didn't have the below fields,
2126 * version numbers were taked from the OpenType spec.
2128 /* version 0 (TrueType 1.5) */
2129 USHORT sTypoAscender;
2130 USHORT sTypoDescender;
2131 USHORT sTypoLineGap;
2133 USHORT usWinDescent;
2134 /* version 1 (TrueType 1.66) */
2135 ULONG ulCodePageRange1;
2136 ULONG ulCodePageRange2;
2137 /* version 2 (OpenType 1.2) */
2140 USHORT usDefaultChar;
2142 USHORT usMaxContext;
2144 #include "poppack.h"
2146 #ifdef WORDS_BIGENDIAN
2147 #define GET_BE_WORD(x) (x)
2148 #define GET_BE_DWORD(x) (x)
2150 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2151 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2154 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2155 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2156 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2157 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2158 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2171 } cmap_encoding_record;
2179 BYTE glyph_ids[256];
2189 USHORT search_range;
2190 USHORT entry_selector;
2193 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2196 USHORT start_count[seg_countx2 / 2];
2197 USHORT id_delta[seg_countx2 / 2];
2198 USHORT id_range_offset[seg_countx2 / 2];
2208 USHORT id_range_offset;
2209 } cmap_format_4_seg;
2211 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2213 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2214 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2215 os2->panose.bWeight, os2->panose.bProportion);
2218 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2221 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2225 for(i = 0; i < 256; i++)
2227 if(cmap->glyph_ids[i] == 0) continue;
2229 if(*first == 256) *first = i;
2231 if(*first == 256) return FALSE;
2235 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2237 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2238 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2239 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2240 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2241 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2244 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last, DWORD limit)
2247 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2248 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2249 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2253 for(i = 0; i < seg_count; i++)
2256 cmap_format_4_seg seg;
2258 get_seg4(cmap, i, &seg);
2259 for(code = seg.start_count; code <= seg.end_count; code++)
2261 if(seg.id_range_offset == 0)
2262 index = (seg.id_delta + code) & 0xffff;
2265 index = seg.id_range_offset / 2
2266 + code - seg.start_count
2269 /* some fonts have broken last segment */
2270 if ((char *)(glyph_ids + index + sizeof(*glyph_ids)) < (char *)ptr + limit)
2271 index = GET_BE_WORD(glyph_ids[index]);
2274 trace("segment %04x/%04x index %04x points to nowhere\n",
2275 seg.start_count, seg.end_count, index);
2278 if(index) index += seg.id_delta;
2280 if(*first == 0x10000)
2281 *last = *first = code;
2287 if(*first == 0x10000) return FALSE;
2291 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2294 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2296 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2298 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2299 return (BYTE *)header + GET_BE_DWORD(record->offset);
2312 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last, cmap_type *cmap_type)
2315 cmap_header *header;
2320 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2321 ok(size != GDI_ERROR, "no cmap table found\n");
2322 if(size == GDI_ERROR) return FALSE;
2324 header = HeapAlloc(GetProcessHeap(), 0, size);
2325 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2326 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2327 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2329 cmap = get_cmap(header, 3, 1);
2331 *cmap_type = cmap_ms_unicode;
2334 cmap = get_cmap(header, 3, 0);
2335 if(cmap) *cmap_type = cmap_ms_symbol;
2339 *cmap_type = cmap_none;
2343 format = GET_BE_WORD(*(WORD *)cmap);
2347 r = get_first_last_from_cmap0(cmap, first, last);
2350 r = get_first_last_from_cmap4(cmap, first, last, size);
2353 trace("unhandled cmap format %d\n", format);
2358 HeapFree(GetProcessHeap(), 0, header);
2362 static void test_text_metrics(const LOGFONTA *lf)
2365 HFONT hfont, hfont_old;
2369 const char *font_name = lf->lfFaceName;
2370 DWORD cmap_first = 0, cmap_last = 0;
2371 cmap_type cmap_type;
2375 SetLastError(0xdeadbeef);
2376 hfont = CreateFontIndirectA(lf);
2377 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2379 hfont_old = SelectObject(hdc, hfont);
2381 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2382 if (size == GDI_ERROR)
2384 trace("OS/2 chunk was not found\n");
2387 if (size > sizeof(tt_os2))
2389 trace("got too large OS/2 chunk of size %u\n", size);
2390 size = sizeof(tt_os2);
2393 memset(&tt_os2, 0, sizeof(tt_os2));
2394 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2395 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2397 SetLastError(0xdeadbeef);
2398 ret = GetTextMetricsA(hdc, &tmA);
2399 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2401 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last, &cmap_type))
2403 skip("Unable to retrieve first and last glyphs from cmap\n");
2407 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2408 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2409 UINT os2_first_char, os2_last_char, default_char, break_char;
2413 version = GET_BE_WORD(tt_os2.version);
2415 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2416 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2417 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2418 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2420 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2421 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2422 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2424 if (cmap_type == cmap_ms_symbol || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2429 case 1257: /* Baltic */
2430 expect_last_W = 0xf8fd;
2433 expect_last_W = 0xf0ff;
2435 expect_break_W = 0x20;
2436 expect_default_W = expect_break_W - 1;
2437 expect_first_A = 0x1e;
2438 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2442 expect_first_W = cmap_first;
2443 expect_last_W = min(cmap_last, os2_last_char);
2444 if(os2_first_char <= 1)
2445 expect_break_W = os2_first_char + 2;
2446 else if(os2_first_char > 0xff)
2447 expect_break_W = 0x20;
2449 expect_break_W = os2_first_char;
2450 expect_default_W = expect_break_W - 1;
2451 expect_first_A = expect_default_W - 1;
2452 expect_last_A = min(expect_last_W, 0xff);
2454 expect_break_A = expect_break_W;
2455 expect_default_A = expect_default_W;
2457 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2458 if(cmap_type != cmap_ms_symbol && tmA.tmCharSet == SYMBOL_CHARSET && expect_first_A != 0x1e)
2459 todo_wine ok(tmA.tmFirstChar == expect_first_A ||
2460 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2461 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2463 ok(tmA.tmFirstChar == expect_first_A ||
2464 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2465 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2466 ok(tmA.tmLastChar == expect_last_A ||
2467 tmA.tmLastChar == 0xff /* win9x */,
2468 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2469 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2470 font_name, tmA.tmBreakChar, expect_break_A);
2471 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2472 font_name, tmA.tmDefaultChar, expect_default_A);
2475 SetLastError(0xdeadbeef);
2476 ret = GetTextMetricsW(hdc, &tmW);
2477 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2478 "GetTextMetricsW error %u\n", GetLastError());
2481 /* Wine uses the os2 first char */
2482 if(cmap_first != os2_first_char && cmap_type != cmap_ms_symbol)
2483 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2484 font_name, tmW.tmFirstChar, expect_first_W);
2486 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2487 font_name, tmW.tmFirstChar, expect_first_W);
2489 /* Wine uses the os2 last char */
2490 if(expect_last_W != os2_last_char && cmap_type != cmap_ms_symbol)
2491 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2492 font_name, tmW.tmLastChar, expect_last_W);
2494 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2495 font_name, tmW.tmLastChar, expect_last_W);
2496 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2497 font_name, tmW.tmBreakChar, expect_break_W);
2498 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2499 font_name, tmW.tmDefaultChar, expect_default_W);
2501 /* Test the aspect ratio while we have tmW */
2502 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2503 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2504 tmW.tmDigitizedAspectX, ret);
2505 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2506 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2507 tmW.tmDigitizedAspectX, ret);
2511 /* test FF_ values */
2512 switch(tt_os2.panose.bFamilyType)
2516 case PAN_FAMILY_TEXT_DISPLAY:
2517 case PAN_FAMILY_PICTORIAL:
2519 if((tmA.tmPitchAndFamily & 1) == 0 || /* fixed */
2520 tt_os2.panose.bProportion == PAN_PROP_MONOSPACED)
2522 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2525 switch(tt_os2.panose.bSerifStyle)
2530 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2533 case PAN_SERIF_COVE:
2534 case PAN_SERIF_OBTUSE_COVE:
2535 case PAN_SERIF_SQUARE_COVE:
2536 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2537 case PAN_SERIF_SQUARE:
2538 case PAN_SERIF_THIN:
2539 case PAN_SERIF_BONE:
2540 case PAN_SERIF_EXAGGERATED:
2541 case PAN_SERIF_TRIANGLE:
2542 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2545 case PAN_SERIF_NORMAL_SANS:
2546 case PAN_SERIF_OBTUSE_SANS:
2547 case PAN_SERIF_PERP_SANS:
2548 case PAN_SERIF_FLARED:
2549 case PAN_SERIF_ROUNDED:
2550 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2555 case PAN_FAMILY_SCRIPT:
2556 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2559 case PAN_FAMILY_DECORATIVE:
2560 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2564 test_negative_width(hdc, lf);
2567 SelectObject(hdc, hfont_old);
2568 DeleteObject(hfont);
2573 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2575 INT *enumed = (INT *)lParam;
2577 if (type == TRUETYPE_FONTTYPE)
2580 test_text_metrics(lf);
2585 static void test_GetTextMetrics(void)
2591 /* Report only once */
2592 if(!pGetGlyphIndicesA)
2593 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2597 memset(&lf, 0, sizeof(lf));
2598 lf.lfCharSet = DEFAULT_CHARSET;
2600 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2601 trace("Tested metrics of %d truetype fonts\n", enumed);
2606 static void test_nonexistent_font(void)
2614 { "Times New Roman Baltic", 186 },
2615 { "Times New Roman CE", 238 },
2616 { "Times New Roman CYR", 204 },
2617 { "Times New Roman Greek", 161 },
2618 { "Times New Roman TUR", 162 }
2624 INT cs, expected_cs, i;
2625 char buf[LF_FACESIZE];
2627 if (!is_truetype_font_installed("Arial") ||
2628 !is_truetype_font_installed("Times New Roman"))
2630 skip("Arial or Times New Roman not installed\n");
2634 expected_cs = GetACP();
2635 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2637 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2640 expected_cs = csi.ciCharset;
2641 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2645 memset(&lf, 0, sizeof(lf));
2647 lf.lfWeight = FW_REGULAR;
2648 lf.lfCharSet = ANSI_CHARSET;
2649 lf.lfPitchAndFamily = FF_SWISS;
2650 strcpy(lf.lfFaceName, "Nonexistent font");
2651 hfont = CreateFontIndirectA(&lf);
2652 hfont = SelectObject(hdc, hfont);
2653 GetTextFaceA(hdc, sizeof(buf), buf);
2654 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2655 cs = GetTextCharset(hdc);
2656 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2657 DeleteObject(SelectObject(hdc, hfont));
2659 memset(&lf, 0, sizeof(lf));
2661 lf.lfWeight = FW_DONTCARE;
2662 strcpy(lf.lfFaceName, "Nonexistent font");
2663 hfont = CreateFontIndirectA(&lf);
2664 hfont = SelectObject(hdc, hfont);
2665 GetTextFaceA(hdc, sizeof(buf), buf);
2666 todo_wine /* Wine uses Arial for all substitutions */
2667 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2668 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2669 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2671 cs = GetTextCharset(hdc);
2672 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2673 DeleteObject(SelectObject(hdc, hfont));
2675 memset(&lf, 0, sizeof(lf));
2677 lf.lfWeight = FW_REGULAR;
2678 strcpy(lf.lfFaceName, "Nonexistent font");
2679 hfont = CreateFontIndirectA(&lf);
2680 hfont = SelectObject(hdc, hfont);
2681 GetTextFaceA(hdc, sizeof(buf), buf);
2682 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2683 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2684 cs = GetTextCharset(hdc);
2685 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2686 DeleteObject(SelectObject(hdc, hfont));
2688 memset(&lf, 0, sizeof(lf));
2690 lf.lfWeight = FW_DONTCARE;
2691 strcpy(lf.lfFaceName, "Times New Roman");
2692 hfont = CreateFontIndirectA(&lf);
2693 hfont = SelectObject(hdc, hfont);
2694 GetTextFaceA(hdc, sizeof(buf), buf);
2695 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2696 cs = GetTextCharset(hdc);
2697 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2698 DeleteObject(SelectObject(hdc, hfont));
2700 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2702 memset(&lf, 0, sizeof(lf));
2704 lf.lfWeight = FW_REGULAR;
2705 strcpy(lf.lfFaceName, font_subst[i].name);
2706 hfont = CreateFontIndirectA(&lf);
2707 hfont = SelectObject(hdc, hfont);
2708 cs = GetTextCharset(hdc);
2709 if (font_subst[i].charset == expected_cs)
2711 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2712 GetTextFaceA(hdc, sizeof(buf), buf);
2713 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2717 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d for font %s\n", cs, font_subst[i].name);
2718 GetTextFaceA(hdc, sizeof(buf), buf);
2719 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2720 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf, font_subst[i].name);
2722 DeleteObject(SelectObject(hdc, hfont));
2724 memset(&lf, 0, sizeof(lf));
2726 lf.lfWeight = FW_DONTCARE;
2727 strcpy(lf.lfFaceName, font_subst[i].name);
2728 hfont = CreateFontIndirectA(&lf);
2729 hfont = SelectObject(hdc, hfont);
2730 GetTextFaceA(hdc, sizeof(buf), buf);
2731 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2732 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2733 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2734 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2735 "got %s for font %s\n", buf, font_subst[i].name);
2736 cs = GetTextCharset(hdc);
2737 ok(cs == expected_cs, "expected %d, got %d for font %s\n", expected_cs, cs, font_subst[i].name);
2738 DeleteObject(SelectObject(hdc, hfont));
2744 static void test_GdiRealizationInfo(void)
2749 HFONT hfont, hfont_old;
2752 if(!pGdiRealizationInfo)
2754 win_skip("GdiRealizationInfo not available\n");
2760 memset(info, 0xcc, sizeof(info));
2761 r = pGdiRealizationInfo(hdc, info);
2762 ok(r != 0, "ret 0\n");
2763 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2764 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2766 if (!is_truetype_font_installed("Arial"))
2768 skip("skipping GdiRealizationInfo with truetype font\n");
2772 memset(&lf, 0, sizeof(lf));
2773 strcpy(lf.lfFaceName, "Arial");
2775 lf.lfWeight = FW_NORMAL;
2776 hfont = CreateFontIndirectA(&lf);
2777 hfont_old = SelectObject(hdc, hfont);
2779 memset(info, 0xcc, sizeof(info));
2780 r = pGdiRealizationInfo(hdc, info);
2781 ok(r != 0, "ret 0\n");
2782 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2783 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2785 DeleteObject(SelectObject(hdc, hfont_old));
2791 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2792 the nul in the count of characters copied when the face name buffer is not
2793 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2794 always includes it. */
2795 static void test_GetTextFace(void)
2797 static const char faceA[] = "Tahoma";
2798 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2801 char bufA[LF_FACESIZE];
2802 WCHAR bufW[LF_FACESIZE];
2807 if(!is_font_installed("Tahoma"))
2809 skip("Tahoma is not installed so skipping this test\n");
2814 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2815 f = CreateFontIndirectA(&fA);
2816 ok(f != NULL, "CreateFontIndirectA failed\n");
2819 g = SelectObject(dc, f);
2820 n = GetTextFaceA(dc, sizeof bufA, bufA);
2821 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2822 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2824 /* Play with the count arg. */
2826 n = GetTextFaceA(dc, 0, bufA);
2827 ok(n == 0, "GetTextFaceA returned %d\n", n);
2828 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2831 n = GetTextFaceA(dc, 1, bufA);
2832 ok(n == 0, "GetTextFaceA returned %d\n", n);
2833 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2835 bufA[0] = 'x'; bufA[1] = 'y';
2836 n = GetTextFaceA(dc, 2, bufA);
2837 ok(n == 1, "GetTextFaceA returned %d\n", n);
2838 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2840 n = GetTextFaceA(dc, 0, NULL);
2841 ok(n == sizeof faceA ||
2842 broken(n == 0), /* win98, winMe */
2843 "GetTextFaceA returned %d\n", n);
2845 DeleteObject(SelectObject(dc, g));
2846 ReleaseDC(NULL, dc);
2849 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2850 SetLastError(0xdeadbeef);
2851 f = CreateFontIndirectW(&fW);
2852 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2854 win_skip("CreateFontIndirectW is not implemented\n");
2857 ok(f != NULL, "CreateFontIndirectW failed\n");
2860 g = SelectObject(dc, f);
2861 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2862 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2863 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2865 /* Play with the count arg. */
2867 n = GetTextFaceW(dc, 0, bufW);
2868 ok(n == 0, "GetTextFaceW returned %d\n", n);
2869 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2872 n = GetTextFaceW(dc, 1, bufW);
2873 ok(n == 1, "GetTextFaceW returned %d\n", n);
2874 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2876 bufW[0] = 'x'; bufW[1] = 'y';
2877 n = GetTextFaceW(dc, 2, bufW);
2878 ok(n == 2, "GetTextFaceW returned %d\n", n);
2879 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2881 n = GetTextFaceW(dc, 0, NULL);
2882 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2884 DeleteObject(SelectObject(dc, g));
2885 ReleaseDC(NULL, dc);
2888 static void test_orientation(void)
2890 static const char test_str[11] = "Test String";
2893 HFONT hfont, old_hfont;
2896 if (!is_truetype_font_installed("Arial"))
2898 skip("Arial is not installed\n");
2902 hdc = CreateCompatibleDC(0);
2903 memset(&lf, 0, sizeof(lf));
2904 lstrcpyA(lf.lfFaceName, "Arial");
2906 lf.lfOrientation = lf.lfEscapement = 900;
2907 hfont = create_font("orientation", &lf);
2908 old_hfont = SelectObject(hdc, hfont);
2909 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2910 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2911 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2912 SelectObject(hdc, old_hfont);
2913 DeleteObject(hfont);
2917 static void test_oemcharset(void)
2921 HFONT hfont, old_hfont;
2924 hdc = CreateCompatibleDC(0);
2925 ZeroMemory(&lf, sizeof(lf));
2927 lf.lfCharSet = OEM_CHARSET;
2928 lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
2929 lstrcpyA(lf.lfFaceName, "Terminal");
2930 hfont = CreateFontIndirectA(&lf);
2931 old_hfont = SelectObject(hdc, hfont);
2932 charset = GetTextCharset(hdc);
2934 ok(charset == OEM_CHARSET, "expected %d charset, got %d\n", OEM_CHARSET, charset);
2935 hfont = SelectObject(hdc, old_hfont);
2936 GetObjectA(hfont, sizeof(clf), &clf);
2937 ok(!lstrcmpA(clf.lfFaceName, lf.lfFaceName), "expected %s face name, got %s\n", lf.lfFaceName, clf.lfFaceName);
2938 ok(clf.lfPitchAndFamily == lf.lfPitchAndFamily, "expected %x family, got %x\n", lf.lfPitchAndFamily, clf.lfPitchAndFamily);
2939 ok(clf.lfCharSet == lf.lfCharSet, "expected %d charset, got %d\n", lf.lfCharSet, clf.lfCharSet);
2940 ok(clf.lfHeight == lf.lfHeight, "expected %d height, got %d\n", lf.lfHeight, clf.lfHeight);
2941 DeleteObject(hfont);
2945 static void test_GetGlyphOutline(void)
2947 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2951 HFONT hfont, old_hfont;
2954 if (!is_truetype_font_installed("Tahoma"))
2956 skip("Tahoma is not installed\n");
2960 hdc = CreateCompatibleDC(0);
2961 memset(&lf, 0, sizeof(lf));
2963 lstrcpyA(lf.lfFaceName, "Tahoma");
2964 SetLastError(0xdeadbeef);
2965 hfont = CreateFontIndirectA(&lf);
2966 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2967 old_hfont = SelectObject(hdc, hfont);
2969 memset(&gm, 0, sizeof(gm));
2970 SetLastError(0xdeadbeef);
2971 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2972 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2974 memset(&gm, 0, sizeof(gm));
2975 SetLastError(0xdeadbeef);
2976 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2977 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2978 ok(GetLastError() == 0xdeadbeef ||
2979 GetLastError() == ERROR_INVALID_PARAMETER, /* win98, winMe */
2980 "expected 0xdeadbeef, got %u\n", GetLastError());
2982 memset(&gm, 0, sizeof(gm));
2983 SetLastError(0xdeadbeef);
2984 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2985 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2986 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
2988 memset(&gm, 0, sizeof(gm));
2989 SetLastError(0xdeadbeef);
2990 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2991 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2993 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
2994 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2997 /* test for needed buffer size request on space char */
2998 memset(&gm, 0, sizeof(gm));
2999 SetLastError(0xdeadbeef);
3000 ret = GetGlyphOutlineW(hdc, ' ', GGO_NATIVE, &gm, 0, NULL, &mat);
3001 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3002 ok(ret == 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3004 /* requesting buffer size for space char + error */
3005 memset(&gm, 0, sizeof(gm));
3006 SetLastError(0xdeadbeef);
3007 ret = GetGlyphOutlineW(0, ' ', GGO_NATIVE, &gm, 0, NULL, NULL);
3008 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
3010 ok(ret == GDI_ERROR, "GetGlyphOutlineW should return GDI_ERROR\n");
3011 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3014 SelectObject(hdc, old_hfont);
3015 DeleteObject(hfont);
3019 /* bug #9995: there is a limit to the character width that can be specified */
3020 static void test_GetTextMetrics2(const char *fontname, int font_height)
3026 int ave_width, height, width, ratio, scale;
3028 if (!is_truetype_font_installed( fontname)) {
3029 skip("%s is not installed\n", fontname);
3032 hdc = CreateCompatibleDC(0);
3033 ok( hdc != NULL, "CreateCompatibleDC failed\n");
3034 /* select width = 0 */
3035 hf = CreateFontA(font_height, 0, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3036 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3037 DEFAULT_QUALITY, VARIABLE_PITCH,
3039 ok( hf != NULL, "CreateFontA(%s, %d) failed\n", fontname, font_height);
3040 of = SelectObject( hdc, hf);
3041 ret = GetTextMetricsA( hdc, &tm);
3042 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
3043 height = tm.tmHeight;
3044 ave_width = tm.tmAveCharWidth;
3045 SelectObject( hdc, of);
3048 trace("height %d, ave width %d\n", height, ave_width);
3050 for (width = ave_width * 2; /* nothing*/; width += ave_width)
3052 hf = CreateFont(height, width, 0, 0, FW_REGULAR, FALSE, FALSE, FALSE,
3053 DEFAULT_CHARSET, OUT_TT_PRECIS, CLIP_LH_ANGLES,
3054 DEFAULT_QUALITY, VARIABLE_PITCH, fontname);
3055 ok(hf != 0, "CreateFont failed\n");
3056 of = SelectObject(hdc, hf);
3057 ret = GetTextMetrics(hdc, &tm);
3058 ok(ret, "GetTextMetrics error %u\n", GetLastError());
3059 SelectObject(hdc, of);
3062 if (match_off_by_1(tm.tmAveCharWidth, ave_width) || width / height > 200)
3068 ratio = width / height;
3069 scale = width / ave_width;
3071 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3072 width, height, ratio, width, ave_width, scale);
3074 ok(ratio >= 90 && ratio <= 110, "expected width/height ratio 90-110, got %d\n", ratio);
3077 static void test_CreateFontIndirect(void)
3079 LOGFONTA lf, getobj_lf;
3082 char TestName[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3084 memset(&lf, 0, sizeof(lf));
3085 lf.lfCharSet = ANSI_CHARSET;
3086 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
3089 lf.lfQuality = DEFAULT_QUALITY;
3090 lf.lfItalic = FALSE;
3091 lf.lfWeight = FW_DONTCARE;
3093 for (i = 0; i < sizeof(TestName)/sizeof(TestName[0]); i++)
3095 lstrcpyA(lf.lfFaceName, TestName[i]);
3096 hfont = CreateFontIndirectA(&lf);
3097 ok(hfont != 0, "CreateFontIndirectA failed\n");
3098 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
3099 ok(lf.lfItalic == getobj_lf.lfItalic, "lfItalic: expect %02x got %02x\n", lf.lfItalic, getobj_lf.lfItalic);
3100 ok(lf.lfWeight == getobj_lf.lfWeight ||
3101 broken((SHORT)lf.lfWeight == getobj_lf.lfWeight), /* win9x */
3102 "lfWeight: expect %08x got %08x\n", lf.lfWeight, getobj_lf.lfWeight);
3103 ok(!lstrcmpA(lf.lfFaceName, getobj_lf.lfFaceName) ||
3104 broken(!memcmp(lf.lfFaceName, getobj_lf.lfFaceName, LF_FACESIZE-1)), /* win9x doesn't ensure '\0' termination */
3105 "font names don't match: %s != %s\n", lf.lfFaceName, getobj_lf.lfFaceName);
3106 DeleteObject(hfont);
3116 test_outline_font();
3117 test_bitmap_font_metrics();
3118 test_GdiGetCharDimensions();
3119 test_GetCharABCWidths();
3120 test_text_extents();
3121 test_GetGlyphIndices();
3122 test_GetKerningPairs();
3123 test_GetOutlineTextMetrics();
3124 test_SetTextJustification();
3125 test_font_charset();
3126 test_GetFontUnicodeRanges();
3127 test_nonexistent_font();
3129 test_height_selection();
3131 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3132 * I'd like to avoid them in this test.
3134 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
3135 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
3136 if (is_truetype_font_installed("Arial Black") &&
3137 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3139 test_EnumFontFamilies("", ANSI_CHARSET);
3140 test_EnumFontFamilies("", SYMBOL_CHARSET);
3141 test_EnumFontFamilies("", DEFAULT_CHARSET);
3144 skip("Arial Black or Symbol/Wingdings is not installed\n");
3145 test_GetTextMetrics();
3146 test_GdiRealizationInfo();
3148 test_GetGlyphOutline();
3149 test_GetTextMetrics2("Tahoma", -11);
3150 test_GetTextMetrics2("Tahoma", -55);
3151 test_GetTextMetrics2("Tahoma", -110);
3152 test_GetTextMetrics2("Arial", -11);
3153 test_GetTextMetrics2("Arial", -55);
3154 test_GetTextMetrics2("Arial", -110);
3155 test_CreateFontIndirect();