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 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
34 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
35 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
36 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
37 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
39 static HMODULE hgdi32 = 0;
41 static void init(void)
43 hgdi32 = GetModuleHandleA("gdi32.dll");
45 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
46 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
47 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
48 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
49 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
52 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
54 if (type != TRUETYPE_FONTTYPE) return 1;
59 static BOOL is_truetype_font_installed(const char *name)
64 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
71 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
76 static BOOL is_font_installed(const char *name)
81 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
88 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
96 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
97 /* NT4 tries to be clever and only returns the minimum length */
98 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
100 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
101 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
102 ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
103 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
104 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
107 static HFONT create_font(const char* test, const LOGFONTA* lf)
109 HFONT hfont = CreateFontIndirectA(lf);
110 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
112 check_font(test, lf, hfont);
116 static void test_logfont(void)
121 memset(&lf, 0, sizeof lf);
123 lf.lfCharSet = ANSI_CHARSET;
124 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
125 lf.lfWeight = FW_DONTCARE;
128 lf.lfQuality = DEFAULT_QUALITY;
130 lstrcpyA(lf.lfFaceName, "Arial");
131 hfont = create_font("Arial", &lf);
134 memset(&lf, 'A', sizeof(lf));
135 hfont = CreateFontIndirectA(&lf);
136 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
138 lf.lfFaceName[LF_FACESIZE - 1] = 0;
139 check_font("AAA...", &lf, hfont);
143 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
145 if (type & RASTER_FONTTYPE)
147 LOGFONT *lf = (LOGFONT *)lParam;
149 return 0; /* stop enumeration */
152 return 1; /* continue enumeration */
155 static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
156 INT test_str_len, const TEXTMETRICA *tm_orig,
157 const SIZE *size_orig, INT width_orig,
158 INT scale_x, INT scale_y)
168 old_hfont = SelectObject(hdc, hfont);
170 GetTextMetricsA(hdc, &tm);
172 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
173 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
174 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
175 ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
177 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
179 ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x);
180 ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y);
182 GetCharWidthA(hdc, 'A', 'A', &width);
184 ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
186 SelectObject(hdc, old_hfont);
189 /* see whether GDI scales bitmap font metrics */
190 static void test_bitmap_font(void)
192 static const char test_str[11] = "Test String";
195 HFONT hfont, old_hfont;
198 INT ret, i, width_orig, height_orig;
202 /* "System" has only 1 pixel size defined, otherwise the test breaks */
203 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
207 trace("no bitmap fonts were found, skipping the test\n");
211 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
213 height_orig = bitmap_lf.lfHeight;
214 hfont = create_font("bitmap", &bitmap_lf);
216 old_hfont = SelectObject(hdc, hfont);
217 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
218 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
219 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
220 SelectObject(hdc, old_hfont);
223 /* test fractional scaling */
224 for (i = 1; i < height_orig; i++)
226 hfont = create_font("fractional", &bitmap_lf);
227 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
231 /* test integer scaling 3x2 */
232 bitmap_lf.lfHeight = height_orig * 2;
233 bitmap_lf.lfWidth *= 3;
234 hfont = create_font("3x2", &bitmap_lf);
237 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
241 /* test integer scaling 3x3 */
242 bitmap_lf.lfHeight = height_orig * 3;
243 bitmap_lf.lfWidth = 0;
244 hfont = create_font("3x3", &bitmap_lf);
248 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
255 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
257 LOGFONT *lf = (LOGFONT *)lParam;
259 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
262 return 0; /* stop enumeration */
264 return 1; /* continue enumeration */
267 #define CP1252_BIT 0x00000001
268 #define CP1250_BIT 0x00000002
269 #define CP1251_BIT 0x00000004
270 #define CP1253_BIT 0x00000008
271 #define CP1254_BIT 0x00000010
272 #define CP1255_BIT 0x00000020
273 #define CP1256_BIT 0x00000040
274 #define CP1257_BIT 0x00000080
275 #define CP1258_BIT 0x00000100
276 #define CP874_BIT 0x00010000
277 #define CP932_BIT 0x00020000
278 #define CP936_BIT 0x00040000
279 #define CP949_BIT 0x00080000
280 #define CP950_BIT 0x00100000
282 static void test_bitmap_font_metrics(void)
284 static const struct font_data
286 const char face_name[LF_FACESIZE];
287 int weight, height, ascent, descent, int_leading, ext_leading;
288 int ave_char_width, max_char_width;
292 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT | CP1250_BIT | CP1251_BIT },
293 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT | CP1250_BIT | CP1251_BIT },
294 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, CP1252_BIT | CP1251_BIT },
295 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, CP1250_BIT },
296 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, CP1252_BIT },
297 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, CP1250_BIT },
298 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, CP1251_BIT },
299 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, CP1252_BIT },
300 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, CP1250_BIT },
301 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, CP1251_BIT },
302 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, CP1252_BIT | CP1250_BIT | CP1251_BIT },
303 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
304 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
305 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
306 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT },
307 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, CP1250_BIT | CP1251_BIT },
308 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, CP1252_BIT | CP1250_BIT },
309 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, CP1251_BIT },
310 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, CP1252_BIT | CP1250_BIT },
311 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, CP1251_BIT },
312 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, CP1252_BIT },
313 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, CP1250_BIT },
314 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, CP1251_BIT },
315 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, CP1252_BIT },
316 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, CP1250_BIT },
317 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, CP1251_BIT },
318 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, CP1252_BIT | CP1250_BIT },
319 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, CP1251_BIT },
320 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, CP1252_BIT | CP1250_BIT | CP1251_BIT },
321 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
322 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, CP1252_BIT | CP1250_BIT | CP1251_BIT },
323 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT },
324 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, CP1250_BIT | CP1251_BIT },
325 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT},
326 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT | CP1251_BIT },
327 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT },
328 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT | CP1251_BIT },
329 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT },
330 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT | CP1251_BIT },
331 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT },
332 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT | CP1251_BIT },
333 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
334 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
335 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
336 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT | CP1250_BIT },
337 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT }
339 /* FIXME: add "Terminal" */
343 HFONT hfont, old_hfont;
347 hdc = CreateCompatibleDC(0);
350 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
354 memset(&lf, 0, sizeof(lf));
356 lf.lfHeight = fd[i].height;
357 strcpy(lf.lfFaceName, fd[i].face_name);
359 for(bit = 0; bit < 32; bit++)
366 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
367 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
369 lf.lfCharSet = csi.ciCharset;
370 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
373 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
375 hfont = create_font(lf.lfFaceName, &lf);
376 old_hfont = SelectObject(hdc, hfont);
377 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
379 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);
380 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);
381 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);
382 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);
383 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);
384 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);
385 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);
387 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
388 that make the max width bigger */
389 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
390 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);
392 SelectObject(hdc, old_hfont);
400 static void test_GdiGetCharDimensions(void)
406 LONG avgwidth, height;
407 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
409 if (!pGdiGetCharDimensions)
411 skip("GetFontUnicodeRanges not available on this platform\n");
415 hdc = CreateCompatibleDC(NULL);
417 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
418 avgwidth = ((size.cx / 26) + 1) / 2;
420 ret = pGdiGetCharDimensions(hdc, &tm, &height);
421 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
422 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
424 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
425 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
427 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
428 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
431 ret = pGdiGetCharDimensions(hdc, NULL, &height);
432 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
433 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
438 static void test_GetCharABCWidthsW(void)
442 if (!pGetCharABCWidthsW) return;
444 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
445 ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
448 static void test_text_extents(void)
450 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
452 INT i, len, fit1, fit2;
460 memset(&lf, 0, sizeof(lf));
461 strcpy(lf.lfFaceName, "Arial");
464 hfont = CreateFontIndirectA(&lf);
466 hfont = SelectObject(hdc, hfont);
467 GetTextMetricsA(hdc, &tm);
468 GetTextExtentPointA(hdc, "o", 1, &sz);
469 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
471 SetLastError(0xdeadbeef);
472 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
473 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
475 skip("Skipping remainder of text extents test on a Win9x platform\n");
476 hfont = SelectObject(hdc, hfont);
483 extents = HeapAlloc(GetProcessHeap(), 0, len * sizeof extents[0]);
484 memset(extents, 0, len * sizeof extents[0]);
485 extents[0] = 1; /* So that the increasing sequence test will fail
486 if the extents array is untouched. */
487 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
488 GetTextExtentPointW(hdc, wt, len, &sz2);
490 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
491 /* Because of the '\n' in the string GetTextExtentExPoint and
492 GetTextExtentPoint return different widths under Win2k, but
493 under WinXP they return the same width. So we don't test that
496 for (i = 1; i < len; ++i)
497 ok(extents[i-1] <= extents[i],
498 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
500 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
501 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
502 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
503 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
504 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
505 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
506 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
507 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
508 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
509 ok(extents[0] == extents[2] && extents[1] == extents[3],
510 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
511 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
512 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
513 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
514 HeapFree(GetProcessHeap(), 0, extents);
516 hfont = SelectObject(hdc, hfont);
518 ReleaseDC(NULL, hdc);
521 static void test_GetGlyphIndices()
528 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
529 WORD glyphs[(sizeof(testtext)/2)-1];
532 if (!pGetGlyphIndicesW) {
533 skip("GetGlyphIndices not available on platform\n");
537 if(!is_font_installed("Symbol"))
539 skip("Symbol is not installed so skipping this test\n");
543 memset(&lf, 0, sizeof(lf));
544 strcpy(lf.lfFaceName, "Symbol");
547 hfont = CreateFontIndirectA(&lf);
550 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
551 flags |= GGI_MARK_NONEXISTING_GLYPHS;
552 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
553 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
554 ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
556 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
557 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
558 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
559 textm.tmDefaultChar, glyphs[4]);
562 static void test_GetKerningPairs(void)
564 static const struct kerning_data
566 const char face_name[LF_FACESIZE];
568 /* some interesting fields from OUTLINETEXTMETRIC */
569 LONG tmHeight, tmAscent, tmDescent;
574 UINT otmsCapEmHeight;
579 UINT otmusMinimumPPEM;
580 /* small subset of kerning pairs to test */
581 DWORD total_kern_pairs;
582 const KERNINGPAIR kern_pair[26];
585 {"Arial", 12, 12, 9, 3,
586 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
589 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
590 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
591 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
592 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
593 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
594 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
595 {933,970,+1},{933,972,-1}
598 {"Arial", -34, 39, 32, 7,
599 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
602 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
603 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
604 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
605 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
606 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
607 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
608 {933,970,+2},{933,972,-3}
611 { "Arial", 120, 120, 97, 23,
612 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
615 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
616 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
617 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
618 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
619 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
620 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
621 {933,970,+6},{933,972,-10}
624 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
625 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
626 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
629 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
630 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
631 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
632 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
633 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
634 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
635 {933,970,+54},{933,972,-83}
641 HFONT hfont, hfont_old;
642 KERNINGPAIR *kern_pair;
644 DWORD total_kern_pairs, ret, i, n, matches;
648 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
649 * which may render this test unusable, so we're trying to avoid that.
651 SetLastError(0xdeadbeef);
652 GetKerningPairsW(hdc, 0, NULL);
653 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
655 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
660 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
662 OUTLINETEXTMETRICW otm;
664 if (!is_font_installed(kd[i].face_name))
666 trace("%s is not installed so skipping this test\n", kd[i].face_name);
670 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
672 memset(&lf, 0, sizeof(lf));
673 strcpy(lf.lfFaceName, kd[i].face_name);
674 lf.lfHeight = kd[i].height;
675 hfont = CreateFontIndirect(&lf);
678 hfont_old = SelectObject(hdc, hfont);
680 SetLastError(0xdeadbeef);
681 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
682 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
684 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
685 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
686 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
687 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
688 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
689 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
691 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
692 kd[i].otmEMSquare, otm.otmEMSquare);
693 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
694 kd[i].otmAscent, otm.otmAscent);
695 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
696 kd[i].otmDescent, otm.otmDescent);
697 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
698 kd[i].otmLineGap, otm.otmLineGap);
700 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
701 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
702 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
703 kd[i].otmsXHeight, otm.otmsXHeight);
704 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
705 kd[i].otmMacAscent, otm.otmMacAscent);
706 ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
707 kd[i].otmMacDescent, otm.otmMacDescent);
708 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
709 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
710 kd[i].otmMacLineGap, otm.otmMacLineGap);
711 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
712 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
715 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
716 trace("total_kern_pairs %u\n", total_kern_pairs);
717 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
719 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
720 SetLastError(0xdeadbeef);
721 ret = GetKerningPairsW(hdc, 0, kern_pair);
722 ok(GetLastError() == ERROR_INVALID_PARAMETER,
723 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
724 ok(ret == 0, "got %lu, expected 0\n", ret);
727 ret = GetKerningPairsW(hdc, 100, NULL);
728 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
730 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
731 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
733 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
734 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
738 for (n = 0; n < ret; n++)
742 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
743 trace("{'%c','%c',%d},\n",
744 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
746 for (j = 0; j < kd[i].total_kern_pairs; j++)
748 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
749 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
751 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
752 "pair %d:%d got %d, expected %d\n",
753 kern_pair[n].wFirst, kern_pair[n].wSecond,
754 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
760 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
761 matches, kd[i].total_kern_pairs);
763 HeapFree(GetProcessHeap(), 0, kern_pair);
765 SelectObject(hdc, hfont_old);
772 static void test_GetOutlineTextMetrics(void)
774 OUTLINETEXTMETRIC *otm;
776 HFONT hfont, hfont_old;
780 if (!is_font_installed("Arial"))
782 skip("Arial is not installed\n");
788 memset(&lf, 0, sizeof(lf));
789 strcpy(lf.lfFaceName, "Arial");
791 lf.lfWeight = FW_NORMAL;
792 lf.lfPitchAndFamily = DEFAULT_PITCH;
793 lf.lfQuality = PROOF_QUALITY;
794 hfont = CreateFontIndirect(&lf);
797 hfont_old = SelectObject(hdc, hfont);
798 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
799 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
801 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
803 memset(otm, 0xAA, otm_size);
804 SetLastError(0xdeadbeef);
805 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
806 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
807 ok(ret == 1 /* Win9x */ ||
808 ret == otm->otmSize /* XP*/,
809 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
810 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
812 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
813 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
814 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
815 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
818 memset(otm, 0xAA, otm_size);
819 SetLastError(0xdeadbeef);
820 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
821 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
822 ok(ret == 1 /* Win9x */ ||
823 ret == otm->otmSize /* XP*/,
824 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
825 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
827 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
828 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
829 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
830 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
833 /* ask about truncated data */
834 memset(otm, 0xAA, otm_size);
835 SetLastError(0xdeadbeef);
836 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
837 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
838 ok(ret == 1 /* Win9x */ ||
839 ret == otm->otmSize /* XP*/,
840 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
841 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
843 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
844 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
845 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
847 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
849 HeapFree(GetProcessHeap(), 0, otm);
851 SelectObject(hdc, hfont_old);
857 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
861 outputWidth = 0, /* to test TabbedTextOut() */
862 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
863 areaWidth = clientArea->right - clientArea->left,
865 BOOL lastExtent = FALSE;
866 PSTR pFirstChar, pLastChar;
872 int GetTextExtentExPointWWidth;
873 int TabbedTextOutWidth;
876 GetTextMetricsA(hdc, &tm);
880 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
886 /* if not at the end of the string, ... */
887 if (*str == '\0') break;
888 /* ... add the next word to the current extent */
889 while (*str != '\0' && *str++ != tm.tmBreakChar);
891 SetTextJustification(hdc, 0, 0);
892 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
893 } while ((int) size.cx < areaWidth);
895 /* ignore trailing break chars */
897 while (*(pLastChar - 1) == tm.tmBreakChar)
903 if (*str == '\0' || breakCount <= 0) pLastChar = str;
905 SetTextJustification(hdc, 0, 0);
906 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
908 /* do not justify the last extent */
909 if (*str != '\0' && breakCount > 0)
911 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
912 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
913 justifiedWidth = size.cx;
915 else lastExtent = TRUE;
917 x = clientArea->left;
919 outputWidth = LOWORD(TabbedTextOut(
920 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
922 /* catch errors and report them */
923 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
925 memset(error[nErrors].extent, 0, 100);
926 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
927 error[nErrors].TabbedTextOutWidth = outputWidth;
928 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
934 } while (*str && y < clientArea->bottom);
936 for (e = 0; e < nErrors; e++)
938 ok(error[e].TabbedTextOutWidth == areaWidth,
939 "The output text (\"%s\") width should be %d, not %d.\n",
940 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
941 /* The width returned by GetTextExtentPoint32() is exactly the same
942 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
943 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
944 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
945 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
949 static void test_SetTextJustification(void)
956 static char testText[] =
957 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
958 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
959 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
960 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
961 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
962 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
963 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
965 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
966 GetClientRect( hwnd, &clientArea );
969 memset(&lf, 0, sizeof lf);
970 lf.lfCharSet = ANSI_CHARSET;
971 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
972 lf.lfWeight = FW_DONTCARE;
974 lf.lfQuality = DEFAULT_QUALITY;
975 lstrcpyA(lf.lfFaceName, "Times New Roman");
976 hfont = create_font("Times New Roman", &lf);
977 SelectObject(hdc, hfont);
979 testJustification(hdc, testText, &clientArea);
982 ReleaseDC(hwnd, hdc);
986 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
990 HFONT hfont, hfont_old;
997 assert(count <= 128);
999 memset(&lf, 0, sizeof(lf));
1001 lf.lfCharSet = charset;
1003 lstrcpyA(lf.lfFaceName, "Arial");
1004 SetLastError(0xdeadbeef);
1005 hfont = CreateFontIndirectA(&lf);
1006 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1009 hfont_old = SelectObject(hdc, hfont);
1011 cs = GetTextCharsetInfo(hdc, &fs, 0);
1012 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1014 SetLastError(0xdeadbeef);
1015 ret = GetTextFace(hdc, sizeof(name), name);
1016 ok(ret, "GetTextFace error %u\n", GetLastError());
1018 if (charset == SYMBOL_CHARSET)
1020 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1021 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1025 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1026 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1029 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1031 trace("Can't find codepage for charset %d\n", cs);
1035 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1040 WCHAR unicode_buf[128];
1042 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1044 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1046 SetLastError(0xdeadbeef);
1047 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1048 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1054 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1056 SetLastError(0xdeadbeef);
1057 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1058 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1061 SelectObject(hdc, hfont_old);
1062 DeleteObject(hfont);
1069 static void test_font_charset(void)
1071 static struct charset_data
1075 WORD font_idxA[128], font_idxW[128];
1078 { ANSI_CHARSET, 1252 },
1079 { RUSSIAN_CHARSET, 1251 },
1080 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1084 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1086 skip("Skipping the font charset test on a Win9x platform\n");
1090 if (!is_font_installed("Arial"))
1092 skip("Arial is not installed\n");
1096 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1098 if (cd[i].charset == SYMBOL_CHARSET)
1100 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1102 skip("Symbol or Wingdings is not installed\n");
1106 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1107 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1108 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1111 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1114 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1115 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1118 skip("Symbol or Wingdings is not installed\n");
1121 static void test_GetFontUnicodeRanges(void)
1125 HFONT hfont, hfont_old;
1129 if (!pGetFontUnicodeRanges)
1131 skip("GetFontUnicodeRanges not available before W2K\n");
1135 memset(&lf, 0, sizeof(lf));
1136 lstrcpyA(lf.lfFaceName, "Arial");
1137 hfont = create_font("Arial", &lf);
1140 hfont_old = SelectObject(hdc, hfont);
1142 size = pGetFontUnicodeRanges(NULL, NULL);
1143 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1145 size = pGetFontUnicodeRanges(hdc, NULL);
1146 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1148 gs = HeapAlloc(GetProcessHeap(), 0, size);
1150 size = pGetFontUnicodeRanges(hdc, gs);
1151 ok(size, "GetFontUnicodeRanges failed\n");
1153 for (i = 0; i < gs->cRanges; i++)
1154 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1156 trace("found %u ranges\n", gs->cRanges);
1158 HeapFree(GetProcessHeap(), 0, gs);
1160 SelectObject(hdc, hfont_old);
1161 DeleteObject(hfont);
1162 ReleaseDC(NULL, hdc);
1165 #define MAX_ENUM_FONTS 256
1167 struct enum_font_data
1170 LOGFONT lf[MAX_ENUM_FONTS];
1173 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1175 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1177 if (type != TRUETYPE_FONTTYPE) return 1;
1179 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1180 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1182 if (efd->total < MAX_ENUM_FONTS)
1183 efd->lf[efd->total++] = *lf;
1188 static void get_charset_stats(struct enum_font_data *efd,
1189 int *ansi_charset, int *symbol_charset,
1190 int *russian_charset)
1195 *symbol_charset = 0;
1196 *russian_charset = 0;
1198 for (i = 0; i < efd->total; i++)
1200 switch (efd->lf[i].lfCharSet)
1205 case SYMBOL_CHARSET:
1206 (*symbol_charset)++;
1208 case RUSSIAN_CHARSET:
1209 (*russian_charset)++;
1215 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1217 struct enum_font_data efd;
1220 int i, ret, ansi_charset, symbol_charset, russian_charset;
1222 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1224 if (*font_name && !is_truetype_font_installed(font_name))
1226 skip("%s is not installed\n", font_name);
1232 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1233 * while EnumFontFamiliesEx doesn't.
1235 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1238 SetLastError(0xdeadbeef);
1239 ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1240 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1241 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1242 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1243 ansi_charset, symbol_charset, russian_charset);
1244 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1245 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1246 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1247 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1251 SetLastError(0xdeadbeef);
1252 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1253 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1254 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1255 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1256 ansi_charset, symbol_charset, russian_charset,
1257 *font_name ? font_name : "<empty>");
1259 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1261 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1262 for (i = 0; i < efd.total; i++)
1264 /* FIXME: remove completely once Wine is fixed */
1265 if (efd.lf[i].lfCharSet != font_charset)
1268 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1271 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1272 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1273 font_name, efd.lf[i].lfFaceName);
1276 memset(&lf, 0, sizeof(lf));
1277 lf.lfCharSet = ANSI_CHARSET;
1278 lstrcpy(lf.lfFaceName, font_name);
1280 SetLastError(0xdeadbeef);
1281 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1282 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1283 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1284 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1285 ansi_charset, symbol_charset, russian_charset,
1286 *font_name ? font_name : "<empty>");
1287 if (font_charset == SYMBOL_CHARSET)
1290 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1292 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1296 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1297 for (i = 0; i < efd.total; i++)
1299 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1301 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1302 font_name, efd.lf[i].lfFaceName);
1306 /* DEFAULT_CHARSET should enumerate all available charsets */
1307 memset(&lf, 0, sizeof(lf));
1308 lf.lfCharSet = DEFAULT_CHARSET;
1309 lstrcpy(lf.lfFaceName, font_name);
1311 SetLastError(0xdeadbeef);
1312 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1313 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1314 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1315 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1316 ansi_charset, symbol_charset, russian_charset,
1317 *font_name ? font_name : "<empty>");
1318 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1319 for (i = 0; i < efd.total; i++)
1322 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1323 font_name, efd.lf[i].lfFaceName);
1327 switch (font_charset)
1330 ok(ansi_charset > 0,
1331 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1333 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1334 ok(russian_charset > 0,
1335 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1337 case SYMBOL_CHARSET:
1339 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1341 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1342 ok(!russian_charset,
1343 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1345 case DEFAULT_CHARSET:
1346 ok(ansi_charset > 0,
1347 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1348 ok(symbol_charset > 0,
1349 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1350 ok(russian_charset > 0,
1351 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1357 ok(ansi_charset > 0,
1358 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1359 ok(symbol_charset > 0,
1360 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1361 ok(russian_charset > 0,
1362 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1365 memset(&lf, 0, sizeof(lf));
1366 lf.lfCharSet = SYMBOL_CHARSET;
1367 lstrcpy(lf.lfFaceName, font_name);
1369 SetLastError(0xdeadbeef);
1370 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1371 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1372 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1373 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1374 ansi_charset, symbol_charset, russian_charset,
1375 *font_name ? font_name : "<empty>");
1376 if (*font_name && font_charset == ANSI_CHARSET)
1377 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1380 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1381 for (i = 0; i < efd.total; i++)
1383 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1385 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1386 font_name, efd.lf[i].lfFaceName);
1390 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1391 ok(symbol_charset > 0,
1392 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1393 ok(!russian_charset,
1394 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1406 test_bitmap_font_metrics();
1407 test_GdiGetCharDimensions();
1408 test_GetCharABCWidthsW();
1409 test_text_extents();
1410 test_GetGlyphIndices();
1411 test_GetKerningPairs();
1412 test_GetOutlineTextMetrics();
1413 test_SetTextJustification();
1414 test_font_charset();
1415 test_GetFontUnicodeRanges();
1416 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1417 * I'd like to avoid them in this test.
1419 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
1420 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
1421 if (is_truetype_font_installed("Arial Black") &&
1422 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1424 test_EnumFontFamilies("", ANSI_CHARSET);
1425 test_EnumFontFamilies("", SYMBOL_CHARSET);
1426 test_EnumFontFamilies("", DEFAULT_CHARSET);
1429 skip("Arial Black or Symbol/Wingdings is not installed\n");