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
30 #include "wine/test.h"
32 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
37 static BOOL is_font_installed(const char *name)
42 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
49 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
57 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
58 /* NT4 tries to be clever and only returns the minimum length */
59 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
61 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
62 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
63 ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
64 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
65 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
68 static HFONT create_font(const char* test, const LOGFONTA* lf)
70 HFONT hfont = CreateFontIndirectA(lf);
71 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
73 check_font(test, lf, hfont);
77 static void test_logfont(void)
82 memset(&lf, 0, sizeof lf);
84 lf.lfCharSet = ANSI_CHARSET;
85 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
86 lf.lfWeight = FW_DONTCARE;
89 lf.lfQuality = DEFAULT_QUALITY;
91 lstrcpyA(lf.lfFaceName, "Arial");
92 hfont = create_font("Arial", &lf);
95 memset(&lf, 'A', sizeof(lf));
96 hfont = CreateFontIndirectA(&lf);
97 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
99 lf.lfFaceName[LF_FACESIZE - 1] = 0;
100 check_font("AAA...", &lf, hfont);
104 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
106 if (type & RASTER_FONTTYPE)
108 LOGFONT *lf = (LOGFONT *)lParam;
110 return 0; /* stop enumeration */
113 return 1; /* continue enumeration */
116 static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
117 INT test_str_len, const TEXTMETRICA *tm_orig,
118 const SIZE *size_orig, INT width_orig,
119 INT scale_x, INT scale_y)
129 old_hfont = SelectObject(hdc, hfont);
131 GetTextMetricsA(hdc, &tm);
133 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%ld != %ld\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
134 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%ld != %ld\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
135 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%ld != %ld\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
136 ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%ld != %ld\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
138 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
140 ok(size.cx == size_orig->cx * scale_x, "%ld != %ld\n", size.cx, size_orig->cx * scale_x);
141 ok(size.cy == size_orig->cy * scale_y, "%ld != %ld\n", size.cy, size_orig->cy * scale_y);
143 GetCharWidthA(hdc, 'A', 'A', &width);
145 ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
147 SelectObject(hdc, old_hfont);
150 /* see whether GDI scales bitmap font metrics */
151 static void test_bitmap_font(void)
153 static const char test_str[11] = "Test String";
156 HFONT hfont, old_hfont;
159 INT ret, i, width_orig, height_orig;
163 /* "System" has only 1 pixel size defined, otherwise the test breaks */
164 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
168 trace("no bitmap fonts were found, skipping the test\n");
172 trace("found bitmap font %s, height %ld\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
174 height_orig = bitmap_lf.lfHeight;
175 hfont = create_font("bitmap", &bitmap_lf);
177 old_hfont = SelectObject(hdc, hfont);
178 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
179 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
180 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
181 SelectObject(hdc, old_hfont);
184 /* test fractional scaling */
185 for (i = 1; i < height_orig; i++)
187 hfont = create_font("fractional", &bitmap_lf);
188 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
192 /* test integer scaling 3x2 */
193 bitmap_lf.lfHeight = height_orig * 2;
194 bitmap_lf.lfWidth *= 3;
195 hfont = create_font("3x2", &bitmap_lf);
198 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
202 /* test integer scaling 3x3 */
203 bitmap_lf.lfHeight = height_orig * 3;
204 bitmap_lf.lfWidth = 0;
205 hfont = create_font("3x3", &bitmap_lf);
209 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
216 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
218 LOGFONT *lf = (LOGFONT *)lParam;
220 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
223 return 0; /* stop enumeration */
225 return 1; /* continue enumeration */
228 #define CP1252_BIT 0x00000001
229 #define CP1250_BIT 0x00000002
230 #define CP1251_BIT 0x00000004
231 #define CP1253_BIT 0x00000008
232 #define CP1254_BIT 0x00000010
233 #define CP1255_BIT 0x00000020
234 #define CP1256_BIT 0x00000040
235 #define CP1257_BIT 0x00000080
236 #define CP1258_BIT 0x00000100
237 #define CP874_BIT 0x00010000
238 #define CP932_BIT 0x00020000
239 #define CP936_BIT 0x00040000
240 #define CP949_BIT 0x00080000
241 #define CP950_BIT 0x00100000
243 static void test_bitmap_font_metrics(void)
245 static const struct font_data
247 const char face_name[LF_FACESIZE];
248 int weight, height, ascent, descent, int_leading, ext_leading;
249 int ave_char_width, max_char_width;
253 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT | CP1250_BIT | CP1251_BIT },
254 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT | CP1250_BIT | CP1251_BIT },
255 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, CP1252_BIT | CP1251_BIT },
256 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, CP1250_BIT },
257 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, CP1252_BIT },
258 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, CP1250_BIT },
259 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, CP1251_BIT },
260 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, CP1252_BIT },
261 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, CP1250_BIT },
262 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, CP1251_BIT },
263 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, CP1252_BIT | CP1250_BIT | CP1251_BIT },
264 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
265 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
266 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
267 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT },
268 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, CP1250_BIT | CP1251_BIT },
269 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, CP1252_BIT | CP1250_BIT },
270 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, CP1251_BIT },
271 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, CP1252_BIT | CP1250_BIT },
272 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, CP1251_BIT },
273 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, CP1252_BIT },
274 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, CP1250_BIT },
275 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, CP1251_BIT },
276 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, CP1252_BIT },
277 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, CP1250_BIT },
278 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, CP1251_BIT },
279 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, CP1252_BIT | CP1250_BIT },
280 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, CP1251_BIT },
281 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, CP1252_BIT | CP1250_BIT | CP1251_BIT },
282 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
283 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, CP1252_BIT | CP1250_BIT | CP1251_BIT },
284 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT },
285 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, CP1250_BIT | CP1251_BIT },
286 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT},
287 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT | CP1251_BIT },
288 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT },
289 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT | CP1251_BIT },
290 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT },
291 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT | CP1251_BIT },
292 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT },
293 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT | CP1251_BIT },
294 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
295 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
296 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
297 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT | CP1250_BIT },
298 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT }
300 /* FIXME: add "Terminal" */
304 HFONT hfont, old_hfont;
308 hdc = CreateCompatibleDC(0);
311 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
315 memset(&lf, 0, sizeof(lf));
317 lf.lfHeight = fd[i].height;
318 strcpy(lf.lfFaceName, fd[i].face_name);
320 for(bit = 0; bit < 32; bit++)
327 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
328 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
330 lf.lfCharSet = csi.ciCharset;
331 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
334 trace("found font %s, height %ld charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
336 hfont = create_font(lf.lfFaceName, &lf);
337 old_hfont = SelectObject(hdc, hfont);
338 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %ld\n", GetLastError());
340 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
341 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
342 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
343 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
344 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
345 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
346 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
348 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
349 that make the max width bigger */
350 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
351 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %ld != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
353 SelectObject(hdc, old_hfont);
361 static void test_GdiGetCharDimensions(void)
367 LONG avgwidth, height;
368 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
369 typedef LONG (WINAPI *fnGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
370 fnGdiGetCharDimensions GdiGetCharDimensions = (fnGdiGetCharDimensions)GetProcAddress(LoadLibrary("gdi32"), "GdiGetCharDimensions");
371 if (!GdiGetCharDimensions) return;
373 hdc = CreateCompatibleDC(NULL);
375 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
376 avgwidth = ((size.cx / 26) + 1) / 2;
378 ret = GdiGetCharDimensions(hdc, &tm, &height);
379 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
380 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm.tmHeight, height);
382 ret = GdiGetCharDimensions(hdc, &tm, NULL);
383 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
385 ret = GdiGetCharDimensions(hdc, NULL, NULL);
386 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
389 ret = GdiGetCharDimensions(hdc, NULL, &height);
390 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth, ret);
391 ok(height == size.cy, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size.cy, height);
396 static void test_GetCharABCWidthsW(void)
400 typedef BOOL (WINAPI *fnGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
401 fnGetCharABCWidthsW GetCharABCWidthsW = (fnGetCharABCWidthsW)GetProcAddress(LoadLibrary("gdi32"), "GetCharABCWidthsW");
402 if (!GetCharABCWidthsW) return;
404 ret = GetCharABCWidthsW(NULL, 'a', 'a', abc);
405 ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
408 static void test_text_extents(void)
410 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
412 INT i, len, fit1, fit2;
420 memset(&lf, 0, sizeof(lf));
421 strcpy(lf.lfFaceName, "Arial");
424 hfont = CreateFontIndirectA(&lf);
426 hfont = SelectObject(hdc, hfont);
427 GetTextMetricsA(hdc, &tm);
428 GetTextExtentPointA(hdc, "o", 1, &sz);
429 ok(sz.cy == tm.tmHeight, "cy %ld tmHeight %ld\n", sz.cy, tm.tmHeight);
431 SetLastError(0xdeadbeef);
432 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
433 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
435 trace("Skipping remainder of text extents test on a Win9x platform\n");
436 SelectObject(hdc, hfont);
443 extents = HeapAlloc(GetProcessHeap(), 0, len * sizeof extents[0]);
444 memset(extents, 0, len * sizeof extents[0]);
445 extents[0] = 1; /* So that the increasing sequence test will fail
446 if the extents array is untouched. */
447 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
448 GetTextExtentPointW(hdc, wt, len, &sz2);
450 "cy from GetTextExtentExPointW (%ld) and GetTextExtentPointW (%ld) differ\n", sz1.cy, sz2.cy);
451 /* Because of the '\n' in the string GetTextExtentExPoint and
452 GetTextExtentPoint return different widths under Win2k, but
453 under WinXP they return the same width. So we don't test that
456 for (i = 1; i < len; ++i)
457 ok(extents[i-1] <= extents[i],
458 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
460 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
461 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
462 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
463 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
464 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
465 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
466 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
467 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
468 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
469 ok(extents[0] == extents[2] && extents[1] == extents[3],
470 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
471 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
472 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
473 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
474 HeapFree(GetProcessHeap(), 0, extents);
476 SelectObject(hdc, hfont);
478 ReleaseDC(NULL, hdc);
481 static void test_GetGlyphIndices()
488 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
489 WORD glyphs[(sizeof(testtext)/2)-1];
492 typedef BOOL (WINAPI *fnGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
493 fnGetGlyphIndicesW GetGlyphIndicesW = (fnGetGlyphIndicesW)GetProcAddress(LoadLibrary("gdi32"),
495 if (!GetGlyphIndicesW) {
496 trace("GetGlyphIndices not available on platform\n");
500 if(!is_font_installed("Symbol"))
502 trace("Symbol is not installed so skipping this test\n");
506 memset(&lf, 0, sizeof(lf));
507 strcpy(lf.lfFaceName, "Symbol");
510 hfont = CreateFontIndirectA(&lf);
513 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
514 flags |= GGI_MARK_NONEXISTING_GLYPHS;
515 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
516 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
517 ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
519 charcount = GetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
520 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %ld\n", charcount);
521 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
522 textm.tmDefaultChar, glyphs[4]);
525 static void test_GetKerningPairs(void)
527 static const struct kerning_data
529 const char face_name[LF_FACESIZE];
531 /* small subset of kerning pairs to test */
532 DWORD total_kern_pairs;
533 const KERNINGPAIR kern_pair[20];
538 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
539 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
540 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
541 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
542 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3}
547 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
548 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
549 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
550 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
551 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8}
556 HFONT hfont, hfont_old;
557 KERNINGPAIR *kern_pair;
559 DWORD total_kern_pairs, ret, i, n, matches;
563 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
564 * which may render this test unusable, so we're trying to avoid that.
566 SetLastError(0xdeadbeef);
567 GetKerningPairsW(hdc, 0, NULL);
568 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
570 trace("Skipping the GetKerningPairs test on a Win9x platform\n");
575 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
577 if (!is_font_installed(kd[i].face_name))
579 trace("%s is not installed so skipping this test\n", kd[i].face_name);
583 memset(&lf, 0, sizeof(lf));
584 strcpy(lf.lfFaceName, kd[i].face_name);
585 lf.lfHeight = kd[i].height;
586 hfont = CreateFontIndirect(&lf);
589 hfont_old = SelectObject(hdc, hfont);
591 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
592 trace("font %s, height %ld, total_kern_pairs %lu\n",
593 kd[i].face_name, kd[i].height, total_kern_pairs);
594 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
596 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
597 SetLastError(0xdeadbeef);
598 ret = GetKerningPairsW(hdc, 0, kern_pair);
599 ok(GetLastError() == ERROR_INVALID_PARAMETER,
600 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
601 ok(ret == 0, "got %lu, expected 0\n", ret);
604 ret = GetKerningPairsW(hdc, 100, NULL);
605 ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
607 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
608 ok(ret == total_kern_pairs/2, "got %lu, expected %lu\n", ret, total_kern_pairs/2);
610 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
611 ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
615 for (n = 0; n < ret; n++)
619 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
620 trace("wFirst '%c', wSecond '%c', iKernAmount %d\n",
621 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
623 for (j = 0; j < kd[i].total_kern_pairs; j++)
625 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
626 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond &&
627 kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount)
629 /*trace("match\n");*/
635 ok(matches == kd[i].total_kern_pairs, "got matches %lu, expected %lu\n",
636 matches, kd[i].total_kern_pairs);
638 HeapFree(GetProcessHeap(), 0, kern_pair);
640 SelectObject(hdc, hfont_old);
651 test_bitmap_font_metrics();
652 test_GdiGetCharDimensions();
653 test_GetCharABCWidthsW();
655 test_GetGlyphIndices();
656 test_GetKerningPairs();