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 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, CP932_BIT },
351 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT | CP1250_BIT },
352 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT },
353 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, CP932_BIT }
355 /* FIXME: add "Terminal" */
359 HFONT hfont, old_hfont;
363 hdc = CreateCompatibleDC(0);
366 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
370 memset(&lf, 0, sizeof(lf));
372 lf.lfHeight = fd[i].height;
373 strcpy(lf.lfFaceName, fd[i].face_name);
375 for(bit = 0; bit < 32; bit++)
382 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
383 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
385 lf.lfCharSet = csi.ciCharset;
386 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
389 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
391 hfont = create_font(lf.lfFaceName, &lf);
392 old_hfont = SelectObject(hdc, hfont);
393 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
395 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);
396 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);
397 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);
398 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);
399 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);
400 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);
401 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);
403 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
404 that make the max width bigger */
405 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
406 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);
408 SelectObject(hdc, old_hfont);
416 static void test_GdiGetCharDimensions(void)
422 LONG avgwidth, height;
423 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
425 if (!pGdiGetCharDimensions)
427 skip("GdiGetCharDimensions not available on this platform\n");
431 hdc = CreateCompatibleDC(NULL);
433 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
434 avgwidth = ((size.cx / 26) + 1) / 2;
436 ret = pGdiGetCharDimensions(hdc, &tm, &height);
437 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
438 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
440 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
441 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
443 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
444 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
447 ret = pGdiGetCharDimensions(hdc, NULL, &height);
448 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
449 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
454 static void test_GetCharABCWidths(void)
456 static const WCHAR str[] = {'a',0};
465 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
467 skip("GetCharABCWidthsW/I not available on this platform\n");
471 memset(&lf, 0, sizeof(lf));
472 strcpy(lf.lfFaceName, "System");
475 hfont = CreateFontIndirectA(&lf);
477 hfont = SelectObject(hdc, hfont);
479 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
480 ok(nb == 1, "pGetGlyphIndicesW should have returned 1\n");
482 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
483 ok(!ret, "GetCharABCWidthsI should have failed\n");
485 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
486 ok(!ret, "GetCharABCWidthsI should have failed\n");
488 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
489 ok(ret, "GetCharABCWidthsI should have succeeded\n");
491 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
492 ok(!ret, "GetCharABCWidthsW should have failed\n");
494 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
495 ok(!ret, "GetCharABCWidthsW should have failed\n");
497 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
498 ok(!ret, "GetCharABCWidthsW should have failed\n");
500 hfont = SelectObject(hdc, hfont);
502 ReleaseDC(NULL, hdc);
505 static void test_text_extents(void)
507 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
509 INT i, len, fit1, fit2;
517 memset(&lf, 0, sizeof(lf));
518 strcpy(lf.lfFaceName, "Arial");
521 hfont = CreateFontIndirectA(&lf);
523 hfont = SelectObject(hdc, hfont);
524 GetTextMetricsA(hdc, &tm);
525 GetTextExtentPointA(hdc, "o", 1, &sz);
526 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
528 SetLastError(0xdeadbeef);
529 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
530 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
532 skip("Skipping remainder of text extents test on a Win9x platform\n");
533 hfont = SelectObject(hdc, hfont);
540 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
541 extents[0] = 1; /* So that the increasing sequence test will fail
542 if the extents array is untouched. */
543 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
544 GetTextExtentPointW(hdc, wt, len, &sz2);
546 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
547 /* Because of the '\n' in the string GetTextExtentExPoint and
548 GetTextExtentPoint return different widths under Win2k, but
549 under WinXP they return the same width. So we don't test that
552 for (i = 1; i < len; ++i)
553 ok(extents[i-1] <= extents[i],
554 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
556 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
557 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
558 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
559 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
560 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
561 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
562 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
563 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
564 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
565 ok(extents[0] == extents[2] && extents[1] == extents[3],
566 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
567 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
568 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
569 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
570 HeapFree(GetProcessHeap(), 0, extents);
572 hfont = SelectObject(hdc, hfont);
574 ReleaseDC(NULL, hdc);
577 static void test_GetGlyphIndices(void)
584 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
585 WORD glyphs[(sizeof(testtext)/2)-1];
588 if (!pGetGlyphIndicesW) {
589 skip("GetGlyphIndices not available on platform\n");
593 if(!is_font_installed("Symbol"))
595 skip("Symbol is not installed so skipping this test\n");
599 memset(&lf, 0, sizeof(lf));
600 strcpy(lf.lfFaceName, "Symbol");
603 hfont = CreateFontIndirectA(&lf);
606 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
607 flags |= GGI_MARK_NONEXISTING_GLYPHS;
608 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
609 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
610 ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
612 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
613 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
614 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
615 textm.tmDefaultChar, glyphs[4]);
618 static void test_GetKerningPairs(void)
620 static const struct kerning_data
622 const char face_name[LF_FACESIZE];
624 /* some interesting fields from OUTLINETEXTMETRIC */
625 LONG tmHeight, tmAscent, tmDescent;
630 UINT otmsCapEmHeight;
635 UINT otmusMinimumPPEM;
636 /* small subset of kerning pairs to test */
637 DWORD total_kern_pairs;
638 const KERNINGPAIR kern_pair[26];
641 {"Arial", 12, 12, 9, 3,
642 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
645 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
646 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
647 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
648 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
649 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
650 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
651 {933,970,+1},{933,972,-1}
654 {"Arial", -34, 39, 32, 7,
655 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
658 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
659 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
660 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
661 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
662 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
663 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
664 {933,970,+2},{933,972,-3}
667 { "Arial", 120, 120, 97, 23,
668 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
671 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
672 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
673 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
674 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
675 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
676 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
677 {933,970,+6},{933,972,-10}
680 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
681 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
682 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
685 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
686 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
687 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
688 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
689 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
690 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
691 {933,970,+54},{933,972,-83}
697 HFONT hfont, hfont_old;
698 KERNINGPAIR *kern_pair;
700 DWORD total_kern_pairs, ret, i, n, matches;
704 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
705 * which may render this test unusable, so we're trying to avoid that.
707 SetLastError(0xdeadbeef);
708 GetKerningPairsW(hdc, 0, NULL);
709 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
711 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
716 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
718 OUTLINETEXTMETRICW otm;
720 if (!is_font_installed(kd[i].face_name))
722 trace("%s is not installed so skipping this test\n", kd[i].face_name);
726 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
728 memset(&lf, 0, sizeof(lf));
729 strcpy(lf.lfFaceName, kd[i].face_name);
730 lf.lfHeight = kd[i].height;
731 hfont = CreateFontIndirect(&lf);
734 hfont_old = SelectObject(hdc, hfont);
736 SetLastError(0xdeadbeef);
737 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
738 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
740 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
741 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
742 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
743 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
744 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
745 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
747 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
748 kd[i].otmEMSquare, otm.otmEMSquare);
749 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
750 kd[i].otmAscent, otm.otmAscent);
751 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
752 kd[i].otmDescent, otm.otmDescent);
753 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
754 kd[i].otmLineGap, otm.otmLineGap);
756 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
757 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
758 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
759 kd[i].otmsXHeight, otm.otmsXHeight);
760 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
761 kd[i].otmMacAscent, otm.otmMacAscent);
762 ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
763 kd[i].otmMacDescent, otm.otmMacDescent);
764 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
765 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
766 kd[i].otmMacLineGap, otm.otmMacLineGap);
767 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
768 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
771 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
772 trace("total_kern_pairs %u\n", total_kern_pairs);
773 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
775 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
776 SetLastError(0xdeadbeef);
777 ret = GetKerningPairsW(hdc, 0, kern_pair);
778 ok(GetLastError() == ERROR_INVALID_PARAMETER,
779 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
780 ok(ret == 0, "got %lu, expected 0\n", ret);
783 ret = GetKerningPairsW(hdc, 100, NULL);
784 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
786 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
787 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
789 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
790 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
794 for (n = 0; n < ret; n++)
798 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
799 trace("{'%c','%c',%d},\n",
800 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
802 for (j = 0; j < kd[i].total_kern_pairs; j++)
804 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
805 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
807 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
808 "pair %d:%d got %d, expected %d\n",
809 kern_pair[n].wFirst, kern_pair[n].wSecond,
810 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
816 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
817 matches, kd[i].total_kern_pairs);
819 HeapFree(GetProcessHeap(), 0, kern_pair);
821 SelectObject(hdc, hfont_old);
828 static void test_GetOutlineTextMetrics(void)
830 OUTLINETEXTMETRIC *otm;
832 HFONT hfont, hfont_old;
836 if (!is_font_installed("Arial"))
838 skip("Arial is not installed\n");
844 memset(&lf, 0, sizeof(lf));
845 strcpy(lf.lfFaceName, "Arial");
847 lf.lfWeight = FW_NORMAL;
848 lf.lfPitchAndFamily = DEFAULT_PITCH;
849 lf.lfQuality = PROOF_QUALITY;
850 hfont = CreateFontIndirect(&lf);
853 hfont_old = SelectObject(hdc, hfont);
854 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
855 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
857 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
859 memset(otm, 0xAA, otm_size);
860 SetLastError(0xdeadbeef);
861 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
862 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
863 ok(ret == 1 /* Win9x */ ||
864 ret == otm->otmSize /* XP*/,
865 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
866 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
868 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
869 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
870 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
871 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
874 memset(otm, 0xAA, otm_size);
875 SetLastError(0xdeadbeef);
876 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
877 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
878 ok(ret == 1 /* Win9x */ ||
879 ret == otm->otmSize /* XP*/,
880 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
881 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
883 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
884 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
885 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
886 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
889 /* ask about truncated data */
890 memset(otm, 0xAA, otm_size);
891 SetLastError(0xdeadbeef);
892 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
893 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
894 ok(ret == 1 /* Win9x */ ||
895 ret == otm->otmSize /* XP*/,
896 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
897 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
899 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
900 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
901 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
903 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
905 HeapFree(GetProcessHeap(), 0, otm);
907 SelectObject(hdc, hfont_old);
913 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
917 outputWidth = 0, /* to test TabbedTextOut() */
918 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
919 areaWidth = clientArea->right - clientArea->left,
921 BOOL lastExtent = FALSE;
922 PSTR pFirstChar, pLastChar;
928 int GetTextExtentExPointWWidth;
929 int TabbedTextOutWidth;
932 GetTextMetricsA(hdc, &tm);
936 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
942 /* if not at the end of the string, ... */
943 if (*str == '\0') break;
944 /* ... add the next word to the current extent */
945 while (*str != '\0' && *str++ != tm.tmBreakChar);
947 SetTextJustification(hdc, 0, 0);
948 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
949 } while ((int) size.cx < areaWidth);
951 /* ignore trailing break chars */
953 while (*(pLastChar - 1) == tm.tmBreakChar)
959 if (*str == '\0' || breakCount <= 0) pLastChar = str;
961 SetTextJustification(hdc, 0, 0);
962 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
964 /* do not justify the last extent */
965 if (*str != '\0' && breakCount > 0)
967 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
968 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
969 justifiedWidth = size.cx;
971 else lastExtent = TRUE;
973 x = clientArea->left;
975 outputWidth = LOWORD(TabbedTextOut(
976 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
978 /* catch errors and report them */
979 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
981 memset(error[nErrors].extent, 0, 100);
982 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
983 error[nErrors].TabbedTextOutWidth = outputWidth;
984 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
990 } while (*str && y < clientArea->bottom);
992 for (e = 0; e < nErrors; e++)
994 ok(error[e].TabbedTextOutWidth == areaWidth,
995 "The output text (\"%s\") width should be %d, not %d.\n",
996 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
997 /* The width returned by GetTextExtentPoint32() is exactly the same
998 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
999 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1000 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1001 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1005 static void test_SetTextJustification(void)
1012 static char testText[] =
1013 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1014 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1015 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1016 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1017 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1018 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1019 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1021 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1022 GetClientRect( hwnd, &clientArea );
1023 hdc = GetDC( hwnd );
1025 memset(&lf, 0, sizeof lf);
1026 lf.lfCharSet = ANSI_CHARSET;
1027 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1028 lf.lfWeight = FW_DONTCARE;
1030 lf.lfQuality = DEFAULT_QUALITY;
1031 lstrcpyA(lf.lfFaceName, "Times New Roman");
1032 hfont = create_font("Times New Roman", &lf);
1033 SelectObject(hdc, hfont);
1035 testJustification(hdc, testText, &clientArea);
1037 DeleteObject(hfont);
1038 ReleaseDC(hwnd, hdc);
1039 DestroyWindow(hwnd);
1042 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1046 HFONT hfont, hfont_old;
1053 assert(count <= 128);
1055 memset(&lf, 0, sizeof(lf));
1057 lf.lfCharSet = charset;
1059 lstrcpyA(lf.lfFaceName, "Arial");
1060 SetLastError(0xdeadbeef);
1061 hfont = CreateFontIndirectA(&lf);
1062 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1065 hfont_old = SelectObject(hdc, hfont);
1067 cs = GetTextCharsetInfo(hdc, &fs, 0);
1068 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1070 SetLastError(0xdeadbeef);
1071 ret = GetTextFace(hdc, sizeof(name), name);
1072 ok(ret, "GetTextFace error %u\n", GetLastError());
1074 if (charset == SYMBOL_CHARSET)
1076 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1077 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1081 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1082 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1085 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1087 trace("Can't find codepage for charset %d\n", cs);
1091 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1096 WCHAR unicode_buf[128];
1098 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1100 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1102 SetLastError(0xdeadbeef);
1103 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1104 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1110 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1112 SetLastError(0xdeadbeef);
1113 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1114 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1117 SelectObject(hdc, hfont_old);
1118 DeleteObject(hfont);
1125 static void test_font_charset(void)
1127 static struct charset_data
1131 WORD font_idxA[128], font_idxW[128];
1134 { ANSI_CHARSET, 1252 },
1135 { RUSSIAN_CHARSET, 1251 },
1136 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1140 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1142 skip("Skipping the font charset test on a Win9x platform\n");
1146 if (!is_font_installed("Arial"))
1148 skip("Arial is not installed\n");
1152 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1154 if (cd[i].charset == SYMBOL_CHARSET)
1156 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1158 skip("Symbol or Wingdings is not installed\n");
1162 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1163 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1164 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1167 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1170 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1171 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1174 skip("Symbol or Wingdings is not installed\n");
1177 static void test_GetFontUnicodeRanges(void)
1181 HFONT hfont, hfont_old;
1185 if (!pGetFontUnicodeRanges)
1187 skip("GetFontUnicodeRanges not available before W2K\n");
1191 memset(&lf, 0, sizeof(lf));
1192 lstrcpyA(lf.lfFaceName, "Arial");
1193 hfont = create_font("Arial", &lf);
1196 hfont_old = SelectObject(hdc, hfont);
1198 size = pGetFontUnicodeRanges(NULL, NULL);
1199 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1201 size = pGetFontUnicodeRanges(hdc, NULL);
1202 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1204 gs = HeapAlloc(GetProcessHeap(), 0, size);
1206 size = pGetFontUnicodeRanges(hdc, gs);
1207 ok(size, "GetFontUnicodeRanges failed\n");
1209 for (i = 0; i < gs->cRanges; i++)
1210 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1212 trace("found %u ranges\n", gs->cRanges);
1214 HeapFree(GetProcessHeap(), 0, gs);
1216 SelectObject(hdc, hfont_old);
1217 DeleteObject(hfont);
1218 ReleaseDC(NULL, hdc);
1221 #define MAX_ENUM_FONTS 256
1223 struct enum_font_data
1226 LOGFONT lf[MAX_ENUM_FONTS];
1229 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1231 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1233 if (type != TRUETYPE_FONTTYPE) return 1;
1235 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1236 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1238 if (efd->total < MAX_ENUM_FONTS)
1239 efd->lf[efd->total++] = *lf;
1244 static void get_charset_stats(struct enum_font_data *efd,
1245 int *ansi_charset, int *symbol_charset,
1246 int *russian_charset)
1251 *symbol_charset = 0;
1252 *russian_charset = 0;
1254 for (i = 0; i < efd->total; i++)
1256 switch (efd->lf[i].lfCharSet)
1261 case SYMBOL_CHARSET:
1262 (*symbol_charset)++;
1264 case RUSSIAN_CHARSET:
1265 (*russian_charset)++;
1271 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1273 struct enum_font_data efd;
1276 int i, ret, ansi_charset, symbol_charset, russian_charset;
1278 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1280 if (*font_name && !is_truetype_font_installed(font_name))
1282 skip("%s is not installed\n", font_name);
1288 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1289 * while EnumFontFamiliesEx doesn't.
1291 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1294 SetLastError(0xdeadbeef);
1295 ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1296 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1297 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1298 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1299 ansi_charset, symbol_charset, russian_charset);
1300 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1301 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1302 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1303 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1307 SetLastError(0xdeadbeef);
1308 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1309 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1310 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1311 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1312 ansi_charset, symbol_charset, russian_charset,
1313 *font_name ? font_name : "<empty>");
1315 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1317 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1318 for (i = 0; i < efd.total; i++)
1320 /* FIXME: remove completely once Wine is fixed */
1321 if (efd.lf[i].lfCharSet != font_charset)
1324 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1327 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1328 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1329 font_name, efd.lf[i].lfFaceName);
1332 memset(&lf, 0, sizeof(lf));
1333 lf.lfCharSet = ANSI_CHARSET;
1334 lstrcpy(lf.lfFaceName, font_name);
1336 SetLastError(0xdeadbeef);
1337 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1338 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1339 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1340 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1341 ansi_charset, symbol_charset, russian_charset,
1342 *font_name ? font_name : "<empty>");
1343 if (font_charset == SYMBOL_CHARSET)
1346 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1348 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1352 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1353 for (i = 0; i < efd.total; i++)
1355 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1357 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1358 font_name, efd.lf[i].lfFaceName);
1362 /* DEFAULT_CHARSET should enumerate all available charsets */
1363 memset(&lf, 0, sizeof(lf));
1364 lf.lfCharSet = DEFAULT_CHARSET;
1365 lstrcpy(lf.lfFaceName, font_name);
1367 SetLastError(0xdeadbeef);
1368 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1369 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1370 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1371 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1372 ansi_charset, symbol_charset, russian_charset,
1373 *font_name ? font_name : "<empty>");
1374 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1375 for (i = 0; i < efd.total; i++)
1378 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1379 font_name, efd.lf[i].lfFaceName);
1383 switch (font_charset)
1386 ok(ansi_charset > 0,
1387 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1389 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1390 ok(russian_charset > 0,
1391 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1393 case SYMBOL_CHARSET:
1395 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1397 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1398 ok(!russian_charset,
1399 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1401 case DEFAULT_CHARSET:
1402 ok(ansi_charset > 0,
1403 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1404 ok(symbol_charset > 0,
1405 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1406 ok(russian_charset > 0,
1407 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1413 ok(ansi_charset > 0,
1414 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1415 ok(symbol_charset > 0,
1416 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1417 ok(russian_charset > 0,
1418 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1421 memset(&lf, 0, sizeof(lf));
1422 lf.lfCharSet = SYMBOL_CHARSET;
1423 lstrcpy(lf.lfFaceName, font_name);
1425 SetLastError(0xdeadbeef);
1426 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1427 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1428 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1429 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1430 ansi_charset, symbol_charset, russian_charset,
1431 *font_name ? font_name : "<empty>");
1432 if (*font_name && font_charset == ANSI_CHARSET)
1433 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1436 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1437 for (i = 0; i < efd.total; i++)
1439 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1441 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1442 font_name, efd.lf[i].lfFaceName);
1446 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1447 ok(symbol_charset > 0,
1448 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1449 ok(!russian_charset,
1450 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1456 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1457 #include "pshpack2.h"
1461 SHORT xAvgCharWidth;
1462 USHORT usWeightClass;
1463 USHORT usWidthClass;
1465 SHORT ySubscriptXSize;
1466 SHORT ySubscriptYSize;
1467 SHORT ySubscriptXOffset;
1468 SHORT ySubscriptYOffset;
1469 SHORT ySuperscriptXSize;
1470 SHORT ySuperscriptYSize;
1471 SHORT ySuperscriptXOffset;
1472 SHORT ySuperscriptYOffset;
1473 SHORT yStrikeoutSize;
1474 SHORT yStrikeoutPosition;
1477 ULONG ulUnicodeRange1;
1478 ULONG ulUnicodeRange2;
1479 ULONG ulUnicodeRange3;
1480 ULONG ulUnicodeRange4;
1483 USHORT usFirstCharIndex;
1484 USHORT usLastCharIndex;
1485 /* According to the Apple spec, original version didn't have the below fields,
1486 * version numbers were taked from the OpenType spec.
1488 /* version 0 (TrueType 1.5) */
1489 USHORT sTypoAscender;
1490 USHORT sTypoDescender;
1491 USHORT sTypoLineGap;
1493 USHORT usWinDescent;
1494 /* version 1 (TrueType 1.66) */
1495 ULONG ulCodePageRange1;
1496 ULONG ulCodePageRange2;
1497 /* version 2 (OpenType 1.2) */
1500 USHORT usDefaultChar;
1502 USHORT usMaxContext;
1504 #include "poppack.h"
1506 #ifdef WORDS_BIGENDIAN
1507 #define GET_BE_WORD(x) (x)
1509 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1512 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1513 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1514 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1515 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1517 static void test_text_metrics(const LOGFONTA *lf)
1520 HFONT hfont, hfont_old;
1523 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1528 const char *font_name = lf->lfFaceName;
1530 trace("Testing font metrics for %s, charset %d\n", font_name, lf->lfCharSet);
1534 SetLastError(0xdeadbeef);
1535 hfont = CreateFontIndirectA(lf);
1536 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1538 hfont_old = SelectObject(hdc, hfont);
1540 if(lf->lfWidth > 0) {
1541 HFONT hfont2, hfont_prev;
1542 GLYPHMETRICS gm1, gm2;
1544 MAT2 mat2 = { {0,1}, {0,0}, {0,0}, {0,1} };
1546 /* negative widths are handled just as positive ones */
1549 SetLastError(0xdeadbeef);
1550 hfont2 = CreateFontIndirectA(&lf2);
1551 ok(hfont2 != 0, "CreateFontIndirect error %u\n", GetLastError());
1552 hfont_prev = SelectObject(hdc, hfont2);
1554 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1555 memset(&gm1, 0xab, sizeof(gm1));
1556 SetLastError(0xdeadbeef);
1557 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat2);
1558 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1560 SelectObject(hdc, hfont_prev);
1561 DeleteObject(hfont2);
1563 memset(&gm2, 0xbb, sizeof(gm2));
1564 SetLastError(0xdeadbeef);
1565 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat2);
1566 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1568 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1569 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1570 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1571 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1572 gm1.gmCellIncX == gm2.gmCellIncX &&
1573 gm1.gmCellIncY == gm2.gmCellIncY,
1574 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1575 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1576 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1577 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1578 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1581 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1582 if (size == GDI_ERROR)
1584 trace("OS/2 chunk was not found\n");
1587 if (size > sizeof(tt_os2))
1589 trace("got too large OS/2 chunk of size %u\n", size);
1590 size = sizeof(tt_os2);
1593 memset(&tt_os2, 0, sizeof(tt_os2));
1594 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1595 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1597 version = GET_BE_WORD(tt_os2.version);
1598 trace("OS/2 chunk version %u, vendor %4.4s\n", version, (LPCSTR)&tt_os2.achVendID);
1600 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
1601 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
1602 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
1603 break_char = GET_BE_WORD(tt_os2.usBreakChar);
1605 trace("for %s first %x, last %x, default %x, break %x\n", font_name,
1606 first_unicode_char, last_unicode_char, default_char, break_char);
1608 SetLastError(0xdeadbeef);
1609 ret = GetTextMetricsA(hdc, &tmA);
1610 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
1611 trace("A: first %x, last %x, default %x, break %x\n",
1612 tmA.tmFirstChar, tmA.tmLastChar, tmA.tmDefaultChar, tmA.tmBreakChar);
1614 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1615 test_char = min(first_unicode_char - 1, 255);
1616 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
1617 font_name, tmA.tmFirstChar, test_char);
1619 if (lf->lfCharSet == SYMBOL_CHARSET)
1621 test_char = min(last_unicode_char - 0xf000, 255);
1622 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1623 font_name, tmA.tmLastChar, test_char);
1627 test_char = min(last_unicode_char, 255);
1628 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1629 font_name, tmA.tmLastChar, test_char);
1632 SetLastError(0xdeadbeef);
1633 ret = GetTextMetricsW(hdc, &tmW);
1634 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
1635 "GetTextMetricsW error %u\n", GetLastError());
1638 trace("W: first %x, last %x, default %x, break %x\n",
1639 tmW.tmFirstChar, tmW.tmLastChar, tmW.tmDefaultChar,
1642 if (lf->lfCharSet == SYMBOL_CHARSET)
1644 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1645 * sets symbol range to 0 - f0ff
1647 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
1648 font_name, tmW.tmFirstChar);
1649 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1650 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1651 font_name, tmW.tmLastChar);
1653 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1654 font_name, tmW.tmDefaultChar);
1655 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1656 font_name, tmW.tmBreakChar);
1660 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
1661 font_name, tmW.tmFirstChar, first_unicode_char);
1662 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
1663 font_name, tmW.tmLastChar, last_unicode_char);
1665 ret = GetDeviceCaps(hdc, LOGPIXELSX);
1666 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
1667 tmW.tmDigitizedAspectX, ret);
1668 ret = GetDeviceCaps(hdc, LOGPIXELSY);
1669 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
1670 tmW.tmDigitizedAspectX, ret);
1674 SelectObject(hdc, hfont_old);
1675 DeleteObject(hfont);
1680 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
1682 INT *enumed = (INT *)lParam;
1684 if (type == TRUETYPE_FONTTYPE)
1687 test_text_metrics(lf);
1692 static void test_GetTextMetrics(void)
1700 memset(&lf, 0, sizeof(lf));
1701 lf.lfCharSet = DEFAULT_CHARSET;
1703 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
1704 trace("Tested metrics of %d truetype fonts\n", enumed);
1709 static void test_nonexistent_font(void)
1714 char buf[LF_FACESIZE];
1716 if (!is_truetype_font_installed("Arial Black"))
1718 skip("Arial not installed\n");
1724 memset(&lf, 0, sizeof(lf));
1726 lf.lfWeight = FW_REGULAR;
1727 lf.lfCharSet = ANSI_CHARSET;
1728 lf.lfPitchAndFamily = FF_SWISS;
1729 strcpy(lf.lfFaceName, "Nonexistent font");
1731 hfont = CreateFontIndirectA(&lf);
1732 hfont = SelectObject(hdc, hfont);
1733 GetTextFaceA(hdc, sizeof(buf), buf);
1734 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
1735 DeleteObject(SelectObject(hdc, hfont));
1745 test_bitmap_font_metrics();
1746 test_GdiGetCharDimensions();
1747 test_GetCharABCWidths();
1748 test_text_extents();
1749 test_GetGlyphIndices();
1750 test_GetKerningPairs();
1751 test_GetOutlineTextMetrics();
1752 test_SetTextJustification();
1753 test_font_charset();
1754 test_GetFontUnicodeRanges();
1755 test_nonexistent_font();
1757 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1758 * I'd like to avoid them in this test.
1760 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
1761 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
1762 if (is_truetype_font_installed("Arial Black") &&
1763 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1765 test_EnumFontFamilies("", ANSI_CHARSET);
1766 test_EnumFontFamilies("", SYMBOL_CHARSET);
1767 test_EnumFontFamilies("", DEFAULT_CHARSET);
1770 skip("Arial Black or Symbol/Wingdings is not installed\n");
1771 test_GetTextMetrics();