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);
41 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
43 static HMODULE hgdi32 = 0;
45 static void init(void)
47 hgdi32 = GetModuleHandleA("gdi32.dll");
49 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
50 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
51 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
52 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
53 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
54 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
55 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
58 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
60 if (type != TRUETYPE_FONTTYPE) return 1;
65 static BOOL is_truetype_font_installed(const char *name)
70 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
77 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
82 static BOOL is_font_installed(const char *name)
87 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
94 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
102 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
103 /* NT4 tries to be clever and only returns the minimum length */
104 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
106 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
107 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
108 ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
109 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
110 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
113 static HFONT create_font(const char* test, const LOGFONTA* lf)
115 HFONT hfont = CreateFontIndirectA(lf);
116 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
118 check_font(test, lf, hfont);
122 static void test_logfont(void)
127 memset(&lf, 0, sizeof lf);
129 lf.lfCharSet = ANSI_CHARSET;
130 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
131 lf.lfWeight = FW_DONTCARE;
134 lf.lfQuality = DEFAULT_QUALITY;
136 lstrcpyA(lf.lfFaceName, "Arial");
137 hfont = create_font("Arial", &lf);
140 memset(&lf, 'A', sizeof(lf));
141 hfont = CreateFontIndirectA(&lf);
142 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
144 lf.lfFaceName[LF_FACESIZE - 1] = 0;
145 check_font("AAA...", &lf, hfont);
149 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
151 if (type & RASTER_FONTTYPE)
153 LOGFONT *lf = (LOGFONT *)lParam;
155 return 0; /* stop enumeration */
158 return 1; /* continue enumeration */
161 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight, const char *test_str,
162 INT test_str_len, const TEXTMETRICA *tm_orig,
163 const SIZE *size_orig, INT width_of_A_orig,
164 INT scale_x, INT scale_y)
170 INT width_of_A, cx, cy;
175 GetObjectA(hfont, sizeof(lf), &lf);
177 old_hfont = SelectObject(hdc, hfont);
179 GetTextMetricsA(hdc, &tm);
181 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
182 cy = tm.tmHeight / tm_orig->tmHeight;
183 ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
184 scale_x, scale_y, cx, cy);
185 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
186 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
187 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
188 ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
189 ok(tm.tmMaxCharWidth == tm_orig->tmMaxCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmMaxCharWidth * scale_x);
191 ok(lf.lfHeight == lfHeight, "lf %d != %d\n", lf.lfHeight, lfHeight);
193 ok(lf.lfWidth == tm.tmAveCharWidth, "lf %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
195 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
197 ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x);
198 ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y);
200 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
202 ok(width_of_A == width_of_A_orig * scale_x, "%d != %d\n", width_of_A, width_of_A_orig * scale_x);
204 SelectObject(hdc, old_hfont);
207 /* Test how GDI scales bitmap font metrics */
208 static void test_bitmap_font(void)
210 static const char test_str[11] = "Test String";
213 HFONT hfont, old_hfont;
216 INT ret, i, width_orig, height_orig, scale;
220 /* "System" has only 1 pixel size defined, otherwise the test breaks */
221 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
225 trace("no bitmap fonts were found, skipping the test\n");
229 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
231 height_orig = bitmap_lf.lfHeight;
232 hfont = create_font("bitmap", &bitmap_lf);
234 old_hfont = SelectObject(hdc, hfont);
235 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
236 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
237 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
238 SelectObject(hdc, old_hfont);
241 /* test fractional scaling */
242 for (i = 1; i <= height_orig * 3; i++)
246 bitmap_lf.lfHeight = i;
247 hfont = create_font("fractional", &bitmap_lf);
248 scale = (i + height_orig - 1) / height_orig;
249 nearest_height = scale * height_orig;
250 /* XP allows not more than 10% deviation */
251 if (scale > 1 && nearest_height - i > nearest_height / 10) scale--;
252 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
256 /* test integer scaling 3x2 */
257 bitmap_lf.lfHeight = height_orig * 2;
258 bitmap_lf.lfWidth *= 3;
259 hfont = create_font("3x2", &bitmap_lf);
260 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
263 /* test integer scaling 3x3 */
264 bitmap_lf.lfHeight = height_orig * 3;
265 bitmap_lf.lfWidth = 0;
266 hfont = create_font("3x3", &bitmap_lf);
267 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
273 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
275 LOGFONT *lf = (LOGFONT *)lParam;
277 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
280 return 0; /* stop enumeration */
282 return 1; /* continue enumeration */
285 static void test_bitmap_font_metrics(void)
287 static const struct font_data
289 const char face_name[LF_FACESIZE];
290 int weight, height, ascent, descent, int_leading, ext_leading;
291 int ave_char_width, max_char_width;
295 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
296 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
297 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
298 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
299 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
300 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
301 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
302 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
303 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
304 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
305 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
306 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
307 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
308 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
309 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
310 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
311 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
312 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
313 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
314 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
315 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
316 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
317 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
318 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
319 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
320 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
321 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
322 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
323 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
324 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
325 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
326 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
327 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
329 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
330 * require a new system.sfd for that font
332 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
333 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
334 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
335 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
336 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
337 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
338 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
339 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
340 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
341 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
342 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
343 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
344 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
345 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
346 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
347 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
348 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
349 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
350 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
351 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
352 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
354 /* FIXME: add "Terminal" */
358 HFONT hfont, old_hfont;
362 hdc = CreateCompatibleDC(0);
365 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
369 memset(&lf, 0, sizeof(lf));
371 lf.lfHeight = fd[i].height;
372 strcpy(lf.lfFaceName, fd[i].face_name);
374 for(bit = 0; bit < 32; bit++)
381 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
382 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
384 lf.lfCharSet = csi.ciCharset;
385 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
388 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
390 hfont = create_font(lf.lfFaceName, &lf);
391 old_hfont = SelectObject(hdc, hfont);
392 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
394 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);
395 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);
396 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);
397 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);
398 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);
399 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);
400 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);
402 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
403 that make the max width bigger */
404 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
405 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);
407 SelectObject(hdc, old_hfont);
415 static void test_GdiGetCharDimensions(void)
421 LONG avgwidth, height;
422 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
424 if (!pGdiGetCharDimensions)
426 skip("GdiGetCharDimensions not available on this platform\n");
430 hdc = CreateCompatibleDC(NULL);
432 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
433 avgwidth = ((size.cx / 26) + 1) / 2;
435 ret = pGdiGetCharDimensions(hdc, &tm, &height);
436 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
437 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
439 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
440 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
442 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
443 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
446 ret = pGdiGetCharDimensions(hdc, NULL, &height);
447 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
448 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
453 static void test_GetCharABCWidths(void)
455 static const WCHAR str[] = {'a',0};
464 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
466 skip("GetCharABCWidthsW/I not available on this platform\n");
470 memset(&lf, 0, sizeof(lf));
471 strcpy(lf.lfFaceName, "System");
474 hfont = CreateFontIndirectA(&lf);
476 hfont = SelectObject(hdc, hfont);
478 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
479 ok(nb == 1, "pGetGlyphIndicesW should have returned 1\n");
481 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
482 ok(!ret, "GetCharABCWidthsI should have failed\n");
484 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
485 ok(!ret, "GetCharABCWidthsI should have failed\n");
487 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
488 ok(ret, "GetCharABCWidthsI should have succeeded\n");
490 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
491 ok(!ret, "GetCharABCWidthsW should have failed\n");
493 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
494 ok(!ret, "GetCharABCWidthsW should have failed\n");
496 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
497 ok(!ret, "GetCharABCWidthsW should have failed\n");
499 hfont = SelectObject(hdc, hfont);
501 ReleaseDC(NULL, hdc);
504 static void test_text_extents(void)
506 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
508 INT i, len, fit1, fit2;
516 memset(&lf, 0, sizeof(lf));
517 strcpy(lf.lfFaceName, "Arial");
520 hfont = CreateFontIndirectA(&lf);
522 hfont = SelectObject(hdc, hfont);
523 GetTextMetricsA(hdc, &tm);
524 GetTextExtentPointA(hdc, "o", 1, &sz);
525 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
527 SetLastError(0xdeadbeef);
528 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
529 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
531 skip("Skipping remainder of text extents test on a Win9x platform\n");
532 hfont = SelectObject(hdc, hfont);
539 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
540 extents[0] = 1; /* So that the increasing sequence test will fail
541 if the extents array is untouched. */
542 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
543 GetTextExtentPointW(hdc, wt, len, &sz2);
545 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
546 /* Because of the '\n' in the string GetTextExtentExPoint and
547 GetTextExtentPoint return different widths under Win2k, but
548 under WinXP they return the same width. So we don't test that
551 for (i = 1; i < len; ++i)
552 ok(extents[i-1] <= extents[i],
553 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
555 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
556 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
557 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
558 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
559 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
560 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
561 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
562 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
563 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
564 ok(extents[0] == extents[2] && extents[1] == extents[3],
565 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
566 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
567 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
568 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
569 HeapFree(GetProcessHeap(), 0, extents);
571 hfont = SelectObject(hdc, hfont);
573 ReleaseDC(NULL, hdc);
576 static void test_GetGlyphIndices(void)
583 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
584 WORD glyphs[(sizeof(testtext)/2)-1];
587 if (!pGetGlyphIndicesW) {
588 skip("GetGlyphIndices not available on platform\n");
592 if(!is_font_installed("Symbol"))
594 skip("Symbol is not installed so skipping this test\n");
598 memset(&lf, 0, sizeof(lf));
599 strcpy(lf.lfFaceName, "Symbol");
602 hfont = CreateFontIndirectA(&lf);
605 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
606 flags |= GGI_MARK_NONEXISTING_GLYPHS;
607 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
608 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
609 ok((glyphs[4] == 0x001f || glyphs[4] == UNICODE_NOCHAR /* Vista */), "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
611 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
612 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
613 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
614 textm.tmDefaultChar, glyphs[4]);
617 static void test_GetKerningPairs(void)
619 static const struct kerning_data
621 const char face_name[LF_FACESIZE];
623 /* some interesting fields from OUTLINETEXTMETRIC */
624 LONG tmHeight, tmAscent, tmDescent;
629 UINT otmsCapEmHeight;
634 UINT otmusMinimumPPEM;
635 /* small subset of kerning pairs to test */
636 DWORD total_kern_pairs;
637 const KERNINGPAIR kern_pair[26];
640 {"Arial", 12, 12, 9, 3,
641 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
644 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
645 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
646 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
647 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
648 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
649 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
650 {933,970,+1},{933,972,-1}
653 {"Arial", -34, 39, 32, 7,
654 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
657 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
658 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
659 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
660 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
661 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
662 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
663 {933,970,+2},{933,972,-3}
666 { "Arial", 120, 120, 97, 23,
667 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
670 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
671 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
672 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
673 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
674 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
675 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
676 {933,970,+6},{933,972,-10}
679 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
680 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
681 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
684 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
685 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
686 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
687 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
688 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
689 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
690 {933,970,+54},{933,972,-83}
696 HFONT hfont, hfont_old;
697 KERNINGPAIR *kern_pair;
699 DWORD total_kern_pairs, ret, i, n, matches;
703 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
704 * which may render this test unusable, so we're trying to avoid that.
706 SetLastError(0xdeadbeef);
707 GetKerningPairsW(hdc, 0, NULL);
708 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
710 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
715 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
717 OUTLINETEXTMETRICW otm;
719 if (!is_font_installed(kd[i].face_name))
721 trace("%s is not installed so skipping this test\n", kd[i].face_name);
725 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
727 memset(&lf, 0, sizeof(lf));
728 strcpy(lf.lfFaceName, kd[i].face_name);
729 lf.lfHeight = kd[i].height;
730 hfont = CreateFontIndirect(&lf);
733 hfont_old = SelectObject(hdc, hfont);
735 SetLastError(0xdeadbeef);
736 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
737 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
739 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
740 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
741 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
742 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
743 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
744 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
746 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
747 kd[i].otmEMSquare, otm.otmEMSquare);
748 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
749 kd[i].otmAscent, otm.otmAscent);
750 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
751 kd[i].otmDescent, otm.otmDescent);
752 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
753 kd[i].otmLineGap, otm.otmLineGap);
755 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
756 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
757 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
758 kd[i].otmsXHeight, otm.otmsXHeight);
759 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
760 kd[i].otmMacAscent, otm.otmMacAscent);
761 ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
762 kd[i].otmMacDescent, otm.otmMacDescent);
763 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
764 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
765 kd[i].otmMacLineGap, otm.otmMacLineGap);
766 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
767 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
770 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
771 trace("total_kern_pairs %u\n", total_kern_pairs);
772 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
774 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
775 SetLastError(0xdeadbeef);
776 ret = GetKerningPairsW(hdc, 0, kern_pair);
777 ok(GetLastError() == ERROR_INVALID_PARAMETER,
778 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
779 ok(ret == 0, "got %lu, expected 0\n", ret);
782 ret = GetKerningPairsW(hdc, 100, NULL);
783 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
785 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
786 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
788 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
789 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
793 for (n = 0; n < ret; n++)
797 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
798 trace("{'%c','%c',%d},\n",
799 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
801 for (j = 0; j < kd[i].total_kern_pairs; j++)
803 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
804 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
806 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
807 "pair %d:%d got %d, expected %d\n",
808 kern_pair[n].wFirst, kern_pair[n].wSecond,
809 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
815 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
816 matches, kd[i].total_kern_pairs);
818 HeapFree(GetProcessHeap(), 0, kern_pair);
820 SelectObject(hdc, hfont_old);
827 static void test_GetOutlineTextMetrics(void)
829 OUTLINETEXTMETRIC *otm;
831 HFONT hfont, hfont_old;
835 if (!is_font_installed("Arial"))
837 skip("Arial is not installed\n");
843 memset(&lf, 0, sizeof(lf));
844 strcpy(lf.lfFaceName, "Arial");
846 lf.lfWeight = FW_NORMAL;
847 lf.lfPitchAndFamily = DEFAULT_PITCH;
848 lf.lfQuality = PROOF_QUALITY;
849 hfont = CreateFontIndirect(&lf);
852 hfont_old = SelectObject(hdc, hfont);
853 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
854 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
856 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
858 memset(otm, 0xAA, otm_size);
859 SetLastError(0xdeadbeef);
860 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
861 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
862 ok(ret == 1 /* Win9x */ ||
863 ret == otm->otmSize /* XP*/,
864 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
865 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
867 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
868 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
869 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
870 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
873 memset(otm, 0xAA, otm_size);
874 SetLastError(0xdeadbeef);
875 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
876 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
877 ok(ret == 1 /* Win9x */ ||
878 ret == otm->otmSize /* XP*/,
879 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
880 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
882 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
883 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
884 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
885 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
888 /* ask about truncated data */
889 memset(otm, 0xAA, otm_size);
890 SetLastError(0xdeadbeef);
891 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
892 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
893 ok(ret == 1 /* Win9x */ ||
894 ret == otm->otmSize /* XP*/,
895 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
896 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
898 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
899 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
900 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
902 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
904 HeapFree(GetProcessHeap(), 0, otm);
906 SelectObject(hdc, hfont_old);
912 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
916 outputWidth = 0, /* to test TabbedTextOut() */
917 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
918 areaWidth = clientArea->right - clientArea->left,
920 BOOL lastExtent = FALSE;
921 PSTR pFirstChar, pLastChar;
927 int GetTextExtentExPointWWidth;
928 int TabbedTextOutWidth;
931 GetTextMetricsA(hdc, &tm);
935 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
941 /* if not at the end of the string, ... */
942 if (*str == '\0') break;
943 /* ... add the next word to the current extent */
944 while (*str != '\0' && *str++ != tm.tmBreakChar);
946 SetTextJustification(hdc, 0, 0);
947 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
948 } while ((int) size.cx < areaWidth);
950 /* ignore trailing break chars */
952 while (*(pLastChar - 1) == tm.tmBreakChar)
958 if (*str == '\0' || breakCount <= 0) pLastChar = str;
960 SetTextJustification(hdc, 0, 0);
961 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
963 /* do not justify the last extent */
964 if (*str != '\0' && breakCount > 0)
966 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
967 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
968 justifiedWidth = size.cx;
970 else lastExtent = TRUE;
972 x = clientArea->left;
974 outputWidth = LOWORD(TabbedTextOut(
975 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
977 /* catch errors and report them */
978 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
980 memset(error[nErrors].extent, 0, 100);
981 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
982 error[nErrors].TabbedTextOutWidth = outputWidth;
983 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
989 } while (*str && y < clientArea->bottom);
991 for (e = 0; e < nErrors; e++)
993 ok(error[e].TabbedTextOutWidth == areaWidth,
994 "The output text (\"%s\") width should be %d, not %d.\n",
995 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
996 /* The width returned by GetTextExtentPoint32() is exactly the same
997 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
998 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
999 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1000 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1004 static void test_SetTextJustification(void)
1011 static char testText[] =
1012 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1013 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1014 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1015 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1016 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1017 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1018 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1020 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1021 GetClientRect( hwnd, &clientArea );
1022 hdc = GetDC( hwnd );
1024 memset(&lf, 0, sizeof lf);
1025 lf.lfCharSet = ANSI_CHARSET;
1026 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1027 lf.lfWeight = FW_DONTCARE;
1029 lf.lfQuality = DEFAULT_QUALITY;
1030 lstrcpyA(lf.lfFaceName, "Times New Roman");
1031 hfont = create_font("Times New Roman", &lf);
1032 SelectObject(hdc, hfont);
1034 testJustification(hdc, testText, &clientArea);
1036 DeleteObject(hfont);
1037 ReleaseDC(hwnd, hdc);
1038 DestroyWindow(hwnd);
1041 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1045 HFONT hfont, hfont_old;
1052 assert(count <= 128);
1054 memset(&lf, 0, sizeof(lf));
1056 lf.lfCharSet = charset;
1058 lstrcpyA(lf.lfFaceName, "Arial");
1059 SetLastError(0xdeadbeef);
1060 hfont = CreateFontIndirectA(&lf);
1061 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1064 hfont_old = SelectObject(hdc, hfont);
1066 cs = GetTextCharsetInfo(hdc, &fs, 0);
1067 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1069 SetLastError(0xdeadbeef);
1070 ret = GetTextFace(hdc, sizeof(name), name);
1071 ok(ret, "GetTextFace error %u\n", GetLastError());
1073 if (charset == SYMBOL_CHARSET)
1075 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1076 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1080 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1081 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1084 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1086 trace("Can't find codepage for charset %d\n", cs);
1090 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1095 WCHAR unicode_buf[128];
1097 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1099 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1101 SetLastError(0xdeadbeef);
1102 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1103 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1109 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1111 SetLastError(0xdeadbeef);
1112 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1113 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1116 SelectObject(hdc, hfont_old);
1117 DeleteObject(hfont);
1124 static void test_font_charset(void)
1126 static struct charset_data
1130 WORD font_idxA[128], font_idxW[128];
1133 { ANSI_CHARSET, 1252 },
1134 { RUSSIAN_CHARSET, 1251 },
1135 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1139 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1141 skip("Skipping the font charset test on a Win9x platform\n");
1145 if (!is_font_installed("Arial"))
1147 skip("Arial is not installed\n");
1151 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1153 if (cd[i].charset == SYMBOL_CHARSET)
1155 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1157 skip("Symbol or Wingdings is not installed\n");
1161 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1162 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1163 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1166 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1169 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1170 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1173 skip("Symbol or Wingdings is not installed\n");
1176 static void test_GetFontUnicodeRanges(void)
1180 HFONT hfont, hfont_old;
1184 if (!pGetFontUnicodeRanges)
1186 skip("GetFontUnicodeRanges not available before W2K\n");
1190 memset(&lf, 0, sizeof(lf));
1191 lstrcpyA(lf.lfFaceName, "Arial");
1192 hfont = create_font("Arial", &lf);
1195 hfont_old = SelectObject(hdc, hfont);
1197 size = pGetFontUnicodeRanges(NULL, NULL);
1198 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1200 size = pGetFontUnicodeRanges(hdc, NULL);
1201 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1203 gs = HeapAlloc(GetProcessHeap(), 0, size);
1205 size = pGetFontUnicodeRanges(hdc, gs);
1206 ok(size, "GetFontUnicodeRanges failed\n");
1208 for (i = 0; i < gs->cRanges; i++)
1209 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1211 trace("found %u ranges\n", gs->cRanges);
1213 HeapFree(GetProcessHeap(), 0, gs);
1215 SelectObject(hdc, hfont_old);
1216 DeleteObject(hfont);
1217 ReleaseDC(NULL, hdc);
1220 #define MAX_ENUM_FONTS 256
1222 struct enum_font_data
1225 LOGFONT lf[MAX_ENUM_FONTS];
1228 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1230 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1232 if (type != TRUETYPE_FONTTYPE) return 1;
1234 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1235 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1237 if (efd->total < MAX_ENUM_FONTS)
1238 efd->lf[efd->total++] = *lf;
1243 static void get_charset_stats(struct enum_font_data *efd,
1244 int *ansi_charset, int *symbol_charset,
1245 int *russian_charset)
1250 *symbol_charset = 0;
1251 *russian_charset = 0;
1253 for (i = 0; i < efd->total; i++)
1255 switch (efd->lf[i].lfCharSet)
1260 case SYMBOL_CHARSET:
1261 (*symbol_charset)++;
1263 case RUSSIAN_CHARSET:
1264 (*russian_charset)++;
1270 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1272 struct enum_font_data efd;
1275 int i, ret, ansi_charset, symbol_charset, russian_charset;
1277 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1279 if (*font_name && !is_truetype_font_installed(font_name))
1281 skip("%s is not installed\n", font_name);
1287 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1288 * while EnumFontFamiliesEx doesn't.
1290 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1293 SetLastError(0xdeadbeef);
1294 ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1295 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1296 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1297 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1298 ansi_charset, symbol_charset, russian_charset);
1299 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1300 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1301 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1302 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1305 SetLastError(0xdeadbeef);
1306 ret = EnumFontFamiliesEx(hdc, NULL, arial_enum_proc, (LPARAM)&efd, 0);
1307 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1308 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1309 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1310 ansi_charset, symbol_charset, russian_charset);
1311 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1312 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1313 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1314 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1318 SetLastError(0xdeadbeef);
1319 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1320 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1321 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1322 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1323 ansi_charset, symbol_charset, russian_charset,
1324 *font_name ? font_name : "<empty>");
1326 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1328 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1329 for (i = 0; i < efd.total; i++)
1331 /* FIXME: remove completely once Wine is fixed */
1332 if (efd.lf[i].lfCharSet != font_charset)
1335 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1338 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1339 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1340 font_name, efd.lf[i].lfFaceName);
1343 memset(&lf, 0, sizeof(lf));
1344 lf.lfCharSet = ANSI_CHARSET;
1345 lstrcpy(lf.lfFaceName, font_name);
1347 SetLastError(0xdeadbeef);
1348 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1349 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1350 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1351 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1352 ansi_charset, symbol_charset, russian_charset,
1353 *font_name ? font_name : "<empty>");
1354 if (font_charset == SYMBOL_CHARSET)
1357 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1359 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1363 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1364 for (i = 0; i < efd.total; i++)
1366 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1368 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1369 font_name, efd.lf[i].lfFaceName);
1373 /* DEFAULT_CHARSET should enumerate all available charsets */
1374 memset(&lf, 0, sizeof(lf));
1375 lf.lfCharSet = DEFAULT_CHARSET;
1376 lstrcpy(lf.lfFaceName, font_name);
1378 SetLastError(0xdeadbeef);
1379 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1380 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1381 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1382 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1383 ansi_charset, symbol_charset, russian_charset,
1384 *font_name ? font_name : "<empty>");
1385 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1386 for (i = 0; i < efd.total; i++)
1389 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1390 font_name, efd.lf[i].lfFaceName);
1394 switch (font_charset)
1397 ok(ansi_charset > 0,
1398 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1400 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1401 ok(russian_charset > 0,
1402 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1404 case SYMBOL_CHARSET:
1406 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1408 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1409 ok(!russian_charset,
1410 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1412 case DEFAULT_CHARSET:
1413 ok(ansi_charset > 0,
1414 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1415 ok(symbol_charset > 0,
1416 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1417 ok(russian_charset > 0,
1418 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1424 ok(ansi_charset > 0,
1425 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1426 ok(symbol_charset > 0,
1427 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1428 ok(russian_charset > 0,
1429 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1432 memset(&lf, 0, sizeof(lf));
1433 lf.lfCharSet = SYMBOL_CHARSET;
1434 lstrcpy(lf.lfFaceName, font_name);
1436 SetLastError(0xdeadbeef);
1437 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1438 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1439 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1440 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1441 ansi_charset, symbol_charset, russian_charset,
1442 *font_name ? font_name : "<empty>");
1443 if (*font_name && font_charset == ANSI_CHARSET)
1444 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1447 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1448 for (i = 0; i < efd.total; i++)
1450 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1452 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1453 font_name, efd.lf[i].lfFaceName);
1457 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1458 ok(symbol_charset > 0,
1459 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1460 ok(!russian_charset,
1461 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1467 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1468 #include "pshpack2.h"
1472 SHORT xAvgCharWidth;
1473 USHORT usWeightClass;
1474 USHORT usWidthClass;
1476 SHORT ySubscriptXSize;
1477 SHORT ySubscriptYSize;
1478 SHORT ySubscriptXOffset;
1479 SHORT ySubscriptYOffset;
1480 SHORT ySuperscriptXSize;
1481 SHORT ySuperscriptYSize;
1482 SHORT ySuperscriptXOffset;
1483 SHORT ySuperscriptYOffset;
1484 SHORT yStrikeoutSize;
1485 SHORT yStrikeoutPosition;
1488 ULONG ulUnicodeRange1;
1489 ULONG ulUnicodeRange2;
1490 ULONG ulUnicodeRange3;
1491 ULONG ulUnicodeRange4;
1494 USHORT usFirstCharIndex;
1495 USHORT usLastCharIndex;
1496 /* According to the Apple spec, original version didn't have the below fields,
1497 * version numbers were taked from the OpenType spec.
1499 /* version 0 (TrueType 1.5) */
1500 USHORT sTypoAscender;
1501 USHORT sTypoDescender;
1502 USHORT sTypoLineGap;
1504 USHORT usWinDescent;
1505 /* version 1 (TrueType 1.66) */
1506 ULONG ulCodePageRange1;
1507 ULONG ulCodePageRange2;
1508 /* version 2 (OpenType 1.2) */
1511 USHORT usDefaultChar;
1513 USHORT usMaxContext;
1515 #include "poppack.h"
1517 #ifdef WORDS_BIGENDIAN
1518 #define GET_BE_WORD(x) (x)
1520 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1523 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1524 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1525 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1526 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1528 static void test_text_metrics(const LOGFONTA *lf)
1531 HFONT hfont, hfont_old;
1534 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1539 const char *font_name = lf->lfFaceName;
1541 trace("Testing font metrics for %s, charset %d\n", font_name, lf->lfCharSet);
1545 SetLastError(0xdeadbeef);
1546 hfont = CreateFontIndirectA(lf);
1547 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1549 hfont_old = SelectObject(hdc, hfont);
1551 if(lf->lfWidth > 0) {
1552 HFONT hfont2, hfont_prev;
1553 GLYPHMETRICS gm1, gm2;
1555 MAT2 mat2 = { {0,1}, {0,0}, {0,0}, {0,1} };
1557 /* negative widths are handled just as positive ones */
1560 SetLastError(0xdeadbeef);
1561 hfont2 = CreateFontIndirectA(&lf2);
1562 ok(hfont2 != 0, "CreateFontIndirect error %u\n", GetLastError());
1563 hfont_prev = SelectObject(hdc, hfont2);
1565 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1566 memset(&gm1, 0xab, sizeof(gm1));
1567 SetLastError(0xdeadbeef);
1568 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat2);
1569 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1571 SelectObject(hdc, hfont_prev);
1572 DeleteObject(hfont2);
1574 memset(&gm2, 0xbb, sizeof(gm2));
1575 SetLastError(0xdeadbeef);
1576 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat2);
1577 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1579 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1580 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1581 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1582 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1583 gm1.gmCellIncX == gm2.gmCellIncX &&
1584 gm1.gmCellIncY == gm2.gmCellIncY,
1585 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1586 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1587 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1588 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1589 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1592 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1593 if (size == GDI_ERROR)
1595 trace("OS/2 chunk was not found\n");
1598 if (size > sizeof(tt_os2))
1600 trace("got too large OS/2 chunk of size %u\n", size);
1601 size = sizeof(tt_os2);
1604 memset(&tt_os2, 0, sizeof(tt_os2));
1605 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1606 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1608 version = GET_BE_WORD(tt_os2.version);
1609 trace("OS/2 chunk version %u, vendor %4.4s\n", version, (LPCSTR)&tt_os2.achVendID);
1611 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
1612 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
1613 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
1614 break_char = GET_BE_WORD(tt_os2.usBreakChar);
1616 trace("for %s first %x, last %x, default %x, break %x\n", font_name,
1617 first_unicode_char, last_unicode_char, default_char, break_char);
1619 SetLastError(0xdeadbeef);
1620 ret = GetTextMetricsA(hdc, &tmA);
1621 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
1622 trace("A: first %x, last %x, default %x, break %x\n",
1623 tmA.tmFirstChar, tmA.tmLastChar, tmA.tmDefaultChar, tmA.tmBreakChar);
1625 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1626 test_char = min(first_unicode_char - 1, 255);
1627 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
1628 font_name, tmA.tmFirstChar, test_char);
1630 if (lf->lfCharSet == SYMBOL_CHARSET)
1632 test_char = min(last_unicode_char - 0xf000, 255);
1633 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1634 font_name, tmA.tmLastChar, test_char);
1638 test_char = min(last_unicode_char, 255);
1639 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1640 font_name, tmA.tmLastChar, test_char);
1643 SetLastError(0xdeadbeef);
1644 ret = GetTextMetricsW(hdc, &tmW);
1645 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
1646 "GetTextMetricsW error %u\n", GetLastError());
1649 trace("W: first %x, last %x, default %x, break %x\n",
1650 tmW.tmFirstChar, tmW.tmLastChar, tmW.tmDefaultChar,
1653 if (lf->lfCharSet == SYMBOL_CHARSET)
1655 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1656 * sets symbol range to 0 - f0ff
1658 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
1659 font_name, tmW.tmFirstChar);
1660 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1661 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1662 font_name, tmW.tmLastChar);
1664 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1665 font_name, tmW.tmDefaultChar);
1666 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1667 font_name, tmW.tmBreakChar);
1671 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
1672 font_name, tmW.tmFirstChar, first_unicode_char);
1673 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
1674 font_name, tmW.tmLastChar, last_unicode_char);
1676 ret = GetDeviceCaps(hdc, LOGPIXELSX);
1677 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
1678 tmW.tmDigitizedAspectX, ret);
1679 ret = GetDeviceCaps(hdc, LOGPIXELSY);
1680 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
1681 tmW.tmDigitizedAspectX, ret);
1685 SelectObject(hdc, hfont_old);
1686 DeleteObject(hfont);
1691 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
1693 INT *enumed = (INT *)lParam;
1695 if (type == TRUETYPE_FONTTYPE)
1698 test_text_metrics(lf);
1703 static void test_GetTextMetrics(void)
1711 memset(&lf, 0, sizeof(lf));
1712 lf.lfCharSet = DEFAULT_CHARSET;
1714 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
1715 trace("Tested metrics of %d truetype fonts\n", enumed);
1720 static void test_nonexistent_font(void)
1725 char buf[LF_FACESIZE];
1727 if (!is_truetype_font_installed("Arial Black"))
1729 skip("Arial not installed\n");
1735 memset(&lf, 0, sizeof(lf));
1737 lf.lfWeight = FW_REGULAR;
1738 lf.lfCharSet = ANSI_CHARSET;
1739 lf.lfPitchAndFamily = FF_SWISS;
1740 strcpy(lf.lfFaceName, "Nonexistent font");
1742 hfont = CreateFontIndirectA(&lf);
1743 hfont = SelectObject(hdc, hfont);
1744 GetTextFaceA(hdc, sizeof(buf), buf);
1745 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
1746 DeleteObject(SelectObject(hdc, hfont));
1750 static void test_GdiRealizationInfo(void)
1755 HFONT hfont, hfont_old;
1758 if(!pGdiRealizationInfo)
1760 skip("GdiRealizationInfo not available\n");
1766 memset(info, 0xcc, sizeof(info));
1767 r = pGdiRealizationInfo(hdc, info);
1768 ok(r != 0, "ret 0\n");
1769 ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
1770 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
1772 if (!is_truetype_font_installed("Arial"))
1774 skip("skipping GdiRealizationInfo with truetype font\n");
1778 memset(&lf, 0, sizeof(lf));
1779 strcpy(lf.lfFaceName, "Arial");
1781 lf.lfWeight = FW_NORMAL;
1782 hfont = CreateFontIndirectA(&lf);
1783 hfont_old = SelectObject(hdc, hfont);
1785 memset(info, 0xcc, sizeof(info));
1786 r = pGdiRealizationInfo(hdc, info);
1787 ok(r != 0, "ret 0\n");
1788 ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
1789 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
1791 DeleteObject(SelectObject(hdc, hfont_old));
1803 test_bitmap_font_metrics();
1804 test_GdiGetCharDimensions();
1805 test_GetCharABCWidths();
1806 test_text_extents();
1807 test_GetGlyphIndices();
1808 test_GetKerningPairs();
1809 test_GetOutlineTextMetrics();
1810 test_SetTextJustification();
1811 test_font_charset();
1812 test_GetFontUnicodeRanges();
1813 test_nonexistent_font();
1815 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1816 * I'd like to avoid them in this test.
1818 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
1819 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
1820 if (is_truetype_font_installed("Arial Black") &&
1821 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1823 test_EnumFontFamilies("", ANSI_CHARSET);
1824 test_EnumFontFamilies("", SYMBOL_CHARSET);
1825 test_EnumFontFamilies("", DEFAULT_CHARSET);
1828 skip("Arial Black or Symbol/Wingdings is not installed\n");
1829 test_GetTextMetrics();
1830 test_GdiRealizationInfo();