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 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
35 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
36 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
37 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
38 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
39 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
40 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
42 static HMODULE hgdi32 = 0;
44 static void init(void)
46 hgdi32 = GetModuleHandleA("gdi32.dll");
48 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
49 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
50 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
51 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
52 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
53 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
56 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
58 if (type != TRUETYPE_FONTTYPE) return 1;
63 static BOOL is_truetype_font_installed(const char *name)
68 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
75 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
80 static BOOL is_font_installed(const char *name)
85 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
92 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
100 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
101 /* NT4 tries to be clever and only returns the minimum length */
102 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
104 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
105 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
106 ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
107 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
108 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
111 static HFONT create_font(const char* test, const LOGFONTA* lf)
113 HFONT hfont = CreateFontIndirectA(lf);
114 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
116 check_font(test, lf, hfont);
120 static void test_logfont(void)
125 memset(&lf, 0, sizeof lf);
127 lf.lfCharSet = ANSI_CHARSET;
128 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
129 lf.lfWeight = FW_DONTCARE;
132 lf.lfQuality = DEFAULT_QUALITY;
134 lstrcpyA(lf.lfFaceName, "Arial");
135 hfont = create_font("Arial", &lf);
138 memset(&lf, 'A', sizeof(lf));
139 hfont = CreateFontIndirectA(&lf);
140 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
142 lf.lfFaceName[LF_FACESIZE - 1] = 0;
143 check_font("AAA...", &lf, hfont);
147 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
149 if (type & RASTER_FONTTYPE)
151 LOGFONT *lf = (LOGFONT *)lParam;
153 return 0; /* stop enumeration */
156 return 1; /* continue enumeration */
159 static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
160 INT test_str_len, const TEXTMETRICA *tm_orig,
161 const SIZE *size_orig, INT width_orig,
162 INT scale_x, INT scale_y)
172 old_hfont = SelectObject(hdc, hfont);
174 GetTextMetricsA(hdc, &tm);
176 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
177 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
178 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
179 ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
181 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
183 ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x);
184 ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y);
186 GetCharWidthA(hdc, 'A', 'A', &width);
188 ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
190 SelectObject(hdc, old_hfont);
193 /* see whether GDI scales bitmap font metrics */
194 static void test_bitmap_font(void)
196 static const char test_str[11] = "Test String";
199 HFONT hfont, old_hfont;
202 INT ret, i, width_orig, height_orig;
206 /* "System" has only 1 pixel size defined, otherwise the test breaks */
207 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
211 trace("no bitmap fonts were found, skipping the test\n");
215 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
217 height_orig = bitmap_lf.lfHeight;
218 hfont = create_font("bitmap", &bitmap_lf);
220 old_hfont = SelectObject(hdc, hfont);
221 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
222 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
223 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
224 SelectObject(hdc, old_hfont);
227 /* test fractional scaling */
228 for (i = 1; i < height_orig; i++)
230 hfont = create_font("fractional", &bitmap_lf);
231 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
235 /* test integer scaling 3x2 */
236 bitmap_lf.lfHeight = height_orig * 2;
237 bitmap_lf.lfWidth *= 3;
238 hfont = create_font("3x2", &bitmap_lf);
241 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
245 /* test integer scaling 3x3 */
246 bitmap_lf.lfHeight = height_orig * 3;
247 bitmap_lf.lfWidth = 0;
248 hfont = create_font("3x3", &bitmap_lf);
252 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
259 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
261 LOGFONT *lf = (LOGFONT *)lParam;
263 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
266 return 0; /* stop enumeration */
268 return 1; /* continue enumeration */
271 #define CP1252_BIT 0x00000001
272 #define CP1250_BIT 0x00000002
273 #define CP1251_BIT 0x00000004
274 #define CP1253_BIT 0x00000008
275 #define CP1254_BIT 0x00000010
276 #define CP1255_BIT 0x00000020
277 #define CP1256_BIT 0x00000040
278 #define CP1257_BIT 0x00000080
279 #define CP1258_BIT 0x00000100
280 #define CP874_BIT 0x00010000
281 #define CP932_BIT 0x00020000
282 #define CP936_BIT 0x00040000
283 #define CP949_BIT 0x00080000
284 #define CP950_BIT 0x00100000
286 static void test_bitmap_font_metrics(void)
288 static const struct font_data
290 const char face_name[LF_FACESIZE];
291 int weight, height, ascent, descent, int_leading, ext_leading;
292 int ave_char_width, max_char_width;
296 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT | CP1250_BIT | CP1251_BIT },
297 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT | CP1250_BIT | CP1251_BIT },
298 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, CP1252_BIT | CP1251_BIT },
299 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, CP1250_BIT },
300 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, CP1252_BIT },
301 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, CP1250_BIT },
302 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, CP1251_BIT },
303 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, CP1252_BIT },
304 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, CP1250_BIT },
305 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, CP1251_BIT },
306 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, CP1252_BIT | CP1250_BIT | CP1251_BIT },
307 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
308 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
309 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
310 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT },
311 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, CP1250_BIT | CP1251_BIT },
312 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, CP1252_BIT | CP1250_BIT },
313 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, CP1251_BIT },
314 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, CP1252_BIT | CP1250_BIT },
315 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, CP1251_BIT },
316 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, CP1252_BIT },
317 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, CP1250_BIT },
318 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, CP1251_BIT },
319 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, CP1252_BIT },
320 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, CP1250_BIT },
321 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, CP1251_BIT },
322 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, CP1252_BIT | CP1250_BIT },
323 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, CP1251_BIT },
324 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, CP1252_BIT | CP1250_BIT | CP1251_BIT },
325 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
326 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, CP1252_BIT | CP1250_BIT | CP1251_BIT },
327 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT },
328 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, CP1250_BIT | CP1251_BIT },
330 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
331 * require a new system.sfd for that font
333 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, CP932_BIT },
334 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT },
335 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT | CP1251_BIT },
336 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, CP932_BIT },
337 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT },
338 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT | CP1251_BIT },
339 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, CP932_BIT },
340 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT },
341 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT | CP1251_BIT },
342 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, CP932_BIT },
343 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT },
344 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT | CP1251_BIT },
345 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, CP932_BIT },
346 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
347 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
348 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, CP932_BIT },
349 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
350 /* No proper small font for Japanese yet */
351 /* { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, CP932_BIT }, */
352 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT | CP1250_BIT },
353 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT },
354 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, CP932_BIT }
356 /* FIXME: add "Terminal" */
360 HFONT hfont, old_hfont;
364 hdc = CreateCompatibleDC(0);
367 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
371 memset(&lf, 0, sizeof(lf));
373 lf.lfHeight = fd[i].height;
374 strcpy(lf.lfFaceName, fd[i].face_name);
376 for(bit = 0; bit < 32; bit++)
383 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
384 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
386 lf.lfCharSet = csi.ciCharset;
387 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
390 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
392 hfont = create_font(lf.lfFaceName, &lf);
393 old_hfont = SelectObject(hdc, hfont);
394 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
396 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);
397 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);
398 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);
399 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);
400 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);
401 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);
402 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);
404 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
405 that make the max width bigger */
406 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
407 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);
409 SelectObject(hdc, old_hfont);
417 static void test_GdiGetCharDimensions(void)
423 LONG avgwidth, height;
424 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
426 if (!pGdiGetCharDimensions)
428 skip("GdiGetCharDimensions not available on this platform\n");
432 hdc = CreateCompatibleDC(NULL);
434 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
435 avgwidth = ((size.cx / 26) + 1) / 2;
437 ret = pGdiGetCharDimensions(hdc, &tm, &height);
438 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
439 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
441 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
442 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
444 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
445 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
448 ret = pGdiGetCharDimensions(hdc, NULL, &height);
449 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
450 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
455 static void test_GetCharABCWidths(void)
457 static const WCHAR str[] = {'a',0};
466 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
468 skip("GetCharABCWidthsW/I not available on this platform\n");
472 memset(&lf, 0, sizeof(lf));
473 strcpy(lf.lfFaceName, "System");
476 hfont = CreateFontIndirectA(&lf);
478 hfont = SelectObject(hdc, hfont);
480 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
481 ok(nb == 1, "pGetGlyphIndicesW should have returned 1\n");
483 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
484 ok(!ret, "GetCharABCWidthsI should have failed\n");
486 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
487 ok(!ret, "GetCharABCWidthsI should have failed\n");
489 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
490 ok(ret, "GetCharABCWidthsI should have succeeded\n");
492 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
493 ok(!ret, "GetCharABCWidthsW should have failed\n");
495 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
496 ok(!ret, "GetCharABCWidthsW should have failed\n");
498 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
499 ok(!ret, "GetCharABCWidthsW should have failed\n");
501 hfont = SelectObject(hdc, hfont);
503 ReleaseDC(NULL, hdc);
506 static void test_text_extents(void)
508 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
510 INT i, len, fit1, fit2;
518 memset(&lf, 0, sizeof(lf));
519 strcpy(lf.lfFaceName, "Arial");
522 hfont = CreateFontIndirectA(&lf);
524 hfont = SelectObject(hdc, hfont);
525 GetTextMetricsA(hdc, &tm);
526 GetTextExtentPointA(hdc, "o", 1, &sz);
527 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
529 SetLastError(0xdeadbeef);
530 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
531 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
533 skip("Skipping remainder of text extents test on a Win9x platform\n");
534 hfont = SelectObject(hdc, hfont);
541 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
542 extents[0] = 1; /* So that the increasing sequence test will fail
543 if the extents array is untouched. */
544 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
545 GetTextExtentPointW(hdc, wt, len, &sz2);
547 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
548 /* Because of the '\n' in the string GetTextExtentExPoint and
549 GetTextExtentPoint return different widths under Win2k, but
550 under WinXP they return the same width. So we don't test that
553 for (i = 1; i < len; ++i)
554 ok(extents[i-1] <= extents[i],
555 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
557 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
558 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
559 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
560 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
561 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
562 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
563 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
564 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
565 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
566 ok(extents[0] == extents[2] && extents[1] == extents[3],
567 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
568 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
569 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
570 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
571 HeapFree(GetProcessHeap(), 0, extents);
573 hfont = SelectObject(hdc, hfont);
575 ReleaseDC(NULL, hdc);
578 static void test_GetGlyphIndices(void)
585 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
586 WORD glyphs[(sizeof(testtext)/2)-1];
589 if (!pGetGlyphIndicesW) {
590 skip("GetGlyphIndices not available on platform\n");
594 if(!is_font_installed("Symbol"))
596 skip("Symbol is not installed so skipping this test\n");
600 memset(&lf, 0, sizeof(lf));
601 strcpy(lf.lfFaceName, "Symbol");
604 hfont = CreateFontIndirectA(&lf);
607 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
608 flags |= GGI_MARK_NONEXISTING_GLYPHS;
609 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
610 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
611 ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
613 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
614 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
615 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
616 textm.tmDefaultChar, glyphs[4]);
619 static void test_GetKerningPairs(void)
621 static const struct kerning_data
623 const char face_name[LF_FACESIZE];
625 /* some interesting fields from OUTLINETEXTMETRIC */
626 LONG tmHeight, tmAscent, tmDescent;
631 UINT otmsCapEmHeight;
636 UINT otmusMinimumPPEM;
637 /* small subset of kerning pairs to test */
638 DWORD total_kern_pairs;
639 const KERNINGPAIR kern_pair[26];
642 {"Arial", 12, 12, 9, 3,
643 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
646 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
647 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
648 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
649 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
650 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
651 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
652 {933,970,+1},{933,972,-1}
655 {"Arial", -34, 39, 32, 7,
656 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
659 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
660 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
661 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
662 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
663 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
664 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
665 {933,970,+2},{933,972,-3}
668 { "Arial", 120, 120, 97, 23,
669 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
672 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
673 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
674 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
675 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
676 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
677 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
678 {933,970,+6},{933,972,-10}
681 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
682 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
683 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
686 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
687 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
688 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
689 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
690 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
691 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
692 {933,970,+54},{933,972,-83}
698 HFONT hfont, hfont_old;
699 KERNINGPAIR *kern_pair;
701 DWORD total_kern_pairs, ret, i, n, matches;
705 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
706 * which may render this test unusable, so we're trying to avoid that.
708 SetLastError(0xdeadbeef);
709 GetKerningPairsW(hdc, 0, NULL);
710 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
712 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
717 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
719 OUTLINETEXTMETRICW otm;
721 if (!is_font_installed(kd[i].face_name))
723 trace("%s is not installed so skipping this test\n", kd[i].face_name);
727 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
729 memset(&lf, 0, sizeof(lf));
730 strcpy(lf.lfFaceName, kd[i].face_name);
731 lf.lfHeight = kd[i].height;
732 hfont = CreateFontIndirect(&lf);
735 hfont_old = SelectObject(hdc, hfont);
737 SetLastError(0xdeadbeef);
738 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
739 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
741 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
742 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
743 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
744 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
745 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
746 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
748 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
749 kd[i].otmEMSquare, otm.otmEMSquare);
750 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
751 kd[i].otmAscent, otm.otmAscent);
752 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
753 kd[i].otmDescent, otm.otmDescent);
754 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
755 kd[i].otmLineGap, otm.otmLineGap);
757 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
758 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
759 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
760 kd[i].otmsXHeight, otm.otmsXHeight);
761 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
762 kd[i].otmMacAscent, otm.otmMacAscent);
763 ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
764 kd[i].otmMacDescent, otm.otmMacDescent);
765 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
766 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
767 kd[i].otmMacLineGap, otm.otmMacLineGap);
768 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
769 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
772 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
773 trace("total_kern_pairs %u\n", total_kern_pairs);
774 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
776 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
777 SetLastError(0xdeadbeef);
778 ret = GetKerningPairsW(hdc, 0, kern_pair);
779 ok(GetLastError() == ERROR_INVALID_PARAMETER,
780 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
781 ok(ret == 0, "got %lu, expected 0\n", ret);
784 ret = GetKerningPairsW(hdc, 100, NULL);
785 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
787 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
788 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
790 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
791 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
795 for (n = 0; n < ret; n++)
799 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
800 trace("{'%c','%c',%d},\n",
801 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
803 for (j = 0; j < kd[i].total_kern_pairs; j++)
805 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
806 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
808 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
809 "pair %d:%d got %d, expected %d\n",
810 kern_pair[n].wFirst, kern_pair[n].wSecond,
811 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
817 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
818 matches, kd[i].total_kern_pairs);
820 HeapFree(GetProcessHeap(), 0, kern_pair);
822 SelectObject(hdc, hfont_old);
829 static void test_GetOutlineTextMetrics(void)
831 OUTLINETEXTMETRIC *otm;
833 HFONT hfont, hfont_old;
837 if (!is_font_installed("Arial"))
839 skip("Arial is not installed\n");
845 memset(&lf, 0, sizeof(lf));
846 strcpy(lf.lfFaceName, "Arial");
848 lf.lfWeight = FW_NORMAL;
849 lf.lfPitchAndFamily = DEFAULT_PITCH;
850 lf.lfQuality = PROOF_QUALITY;
851 hfont = CreateFontIndirect(&lf);
854 hfont_old = SelectObject(hdc, hfont);
855 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
856 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
858 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
860 memset(otm, 0xAA, otm_size);
861 SetLastError(0xdeadbeef);
862 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
863 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
864 ok(ret == 1 /* Win9x */ ||
865 ret == otm->otmSize /* XP*/,
866 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
867 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
869 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
870 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
871 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
872 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
875 memset(otm, 0xAA, otm_size);
876 SetLastError(0xdeadbeef);
877 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
878 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
879 ok(ret == 1 /* Win9x */ ||
880 ret == otm->otmSize /* XP*/,
881 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
882 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
884 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
885 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
886 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
887 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
890 /* ask about truncated data */
891 memset(otm, 0xAA, otm_size);
892 SetLastError(0xdeadbeef);
893 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
894 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
895 ok(ret == 1 /* Win9x */ ||
896 ret == otm->otmSize /* XP*/,
897 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
898 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
900 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
901 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
902 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
904 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
906 HeapFree(GetProcessHeap(), 0, otm);
908 SelectObject(hdc, hfont_old);
914 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
918 outputWidth = 0, /* to test TabbedTextOut() */
919 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
920 areaWidth = clientArea->right - clientArea->left,
922 BOOL lastExtent = FALSE;
923 PSTR pFirstChar, pLastChar;
929 int GetTextExtentExPointWWidth;
930 int TabbedTextOutWidth;
933 GetTextMetricsA(hdc, &tm);
937 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
943 /* if not at the end of the string, ... */
944 if (*str == '\0') break;
945 /* ... add the next word to the current extent */
946 while (*str != '\0' && *str++ != tm.tmBreakChar);
948 SetTextJustification(hdc, 0, 0);
949 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
950 } while ((int) size.cx < areaWidth);
952 /* ignore trailing break chars */
954 while (*(pLastChar - 1) == tm.tmBreakChar)
960 if (*str == '\0' || breakCount <= 0) pLastChar = str;
962 SetTextJustification(hdc, 0, 0);
963 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
965 /* do not justify the last extent */
966 if (*str != '\0' && breakCount > 0)
968 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
969 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
970 justifiedWidth = size.cx;
972 else lastExtent = TRUE;
974 x = clientArea->left;
976 outputWidth = LOWORD(TabbedTextOut(
977 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
979 /* catch errors and report them */
980 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
982 memset(error[nErrors].extent, 0, 100);
983 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
984 error[nErrors].TabbedTextOutWidth = outputWidth;
985 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
991 } while (*str && y < clientArea->bottom);
993 for (e = 0; e < nErrors; e++)
995 ok(error[e].TabbedTextOutWidth == areaWidth,
996 "The output text (\"%s\") width should be %d, not %d.\n",
997 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
998 /* The width returned by GetTextExtentPoint32() is exactly the same
999 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1000 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1001 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1002 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1006 static void test_SetTextJustification(void)
1013 static char testText[] =
1014 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1015 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1016 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1017 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1018 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1019 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1020 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1022 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1023 GetClientRect( hwnd, &clientArea );
1024 hdc = GetDC( hwnd );
1026 memset(&lf, 0, sizeof lf);
1027 lf.lfCharSet = ANSI_CHARSET;
1028 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1029 lf.lfWeight = FW_DONTCARE;
1031 lf.lfQuality = DEFAULT_QUALITY;
1032 lstrcpyA(lf.lfFaceName, "Times New Roman");
1033 hfont = create_font("Times New Roman", &lf);
1034 SelectObject(hdc, hfont);
1036 testJustification(hdc, testText, &clientArea);
1038 DeleteObject(hfont);
1039 ReleaseDC(hwnd, hdc);
1040 DestroyWindow(hwnd);
1043 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1047 HFONT hfont, hfont_old;
1054 assert(count <= 128);
1056 memset(&lf, 0, sizeof(lf));
1058 lf.lfCharSet = charset;
1060 lstrcpyA(lf.lfFaceName, "Arial");
1061 SetLastError(0xdeadbeef);
1062 hfont = CreateFontIndirectA(&lf);
1063 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1066 hfont_old = SelectObject(hdc, hfont);
1068 cs = GetTextCharsetInfo(hdc, &fs, 0);
1069 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1071 SetLastError(0xdeadbeef);
1072 ret = GetTextFace(hdc, sizeof(name), name);
1073 ok(ret, "GetTextFace error %u\n", GetLastError());
1075 if (charset == SYMBOL_CHARSET)
1077 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1078 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1082 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1083 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1086 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1088 trace("Can't find codepage for charset %d\n", cs);
1092 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1097 WCHAR unicode_buf[128];
1099 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1101 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1103 SetLastError(0xdeadbeef);
1104 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1105 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1111 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1113 SetLastError(0xdeadbeef);
1114 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1115 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1118 SelectObject(hdc, hfont_old);
1119 DeleteObject(hfont);
1126 static void test_font_charset(void)
1128 static struct charset_data
1132 WORD font_idxA[128], font_idxW[128];
1135 { ANSI_CHARSET, 1252 },
1136 { RUSSIAN_CHARSET, 1251 },
1137 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1141 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1143 skip("Skipping the font charset test on a Win9x platform\n");
1147 if (!is_font_installed("Arial"))
1149 skip("Arial is not installed\n");
1153 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1155 if (cd[i].charset == SYMBOL_CHARSET)
1157 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1159 skip("Symbol or Wingdings is not installed\n");
1163 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1164 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1165 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1168 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1171 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1172 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1175 skip("Symbol or Wingdings is not installed\n");
1178 static void test_GetFontUnicodeRanges(void)
1182 HFONT hfont, hfont_old;
1186 if (!pGetFontUnicodeRanges)
1188 skip("GetFontUnicodeRanges not available before W2K\n");
1192 memset(&lf, 0, sizeof(lf));
1193 lstrcpyA(lf.lfFaceName, "Arial");
1194 hfont = create_font("Arial", &lf);
1197 hfont_old = SelectObject(hdc, hfont);
1199 size = pGetFontUnicodeRanges(NULL, NULL);
1200 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1202 size = pGetFontUnicodeRanges(hdc, NULL);
1203 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1205 gs = HeapAlloc(GetProcessHeap(), 0, size);
1207 size = pGetFontUnicodeRanges(hdc, gs);
1208 ok(size, "GetFontUnicodeRanges failed\n");
1210 for (i = 0; i < gs->cRanges; i++)
1211 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1213 trace("found %u ranges\n", gs->cRanges);
1215 HeapFree(GetProcessHeap(), 0, gs);
1217 SelectObject(hdc, hfont_old);
1218 DeleteObject(hfont);
1219 ReleaseDC(NULL, hdc);
1222 #define MAX_ENUM_FONTS 256
1224 struct enum_font_data
1227 LOGFONT lf[MAX_ENUM_FONTS];
1230 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1232 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1234 if (type != TRUETYPE_FONTTYPE) return 1;
1236 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1237 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1239 if (efd->total < MAX_ENUM_FONTS)
1240 efd->lf[efd->total++] = *lf;
1245 static void get_charset_stats(struct enum_font_data *efd,
1246 int *ansi_charset, int *symbol_charset,
1247 int *russian_charset)
1252 *symbol_charset = 0;
1253 *russian_charset = 0;
1255 for (i = 0; i < efd->total; i++)
1257 switch (efd->lf[i].lfCharSet)
1262 case SYMBOL_CHARSET:
1263 (*symbol_charset)++;
1265 case RUSSIAN_CHARSET:
1266 (*russian_charset)++;
1272 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1274 struct enum_font_data efd;
1277 int i, ret, ansi_charset, symbol_charset, russian_charset;
1279 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1281 if (*font_name && !is_truetype_font_installed(font_name))
1283 skip("%s is not installed\n", font_name);
1289 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1290 * while EnumFontFamiliesEx doesn't.
1292 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1295 SetLastError(0xdeadbeef);
1296 ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1297 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1298 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1299 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1300 ansi_charset, symbol_charset, russian_charset);
1301 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1302 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1303 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1304 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1308 SetLastError(0xdeadbeef);
1309 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1310 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1311 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1312 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1313 ansi_charset, symbol_charset, russian_charset,
1314 *font_name ? font_name : "<empty>");
1316 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1318 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1319 for (i = 0; i < efd.total; i++)
1321 /* FIXME: remove completely once Wine is fixed */
1322 if (efd.lf[i].lfCharSet != font_charset)
1325 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1328 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1329 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1330 font_name, efd.lf[i].lfFaceName);
1333 memset(&lf, 0, sizeof(lf));
1334 lf.lfCharSet = ANSI_CHARSET;
1335 lstrcpy(lf.lfFaceName, font_name);
1337 SetLastError(0xdeadbeef);
1338 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1339 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1340 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1341 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1342 ansi_charset, symbol_charset, russian_charset,
1343 *font_name ? font_name : "<empty>");
1344 if (font_charset == SYMBOL_CHARSET)
1347 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1349 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1353 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1354 for (i = 0; i < efd.total; i++)
1356 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1358 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1359 font_name, efd.lf[i].lfFaceName);
1363 /* DEFAULT_CHARSET should enumerate all available charsets */
1364 memset(&lf, 0, sizeof(lf));
1365 lf.lfCharSet = DEFAULT_CHARSET;
1366 lstrcpy(lf.lfFaceName, font_name);
1368 SetLastError(0xdeadbeef);
1369 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1370 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1371 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1372 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1373 ansi_charset, symbol_charset, russian_charset,
1374 *font_name ? font_name : "<empty>");
1375 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1376 for (i = 0; i < efd.total; i++)
1379 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1380 font_name, efd.lf[i].lfFaceName);
1384 switch (font_charset)
1387 ok(ansi_charset > 0,
1388 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1390 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1391 ok(russian_charset > 0,
1392 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1394 case SYMBOL_CHARSET:
1396 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1398 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1399 ok(!russian_charset,
1400 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1402 case DEFAULT_CHARSET:
1403 ok(ansi_charset > 0,
1404 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1405 ok(symbol_charset > 0,
1406 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1407 ok(russian_charset > 0,
1408 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1414 ok(ansi_charset > 0,
1415 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1416 ok(symbol_charset > 0,
1417 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1418 ok(russian_charset > 0,
1419 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1422 memset(&lf, 0, sizeof(lf));
1423 lf.lfCharSet = SYMBOL_CHARSET;
1424 lstrcpy(lf.lfFaceName, font_name);
1426 SetLastError(0xdeadbeef);
1427 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1428 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1429 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1430 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1431 ansi_charset, symbol_charset, russian_charset,
1432 *font_name ? font_name : "<empty>");
1433 if (*font_name && font_charset == ANSI_CHARSET)
1434 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1437 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1438 for (i = 0; i < efd.total; i++)
1440 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1442 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1443 font_name, efd.lf[i].lfFaceName);
1447 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1448 ok(symbol_charset > 0,
1449 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1450 ok(!russian_charset,
1451 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1457 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1458 #include "pshpack2.h"
1462 SHORT xAvgCharWidth;
1463 USHORT usWeightClass;
1464 USHORT usWidthClass;
1466 SHORT ySubscriptXSize;
1467 SHORT ySubscriptYSize;
1468 SHORT ySubscriptXOffset;
1469 SHORT ySubscriptYOffset;
1470 SHORT ySuperscriptXSize;
1471 SHORT ySuperscriptYSize;
1472 SHORT ySuperscriptXOffset;
1473 SHORT ySuperscriptYOffset;
1474 SHORT yStrikeoutSize;
1475 SHORT yStrikeoutPosition;
1478 ULONG ulUnicodeRange1;
1479 ULONG ulUnicodeRange2;
1480 ULONG ulUnicodeRange3;
1481 ULONG ulUnicodeRange4;
1484 USHORT usFirstCharIndex;
1485 USHORT usLastCharIndex;
1486 /* According to the Apple spec, original version didn't have the below fields,
1487 * version numbers were taked from the OpenType spec.
1489 /* version 0 (TrueType 1.5) */
1490 USHORT sTypoAscender;
1491 USHORT sTypoDescender;
1492 USHORT sTypoLineGap;
1494 USHORT usWinDescent;
1495 /* version 1 (TrueType 1.66) */
1496 ULONG ulCodePageRange1;
1497 ULONG ulCodePageRange2;
1498 /* version 2 (OpenType 1.2) */
1501 USHORT usDefaultChar;
1503 USHORT usMaxContext;
1505 #include "poppack.h"
1507 #ifdef WORDS_BIGENDIAN
1508 #define GET_BE_WORD(x) (x)
1510 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1513 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1514 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1515 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1516 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1518 static void test_text_metrics(const LOGFONTA *lf)
1521 HFONT hfont, hfont_old;
1524 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1529 const char *font_name = lf->lfFaceName;
1531 trace("Testing font metrics for %s, charset %d\n", font_name, lf->lfCharSet);
1535 SetLastError(0xdeadbeef);
1536 hfont = CreateFontIndirectA(lf);
1537 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1539 hfont_old = SelectObject(hdc, hfont);
1541 if(lf->lfWidth > 0) {
1542 HFONT hfont2, hfont_prev;
1543 GLYPHMETRICS gm1, gm2;
1545 MAT2 mat2 = { {0,1}, {0,0}, {0,0}, {0,1} };
1547 /* negative widths are handled just as positive ones */
1550 SetLastError(0xdeadbeef);
1551 hfont2 = CreateFontIndirectA(&lf2);
1552 ok(hfont2 != 0, "CreateFontIndirect error %u\n", GetLastError());
1553 hfont_prev = SelectObject(hdc, hfont2);
1555 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1556 memset(&gm1, 0xab, sizeof(gm1));
1557 SetLastError(0xdeadbeef);
1558 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat2);
1559 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1561 SelectObject(hdc, hfont_prev);
1562 DeleteObject(hfont2);
1564 memset(&gm2, 0xbb, sizeof(gm2));
1565 SetLastError(0xdeadbeef);
1566 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat2);
1567 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1569 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1570 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1571 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1572 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1573 gm1.gmCellIncX == gm2.gmCellIncX &&
1574 gm1.gmCellIncY == gm2.gmCellIncY,
1575 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1576 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1577 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1578 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1579 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1582 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1583 if (size == GDI_ERROR)
1585 trace("OS/2 chunk was not found\n");
1588 if (size > sizeof(tt_os2))
1590 trace("got too large OS/2 chunk of size %u\n", size);
1591 size = sizeof(tt_os2);
1594 memset(&tt_os2, 0, sizeof(tt_os2));
1595 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1596 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1598 version = GET_BE_WORD(tt_os2.version);
1599 trace("OS/2 chunk version %u, vendor %4.4s\n", version, (LPCSTR)&tt_os2.achVendID);
1601 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
1602 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
1603 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
1604 break_char = GET_BE_WORD(tt_os2.usBreakChar);
1606 trace("for %s first %x, last %x, default %x, break %x\n", font_name,
1607 first_unicode_char, last_unicode_char, default_char, break_char);
1609 SetLastError(0xdeadbeef);
1610 ret = GetTextMetricsA(hdc, &tmA);
1611 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
1612 trace("A: first %x, last %x, default %x, break %x\n",
1613 tmA.tmFirstChar, tmA.tmLastChar, tmA.tmDefaultChar, tmA.tmBreakChar);
1615 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1616 test_char = min(first_unicode_char - 1, 255);
1617 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
1618 font_name, tmA.tmFirstChar, test_char);
1620 if (lf->lfCharSet == SYMBOL_CHARSET)
1622 test_char = min(last_unicode_char - 0xf000, 255);
1623 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1624 font_name, tmA.tmLastChar, test_char);
1628 test_char = min(last_unicode_char, 255);
1629 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1630 font_name, tmA.tmLastChar, test_char);
1633 SetLastError(0xdeadbeef);
1634 ret = GetTextMetricsW(hdc, &tmW);
1635 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
1636 "GetTextMetricsW error %u\n", GetLastError());
1639 trace("W: first %x, last %x, default %x, break %x\n",
1640 tmW.tmFirstChar, tmW.tmLastChar, tmW.tmDefaultChar,
1643 if (lf->lfCharSet == SYMBOL_CHARSET)
1645 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1646 * sets symbol range to 0 - f0ff
1648 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
1649 font_name, tmW.tmFirstChar);
1650 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1651 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1652 font_name, tmW.tmLastChar);
1654 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1655 font_name, tmW.tmDefaultChar);
1656 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1657 font_name, tmW.tmBreakChar);
1661 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
1662 font_name, tmW.tmFirstChar, first_unicode_char);
1663 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
1664 font_name, tmW.tmLastChar, last_unicode_char);
1666 ret = GetDeviceCaps(hdc, LOGPIXELSX);
1667 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
1668 tmW.tmDigitizedAspectX, ret);
1669 ret = GetDeviceCaps(hdc, LOGPIXELSY);
1670 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
1671 tmW.tmDigitizedAspectX, ret);
1675 SelectObject(hdc, hfont_old);
1676 DeleteObject(hfont);
1681 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
1683 INT *enumed = (INT *)lParam;
1685 if (type == TRUETYPE_FONTTYPE)
1688 test_text_metrics(lf);
1693 static void test_GetTextMetrics(void)
1701 memset(&lf, 0, sizeof(lf));
1702 lf.lfCharSet = DEFAULT_CHARSET;
1704 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
1705 trace("Tested metrics of %d truetype fonts\n", enumed);
1710 static void test_nonexistent_font(void)
1715 char buf[LF_FACESIZE];
1717 if (!is_truetype_font_installed("Arial Black"))
1719 skip("Arial not installed\n");
1725 memset(&lf, 0, sizeof(lf));
1727 lf.lfWeight = FW_REGULAR;
1728 lf.lfCharSet = ANSI_CHARSET;
1729 lf.lfPitchAndFamily = FF_SWISS;
1730 strcpy(lf.lfFaceName, "Nonexistent font");
1732 hfont = CreateFontIndirectA(&lf);
1733 hfont = SelectObject(hdc, hfont);
1734 GetTextFaceA(hdc, sizeof(buf), buf);
1735 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
1736 DeleteObject(SelectObject(hdc, hfont));
1746 test_bitmap_font_metrics();
1747 test_GdiGetCharDimensions();
1748 test_GetCharABCWidths();
1749 test_text_extents();
1750 test_GetGlyphIndices();
1751 test_GetKerningPairs();
1752 test_GetOutlineTextMetrics();
1753 test_SetTextJustification();
1754 test_font_charset();
1755 test_GetFontUnicodeRanges();
1756 test_nonexistent_font();
1758 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1759 * I'd like to avoid them in this test.
1761 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
1762 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
1763 if (is_truetype_font_installed("Arial Black") &&
1764 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1766 test_EnumFontFamilies("", ANSI_CHARSET);
1767 test_EnumFontFamilies("", SYMBOL_CHARSET);
1768 test_EnumFontFamilies("", DEFAULT_CHARSET);
1771 skip("Arial Black or Symbol/Wingdings is not installed\n");
1772 test_GetTextMetrics();