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 hfont = 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 hfont = 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 /* some interesting fields from OUTLINETEXTMETRIC */
532 LONG tmHeight, tmAscent, tmDescent;
537 UINT otmsCapEmHeight;
542 UINT otmusMinimumPPEM;
543 /* small subset of kerning pairs to test */
544 DWORD total_kern_pairs;
545 const KERNINGPAIR kern_pair[26];
548 {"Arial", 12, 12, 9, 3,
549 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
552 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
553 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
554 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
555 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
556 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
557 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
558 {933,970,+1},{933,972,-1}
561 {"Arial", -34, 39, 32, 7,
562 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
565 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
566 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
567 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
568 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
569 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
570 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
571 {933,970,+2},{933,972,-3}
574 { "Arial", 120, 120, 97, 23,
575 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
578 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
579 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
580 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
581 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
582 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
583 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
584 {933,970,+6},{933,972,-10}
587 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
588 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
589 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
592 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
593 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
594 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
595 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
596 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
597 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
598 {933,970,+54},{933,972,-83}
604 HFONT hfont, hfont_old;
605 KERNINGPAIR *kern_pair;
607 DWORD total_kern_pairs, ret, i, n, matches;
611 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
612 * which may render this test unusable, so we're trying to avoid that.
614 SetLastError(0xdeadbeef);
615 GetKerningPairsW(hdc, 0, NULL);
616 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
618 trace("Skipping the GetKerningPairs test on a Win9x platform\n");
623 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
625 OUTLINETEXTMETRICW otm;
627 if (!is_font_installed(kd[i].face_name))
629 trace("%s is not installed so skipping this test\n", kd[i].face_name);
633 trace("testing font %s, height %ld\n", kd[i].face_name, kd[i].height);
635 memset(&lf, 0, sizeof(lf));
636 strcpy(lf.lfFaceName, kd[i].face_name);
637 lf.lfHeight = kd[i].height;
638 hfont = CreateFontIndirect(&lf);
641 hfont_old = SelectObject(hdc, hfont);
643 SetLastError(0xdeadbeef);
644 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
645 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %ld\n", GetLastError());
647 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %ld, got %ld\n",
648 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
649 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %ld, got %ld\n",
650 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
651 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %ld, got %ld\n",
652 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
654 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
655 kd[i].otmEMSquare, otm.otmEMSquare);
656 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
657 kd[i].otmAscent, otm.otmAscent);
658 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
659 kd[i].otmDescent, otm.otmDescent);
660 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
661 kd[i].otmLineGap, otm.otmLineGap);
663 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
664 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
665 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
666 kd[i].otmsXHeight, otm.otmsXHeight);
667 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
668 kd[i].otmMacAscent, otm.otmMacAscent);
669 ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
670 kd[i].otmMacDescent, otm.otmMacDescent);
671 #if 0 /* this one succeeds due to expected 0, enable it when removing todo */
672 ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
673 kd[i].otmMacLineGap, otm.otmMacLineGap);
675 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
676 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
679 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
680 trace("total_kern_pairs %lu\n", total_kern_pairs);
681 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
683 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
684 SetLastError(0xdeadbeef);
685 ret = GetKerningPairsW(hdc, 0, kern_pair);
686 ok(GetLastError() == ERROR_INVALID_PARAMETER,
687 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
688 ok(ret == 0, "got %lu, expected 0\n", ret);
691 ret = GetKerningPairsW(hdc, 100, NULL);
692 ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
694 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
695 ok(ret == total_kern_pairs/2, "got %lu, expected %lu\n", ret, total_kern_pairs/2);
697 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
698 ok(ret == total_kern_pairs, "got %lu, expected %lu\n", ret, total_kern_pairs);
702 for (n = 0; n < ret; n++)
706 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
707 trace("{'%c','%c',%d},\n",
708 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
710 for (j = 0; j < kd[i].total_kern_pairs; j++)
712 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
713 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
715 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
716 "pair %d:%d got %d, expected %d\n",
717 kern_pair[n].wFirst, kern_pair[n].wSecond,
718 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
724 ok(matches == kd[i].total_kern_pairs, "got matches %lu, expected %lu\n",
725 matches, kd[i].total_kern_pairs);
727 HeapFree(GetProcessHeap(), 0, kern_pair);
729 SelectObject(hdc, hfont_old);
740 test_bitmap_font_metrics();
741 test_GdiGetCharDimensions();
742 test_GetCharABCWidthsW();
744 test_GetGlyphIndices();
745 test_GetKerningPairs();