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 near_match(a, b) (abs((a) - (b)) <= 4)
34 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
36 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
37 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
38 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
39 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
40 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
41 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
42 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
44 static HMODULE hgdi32 = 0;
46 static void init(void)
48 hgdi32 = GetModuleHandleA("gdi32.dll");
50 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
51 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
52 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
53 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
54 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
55 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
56 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
59 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
61 if (type != TRUETYPE_FONTTYPE) return 1;
66 static BOOL is_truetype_font_installed(const char *name)
71 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
78 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
83 static BOOL is_font_installed(const char *name)
88 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
95 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
103 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
104 /* NT4 tries to be clever and only returns the minimum length */
105 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
107 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
108 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
109 ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
110 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
111 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
114 static HFONT create_font(const char* test, const LOGFONTA* lf)
116 HFONT hfont = CreateFontIndirectA(lf);
117 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
119 check_font(test, lf, hfont);
123 static void test_logfont(void)
128 memset(&lf, 0, sizeof lf);
130 lf.lfCharSet = ANSI_CHARSET;
131 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
132 lf.lfWeight = FW_DONTCARE;
135 lf.lfQuality = DEFAULT_QUALITY;
137 lstrcpyA(lf.lfFaceName, "Arial");
138 hfont = create_font("Arial", &lf);
141 memset(&lf, 'A', sizeof(lf));
142 hfont = CreateFontIndirectA(&lf);
143 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
145 lf.lfFaceName[LF_FACESIZE - 1] = 0;
146 check_font("AAA...", &lf, hfont);
150 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
152 if (type & RASTER_FONTTYPE)
154 LOGFONT *lf = (LOGFONT *)lParam;
156 return 0; /* stop enumeration */
159 return 1; /* continue enumeration */
162 static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
164 ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
165 ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
166 ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
167 ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
168 ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
169 ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
170 ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
171 ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
172 ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
173 ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
174 ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
175 ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
176 ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
177 ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
178 ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
179 ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
180 ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
181 ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
182 ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
183 ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
186 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
187 LONG lfWidth, const char *test_str,
188 INT test_str_len, const TEXTMETRICA *tm_orig,
189 const SIZE *size_orig, INT width_of_A_orig,
190 INT scale_x, INT scale_y)
194 OUTLINETEXTMETRIC otm;
197 INT width_of_A, cx, cy;
203 GetObjectA(hfont, sizeof(lf), &lf);
205 old_hfont = SelectObject(hdc, hfont);
207 if (GetOutlineTextMetricsA(hdc, 0, NULL))
209 otm.otmSize = sizeof(otm) / 2;
210 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
211 ok(ret == sizeof(otm)/2 /* XP */ ||
212 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
214 memset(&otm, 0x1, sizeof(otm));
215 otm.otmSize = sizeof(otm);
216 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
217 ok(ret == sizeof(otm) /* XP */ ||
218 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
220 memset(&tm, 0x2, sizeof(tm));
221 ret = GetTextMetricsA(hdc, &tm);
222 ok(ret, "GetTextMetricsA failed\n");
223 /* the structure size is aligned */
224 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
226 ok(0, "tm != otm\n");
227 compare_tm(&tm, &otm.otmTextMetrics);
230 tm = otm.otmTextMetrics;
231 if (0) /* these metrics are scaled too, but with rounding errors */
233 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
234 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
236 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
237 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
238 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
239 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
240 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
241 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
245 ret = GetTextMetricsA(hdc, &tm);
246 ok(ret, "GetTextMetricsA failed\n");
249 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
250 cy = tm.tmHeight / tm_orig->tmHeight;
251 ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
252 scale_x, scale_y, cx, cy);
253 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
254 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
255 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
256 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
257 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
259 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
263 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
266 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
268 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
270 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
271 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
273 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
275 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
277 SelectObject(hdc, old_hfont);
280 /* Test how GDI scales bitmap font metrics */
281 static void test_bitmap_font(void)
283 static const char test_str[11] = "Test String";
286 HFONT hfont, old_hfont;
289 INT ret, i, width_orig, height_orig, scale, lfWidth;
293 /* "System" has only 1 pixel size defined, otherwise the test breaks */
294 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
298 trace("no bitmap fonts were found, skipping the test\n");
302 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
304 height_orig = bitmap_lf.lfHeight;
305 lfWidth = bitmap_lf.lfWidth;
307 hfont = create_font("bitmap", &bitmap_lf);
308 old_hfont = SelectObject(hdc, hfont);
309 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
310 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
311 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
312 SelectObject(hdc, old_hfont);
315 bitmap_lf.lfHeight = 0;
316 bitmap_lf.lfWidth = 4;
317 hfont = create_font("bitmap", &bitmap_lf);
318 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
321 bitmap_lf.lfHeight = height_orig;
322 bitmap_lf.lfWidth = lfWidth;
324 /* test fractional scaling */
325 for (i = 1; i <= height_orig * 3; i++)
329 bitmap_lf.lfHeight = i;
330 hfont = create_font("fractional", &bitmap_lf);
331 scale = (i + height_orig - 1) / height_orig;
332 nearest_height = scale * height_orig;
333 /* XP allows not more than 10% deviation */
334 if (scale > 1 && nearest_height - i > nearest_height / 10) scale--;
335 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
339 /* test integer scaling 3x2 */
340 bitmap_lf.lfHeight = height_orig * 2;
341 bitmap_lf.lfWidth *= 3;
342 hfont = create_font("3x2", &bitmap_lf);
343 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
346 /* test integer scaling 3x3 */
347 bitmap_lf.lfHeight = height_orig * 3;
348 bitmap_lf.lfWidth = 0;
349 hfont = create_font("3x3", &bitmap_lf);
350 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
356 /* Test how GDI scales outline font metrics */
357 static void test_outline_font(void)
359 static const char test_str[11] = "Test String";
362 HFONT hfont, old_hfont;
363 OUTLINETEXTMETRICA otm;
365 INT width_orig, height_orig, lfWidth;
368 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
369 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
373 if (!is_truetype_font_installed("Arial"))
375 skip("Arial is not installed\n");
379 hdc = CreateCompatibleDC(0);
381 memset(&lf, 0, sizeof(lf));
382 strcpy(lf.lfFaceName, "Arial");
384 hfont = create_font("outline", &lf);
385 old_hfont = SelectObject(hdc, hfont);
386 otm.otmSize = sizeof(otm);
387 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
388 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
389 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
390 SelectObject(hdc, old_hfont);
392 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
395 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
396 lf.lfHeight = otm.otmEMSquare;
397 lf.lfHeight = -lf.lfHeight;
398 hfont = create_font("outline", &lf);
399 old_hfont = SelectObject(hdc, hfont);
400 otm.otmSize = sizeof(otm);
401 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
402 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
403 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
404 SelectObject(hdc, old_hfont);
407 height_orig = otm.otmTextMetrics.tmHeight;
408 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
410 /* test integer scaling 3x2 */
411 lf.lfHeight = height_orig * 2;
412 lf.lfWidth = lfWidth * 3;
413 hfont = create_font("3x2", &lf);
414 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
417 /* test integer scaling 3x3 */
418 lf.lfHeight = height_orig * 3;
419 lf.lfWidth = lfWidth * 3;
420 hfont = create_font("3x3", &lf);
421 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
424 /* test integer scaling 1x1 */
425 lf.lfHeight = height_orig * 1;
426 lf.lfWidth = lfWidth * 1;
427 hfont = create_font("1x1", &lf);
428 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
431 /* test integer scaling 1x1 */
432 lf.lfHeight = height_orig;
434 hfont = create_font("1x1", &lf);
435 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
437 old_hfont = SelectObject(hdc, hfont);
438 /* with an identity matrix */
439 memset(&gm, 0, sizeof(gm));
440 SetLastError(0xdeadbeef);
441 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
442 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
443 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
444 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
445 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
446 /* with a custom matrix */
447 memset(&gm, 0, sizeof(gm));
448 SetLastError(0xdeadbeef);
449 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
450 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
451 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
452 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
453 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
454 SelectObject(hdc, old_hfont);
456 if (!SetGraphicsMode(hdc, GM_ADVANCED))
460 skip("GM_ADVANCED is not supported on this platform\n");
471 SetLastError(0xdeadbeef);
472 ret = SetWorldTransform(hdc, &xform);
473 ok(ret, "SetWorldTransform error %u\n", GetLastError());
475 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
477 old_hfont = SelectObject(hdc, hfont);
478 /* with an identity matrix */
479 memset(&gm, 0, sizeof(gm));
480 SetLastError(0xdeadbeef);
481 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
482 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
483 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
484 pt.x = width_orig; pt.y = 0;
486 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
487 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
488 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
489 /* with a custom matrix */
490 memset(&gm, 0, sizeof(gm));
491 SetLastError(0xdeadbeef);
492 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
493 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
495 pt.x = width_orig; pt.y = 0;
497 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
498 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
499 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
500 SelectObject(hdc, old_hfont);
502 SetLastError(0xdeadbeef);
503 ret = SetMapMode(hdc, MM_LOMETRIC);
504 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
506 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
508 old_hfont = SelectObject(hdc, hfont);
509 /* with an identity matrix */
510 memset(&gm, 0, sizeof(gm));
511 SetLastError(0xdeadbeef);
512 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
513 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
514 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
515 pt.x = width_orig; pt.y = 0;
517 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
518 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
519 /* with a custom matrix */
520 memset(&gm, 0, sizeof(gm));
521 SetLastError(0xdeadbeef);
522 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
523 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
524 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
525 pt.x = width_orig; pt.y = 0;
527 ok(gm.gmCellIncX == (pt.x + 1)/2, "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
528 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
529 SelectObject(hdc, old_hfont);
531 SetLastError(0xdeadbeef);
532 ret = SetMapMode(hdc, MM_TEXT);
533 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
535 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
537 old_hfont = SelectObject(hdc, hfont);
538 /* with an identity matrix */
539 memset(&gm, 0, sizeof(gm));
540 SetLastError(0xdeadbeef);
541 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
542 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
543 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
544 pt.x = width_orig; pt.y = 0;
546 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
547 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
548 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
549 /* with a custom matrix */
550 memset(&gm, 0, sizeof(gm));
551 SetLastError(0xdeadbeef);
552 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
553 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
554 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
555 pt.x = width_orig; pt.y = 0;
557 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
558 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
559 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
560 SelectObject(hdc, old_hfont);
566 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
568 LOGFONT *lf = (LOGFONT *)lParam;
570 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
573 return 0; /* stop enumeration */
575 return 1; /* continue enumeration */
578 static void test_bitmap_font_metrics(void)
580 static const struct font_data
582 const char face_name[LF_FACESIZE];
583 int weight, height, ascent, descent, int_leading, ext_leading;
584 int ave_char_width, max_char_width;
588 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
589 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
590 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
591 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
592 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
593 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
594 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
595 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
596 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
597 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
598 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
599 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
600 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
601 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
602 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
603 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
604 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
605 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
606 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
607 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
608 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
609 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
610 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
611 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
612 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
613 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
614 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
615 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
616 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
617 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
618 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
619 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
620 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
622 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
623 * require a new system.sfd for that font
625 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
626 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
627 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
628 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
629 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
630 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
631 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
632 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
633 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
634 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
635 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
636 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
637 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
638 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
639 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
640 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
641 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
642 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
643 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
644 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
645 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
647 /* FIXME: add "Terminal" */
651 HFONT hfont, old_hfont;
655 hdc = CreateCompatibleDC(0);
658 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
662 memset(&lf, 0, sizeof(lf));
664 lf.lfHeight = fd[i].height;
665 strcpy(lf.lfFaceName, fd[i].face_name);
667 for(bit = 0; bit < 32; bit++)
674 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
675 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
677 lf.lfCharSet = csi.ciCharset;
678 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
681 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
683 hfont = create_font(lf.lfFaceName, &lf);
684 old_hfont = SelectObject(hdc, hfont);
685 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
687 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);
688 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);
689 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);
690 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);
691 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);
692 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);
693 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);
695 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
696 that make the max width bigger */
697 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
698 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);
700 SelectObject(hdc, old_hfont);
708 static void test_GdiGetCharDimensions(void)
714 LONG avgwidth, height;
715 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
717 if (!pGdiGetCharDimensions)
719 skip("GdiGetCharDimensions not available on this platform\n");
723 hdc = CreateCompatibleDC(NULL);
725 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
726 avgwidth = ((size.cx / 26) + 1) / 2;
728 ret = pGdiGetCharDimensions(hdc, &tm, &height);
729 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
730 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
732 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
733 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
735 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
736 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
739 ret = pGdiGetCharDimensions(hdc, NULL, &height);
740 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
741 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
746 static void test_GetCharABCWidths(void)
748 static const WCHAR str[] = {'a',0};
757 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
759 skip("GetCharABCWidthsW/I not available on this platform\n");
763 memset(&lf, 0, sizeof(lf));
764 strcpy(lf.lfFaceName, "System");
767 hfont = CreateFontIndirectA(&lf);
769 hfont = SelectObject(hdc, hfont);
771 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
772 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
774 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
775 ok(!ret, "GetCharABCWidthsI should have failed\n");
777 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
778 ok(!ret, "GetCharABCWidthsI should have failed\n");
780 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
781 ok(ret, "GetCharABCWidthsI should have succeeded\n");
783 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
784 ok(!ret, "GetCharABCWidthsW should have failed\n");
786 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
787 ok(!ret, "GetCharABCWidthsW should have failed\n");
789 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
790 ok(!ret, "GetCharABCWidthsW should have failed\n");
792 hfont = SelectObject(hdc, hfont);
794 ReleaseDC(NULL, hdc);
797 static void test_text_extents(void)
799 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
801 INT i, len, fit1, fit2;
809 memset(&lf, 0, sizeof(lf));
810 strcpy(lf.lfFaceName, "Arial");
813 hfont = CreateFontIndirectA(&lf);
815 hfont = SelectObject(hdc, hfont);
816 GetTextMetricsA(hdc, &tm);
817 GetTextExtentPointA(hdc, "o", 1, &sz);
818 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
820 SetLastError(0xdeadbeef);
821 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
822 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
824 skip("Skipping remainder of text extents test on a Win9x platform\n");
825 hfont = SelectObject(hdc, hfont);
832 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
833 extents[0] = 1; /* So that the increasing sequence test will fail
834 if the extents array is untouched. */
835 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
836 GetTextExtentPointW(hdc, wt, len, &sz2);
838 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
839 /* Because of the '\n' in the string GetTextExtentExPoint and
840 GetTextExtentPoint return different widths under Win2k, but
841 under WinXP they return the same width. So we don't test that
844 for (i = 1; i < len; ++i)
845 ok(extents[i-1] <= extents[i],
846 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
848 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
849 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
850 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
851 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
852 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
853 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
854 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
855 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
856 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
857 ok(extents[0] == extents[2] && extents[1] == extents[3],
858 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
859 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
860 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
861 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
862 HeapFree(GetProcessHeap(), 0, extents);
864 hfont = SelectObject(hdc, hfont);
866 ReleaseDC(NULL, hdc);
869 static void test_GetGlyphIndices(void)
876 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
877 WORD glyphs[(sizeof(testtext)/2)-1];
881 if (!pGetGlyphIndicesW) {
882 skip("GetGlyphIndicesW not available on platform\n");
888 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
889 flags |= GGI_MARK_NONEXISTING_GLYPHS;
890 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
891 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
892 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
894 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
895 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
896 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
897 textm.tmDefaultChar, glyphs[4]);
899 if(!is_font_installed("Tahoma"))
901 skip("Tahoma is not installed so skipping this test\n");
904 memset(&lf, 0, sizeof(lf));
905 strcpy(lf.lfFaceName, "Tahoma");
908 hfont = CreateFontIndirectA(&lf);
909 hOldFont = SelectObject(hdc, hfont);
910 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
911 flags |= GGI_MARK_NONEXISTING_GLYPHS;
912 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
913 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
914 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
916 testtext[0] = textm.tmDefaultChar;
917 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
918 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
919 todo_wine ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
920 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
921 DeleteObject(SelectObject(hdc, hOldFont));
924 static void test_GetKerningPairs(void)
926 static const struct kerning_data
928 const char face_name[LF_FACESIZE];
930 /* some interesting fields from OUTLINETEXTMETRIC */
931 LONG tmHeight, tmAscent, tmDescent;
936 UINT otmsCapEmHeight;
941 UINT otmusMinimumPPEM;
942 /* small subset of kerning pairs to test */
943 DWORD total_kern_pairs;
944 const KERNINGPAIR kern_pair[26];
947 {"Arial", 12, 12, 9, 3,
948 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
951 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
952 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
953 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
954 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
955 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
956 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
957 {933,970,+1},{933,972,-1}
960 {"Arial", -34, 39, 32, 7,
961 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
964 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
965 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
966 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
967 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
968 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
969 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
970 {933,970,+2},{933,972,-3}
973 { "Arial", 120, 120, 97, 23,
974 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
977 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
978 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
979 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
980 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
981 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
982 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
983 {933,970,+6},{933,972,-10}
986 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
987 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
988 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
991 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
992 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
993 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
994 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
995 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
996 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
997 {933,970,+54},{933,972,-83}
1003 HFONT hfont, hfont_old;
1004 KERNINGPAIR *kern_pair;
1006 DWORD total_kern_pairs, ret, i, n, matches;
1010 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1011 * which may render this test unusable, so we're trying to avoid that.
1013 SetLastError(0xdeadbeef);
1014 GetKerningPairsW(hdc, 0, NULL);
1015 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1017 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1022 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1024 OUTLINETEXTMETRICW otm;
1026 if (!is_font_installed(kd[i].face_name))
1028 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1032 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1034 memset(&lf, 0, sizeof(lf));
1035 strcpy(lf.lfFaceName, kd[i].face_name);
1036 lf.lfHeight = kd[i].height;
1037 hfont = CreateFontIndirect(&lf);
1040 hfont_old = SelectObject(hdc, hfont);
1042 SetLastError(0xdeadbeef);
1043 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1044 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1046 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1047 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1048 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1049 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1050 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1051 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1053 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1054 kd[i].otmEMSquare, otm.otmEMSquare);
1055 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1056 kd[i].otmAscent, otm.otmAscent);
1057 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1058 kd[i].otmDescent, otm.otmDescent);
1059 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1060 kd[i].otmLineGap, otm.otmLineGap);
1061 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1062 kd[i].otmMacDescent, otm.otmMacDescent);
1064 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1065 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1066 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1067 kd[i].otmsXHeight, otm.otmsXHeight);
1068 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1069 kd[i].otmMacAscent, otm.otmMacAscent);
1070 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1071 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1072 kd[i].otmMacLineGap, otm.otmMacLineGap);
1073 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1074 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1077 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1078 trace("total_kern_pairs %u\n", total_kern_pairs);
1079 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1081 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1082 SetLastError(0xdeadbeef);
1083 ret = GetKerningPairsW(hdc, 0, kern_pair);
1084 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1085 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1086 ok(ret == 0, "got %lu, expected 0\n", ret);
1089 ret = GetKerningPairsW(hdc, 100, NULL);
1090 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1092 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1093 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1095 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1096 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1100 for (n = 0; n < ret; n++)
1104 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1105 trace("{'%c','%c',%d},\n",
1106 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1108 for (j = 0; j < kd[i].total_kern_pairs; j++)
1110 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1111 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1113 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1114 "pair %d:%d got %d, expected %d\n",
1115 kern_pair[n].wFirst, kern_pair[n].wSecond,
1116 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1122 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1123 matches, kd[i].total_kern_pairs);
1125 HeapFree(GetProcessHeap(), 0, kern_pair);
1127 SelectObject(hdc, hfont_old);
1128 DeleteObject(hfont);
1134 static void test_GetOutlineTextMetrics(void)
1136 OUTLINETEXTMETRIC *otm;
1138 HFONT hfont, hfont_old;
1140 DWORD ret, otm_size;
1142 if (!is_font_installed("Arial"))
1144 skip("Arial is not installed\n");
1150 memset(&lf, 0, sizeof(lf));
1151 strcpy(lf.lfFaceName, "Arial");
1153 lf.lfWeight = FW_NORMAL;
1154 lf.lfPitchAndFamily = DEFAULT_PITCH;
1155 lf.lfQuality = PROOF_QUALITY;
1156 hfont = CreateFontIndirect(&lf);
1159 hfont_old = SelectObject(hdc, hfont);
1160 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1161 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1163 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1165 memset(otm, 0xAA, otm_size);
1166 SetLastError(0xdeadbeef);
1167 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1168 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1169 ok(ret == 1 /* Win9x */ ||
1170 ret == otm->otmSize /* XP*/,
1171 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1172 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1174 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1175 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1176 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1177 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1180 memset(otm, 0xAA, otm_size);
1181 SetLastError(0xdeadbeef);
1182 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1183 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1184 ok(ret == 1 /* Win9x */ ||
1185 ret == otm->otmSize /* XP*/,
1186 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1187 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1189 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1190 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1191 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1192 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1195 /* ask about truncated data */
1196 memset(otm, 0xAA, otm_size);
1197 SetLastError(0xdeadbeef);
1198 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1199 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1200 ok(ret == 1 /* Win9x */ ||
1201 ret == otm->otmSize /* XP*/,
1202 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1203 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1205 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1206 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1207 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1209 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
1211 HeapFree(GetProcessHeap(), 0, otm);
1213 SelectObject(hdc, hfont_old);
1214 DeleteObject(hfont);
1219 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1223 outputWidth = 0, /* to test TabbedTextOut() */
1224 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1225 areaWidth = clientArea->right - clientArea->left,
1227 BOOL lastExtent = FALSE;
1228 PSTR pFirstChar, pLastChar;
1234 int GetTextExtentExPointWWidth;
1235 int TabbedTextOutWidth;
1238 GetTextMetricsA(hdc, &tm);
1239 y = clientArea->top;
1242 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1248 /* if not at the end of the string, ... */
1249 if (*str == '\0') break;
1250 /* ... add the next word to the current extent */
1251 while (*str != '\0' && *str++ != tm.tmBreakChar);
1253 SetTextJustification(hdc, 0, 0);
1254 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1255 } while ((int) size.cx < areaWidth);
1257 /* ignore trailing break chars */
1259 while (*(pLastChar - 1) == tm.tmBreakChar)
1265 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1267 SetTextJustification(hdc, 0, 0);
1268 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1270 /* do not justify the last extent */
1271 if (*str != '\0' && breakCount > 0)
1273 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1274 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1275 justifiedWidth = size.cx;
1277 else lastExtent = TRUE;
1279 x = clientArea->left;
1281 outputWidth = LOWORD(TabbedTextOut(
1282 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1284 /* catch errors and report them */
1285 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1287 memset(error[nErrors].extent, 0, 100);
1288 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1289 error[nErrors].TabbedTextOutWidth = outputWidth;
1290 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1296 } while (*str && y < clientArea->bottom);
1298 for (e = 0; e < nErrors; e++)
1300 ok(error[e].TabbedTextOutWidth == areaWidth,
1301 "The output text (\"%s\") width should be %d, not %d.\n",
1302 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1303 /* The width returned by GetTextExtentPoint32() is exactly the same
1304 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1305 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1306 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1307 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1311 static void test_SetTextJustification(void)
1318 static char testText[] =
1319 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1320 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1321 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1322 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1323 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1324 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1325 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1327 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1328 GetClientRect( hwnd, &clientArea );
1329 hdc = GetDC( hwnd );
1331 memset(&lf, 0, sizeof lf);
1332 lf.lfCharSet = ANSI_CHARSET;
1333 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1334 lf.lfWeight = FW_DONTCARE;
1336 lf.lfQuality = DEFAULT_QUALITY;
1337 lstrcpyA(lf.lfFaceName, "Times New Roman");
1338 hfont = create_font("Times New Roman", &lf);
1339 SelectObject(hdc, hfont);
1341 testJustification(hdc, testText, &clientArea);
1343 DeleteObject(hfont);
1344 ReleaseDC(hwnd, hdc);
1345 DestroyWindow(hwnd);
1348 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1352 HFONT hfont, hfont_old;
1359 assert(count <= 128);
1361 memset(&lf, 0, sizeof(lf));
1363 lf.lfCharSet = charset;
1365 lstrcpyA(lf.lfFaceName, "Arial");
1366 SetLastError(0xdeadbeef);
1367 hfont = CreateFontIndirectA(&lf);
1368 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1371 hfont_old = SelectObject(hdc, hfont);
1373 cs = GetTextCharsetInfo(hdc, &fs, 0);
1374 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1376 SetLastError(0xdeadbeef);
1377 ret = GetTextFaceA(hdc, sizeof(name), name);
1378 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1380 if (charset == SYMBOL_CHARSET)
1382 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1383 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1387 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1388 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1391 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1393 trace("Can't find codepage for charset %d\n", cs);
1397 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1402 WCHAR unicode_buf[128];
1404 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1406 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1408 SetLastError(0xdeadbeef);
1409 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1410 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1416 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1418 SetLastError(0xdeadbeef);
1419 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1420 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1423 SelectObject(hdc, hfont_old);
1424 DeleteObject(hfont);
1431 static void test_font_charset(void)
1433 static struct charset_data
1437 WORD font_idxA[128], font_idxW[128];
1440 { ANSI_CHARSET, 1252 },
1441 { RUSSIAN_CHARSET, 1251 },
1442 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1446 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1448 skip("Skipping the font charset test on a Win9x platform\n");
1452 if (!is_font_installed("Arial"))
1454 skip("Arial is not installed\n");
1458 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1460 if (cd[i].charset == SYMBOL_CHARSET)
1462 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1464 skip("Symbol or Wingdings is not installed\n");
1468 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1469 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1470 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1473 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1476 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1477 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1480 skip("Symbol or Wingdings is not installed\n");
1483 static void test_GetFontUnicodeRanges(void)
1487 HFONT hfont, hfont_old;
1491 if (!pGetFontUnicodeRanges)
1493 skip("GetFontUnicodeRanges not available before W2K\n");
1497 memset(&lf, 0, sizeof(lf));
1498 lstrcpyA(lf.lfFaceName, "Arial");
1499 hfont = create_font("Arial", &lf);
1502 hfont_old = SelectObject(hdc, hfont);
1504 size = pGetFontUnicodeRanges(NULL, NULL);
1505 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1507 size = pGetFontUnicodeRanges(hdc, NULL);
1508 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1510 gs = HeapAlloc(GetProcessHeap(), 0, size);
1512 size = pGetFontUnicodeRanges(hdc, gs);
1513 ok(size, "GetFontUnicodeRanges failed\n");
1515 for (i = 0; i < gs->cRanges; i++)
1516 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1518 trace("found %u ranges\n", gs->cRanges);
1520 HeapFree(GetProcessHeap(), 0, gs);
1522 SelectObject(hdc, hfont_old);
1523 DeleteObject(hfont);
1524 ReleaseDC(NULL, hdc);
1527 #define MAX_ENUM_FONTS 256
1529 struct enum_font_data
1532 LOGFONT lf[MAX_ENUM_FONTS];
1535 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1537 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1539 if (type != TRUETYPE_FONTTYPE) return 1;
1541 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1542 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1544 if (efd->total < MAX_ENUM_FONTS)
1545 efd->lf[efd->total++] = *lf;
1550 static void get_charset_stats(struct enum_font_data *efd,
1551 int *ansi_charset, int *symbol_charset,
1552 int *russian_charset)
1557 *symbol_charset = 0;
1558 *russian_charset = 0;
1560 for (i = 0; i < efd->total; i++)
1562 switch (efd->lf[i].lfCharSet)
1567 case SYMBOL_CHARSET:
1568 (*symbol_charset)++;
1570 case RUSSIAN_CHARSET:
1571 (*russian_charset)++;
1577 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1579 struct enum_font_data efd;
1582 int i, ret, ansi_charset, symbol_charset, russian_charset;
1584 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1586 if (*font_name && !is_truetype_font_installed(font_name))
1588 skip("%s is not installed\n", font_name);
1594 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1595 * while EnumFontFamiliesEx doesn't.
1597 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1600 SetLastError(0xdeadbeef);
1601 ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1602 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1603 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1604 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1605 ansi_charset, symbol_charset, russian_charset);
1606 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1607 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1608 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1609 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1612 SetLastError(0xdeadbeef);
1613 ret = EnumFontFamiliesEx(hdc, NULL, arial_enum_proc, (LPARAM)&efd, 0);
1614 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1615 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1616 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1617 ansi_charset, symbol_charset, russian_charset);
1618 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1619 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1620 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1621 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1625 SetLastError(0xdeadbeef);
1626 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1627 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1628 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1629 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1630 ansi_charset, symbol_charset, russian_charset,
1631 *font_name ? font_name : "<empty>");
1633 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1635 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1636 for (i = 0; i < efd.total; i++)
1638 /* FIXME: remove completely once Wine is fixed */
1639 if (efd.lf[i].lfCharSet != font_charset)
1642 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1645 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1646 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1647 font_name, efd.lf[i].lfFaceName);
1650 memset(&lf, 0, sizeof(lf));
1651 lf.lfCharSet = ANSI_CHARSET;
1652 lstrcpy(lf.lfFaceName, font_name);
1654 SetLastError(0xdeadbeef);
1655 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1656 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1657 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1658 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1659 ansi_charset, symbol_charset, russian_charset,
1660 *font_name ? font_name : "<empty>");
1661 if (font_charset == SYMBOL_CHARSET)
1664 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1666 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1670 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1671 for (i = 0; i < efd.total; i++)
1673 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1675 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1676 font_name, efd.lf[i].lfFaceName);
1680 /* DEFAULT_CHARSET should enumerate all available charsets */
1681 memset(&lf, 0, sizeof(lf));
1682 lf.lfCharSet = DEFAULT_CHARSET;
1683 lstrcpy(lf.lfFaceName, font_name);
1685 SetLastError(0xdeadbeef);
1686 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1687 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1688 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1689 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1690 ansi_charset, symbol_charset, russian_charset,
1691 *font_name ? font_name : "<empty>");
1692 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1693 for (i = 0; i < efd.total; i++)
1696 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1697 font_name, efd.lf[i].lfFaceName);
1701 switch (font_charset)
1704 ok(ansi_charset > 0,
1705 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1707 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1708 ok(russian_charset > 0,
1709 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1711 case SYMBOL_CHARSET:
1713 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1715 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1716 ok(!russian_charset,
1717 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1719 case DEFAULT_CHARSET:
1720 ok(ansi_charset > 0,
1721 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1722 ok(symbol_charset > 0,
1723 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1724 ok(russian_charset > 0,
1725 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1731 ok(ansi_charset > 0,
1732 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1733 ok(symbol_charset > 0,
1734 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1735 ok(russian_charset > 0,
1736 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1739 memset(&lf, 0, sizeof(lf));
1740 lf.lfCharSet = SYMBOL_CHARSET;
1741 lstrcpy(lf.lfFaceName, font_name);
1743 SetLastError(0xdeadbeef);
1744 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1745 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1746 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1747 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1748 ansi_charset, symbol_charset, russian_charset,
1749 *font_name ? font_name : "<empty>");
1750 if (*font_name && font_charset == ANSI_CHARSET)
1751 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1754 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1755 for (i = 0; i < efd.total; i++)
1757 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1759 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1760 font_name, efd.lf[i].lfFaceName);
1764 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1765 ok(symbol_charset > 0,
1766 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1767 ok(!russian_charset,
1768 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1774 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1776 HFONT hfont, hfont_prev;
1778 GLYPHMETRICS gm1, gm2;
1781 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1783 /* negative widths are handled just as positive ones */
1784 lf2.lfWidth = -lf->lfWidth;
1786 SetLastError(0xdeadbeef);
1787 hfont = CreateFontIndirectA(lf);
1788 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1789 check_font("original", lf, hfont);
1791 hfont_prev = SelectObject(hdc, hfont);
1793 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1794 if (ret == GDI_ERROR || idx == 0xffff)
1796 SelectObject(hdc, hfont_prev);
1797 DeleteObject(hfont);
1798 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1802 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1803 memset(&gm1, 0xab, sizeof(gm1));
1804 SetLastError(0xdeadbeef);
1805 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1806 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1808 SelectObject(hdc, hfont_prev);
1809 DeleteObject(hfont);
1811 SetLastError(0xdeadbeef);
1812 hfont = CreateFontIndirectA(&lf2);
1813 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1814 check_font("negative width", &lf2, hfont);
1816 hfont_prev = SelectObject(hdc, hfont);
1818 memset(&gm2, 0xbb, sizeof(gm2));
1819 SetLastError(0xdeadbeef);
1820 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1821 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1823 SelectObject(hdc, hfont_prev);
1824 DeleteObject(hfont);
1826 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1827 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1828 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1829 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1830 gm1.gmCellIncX == gm2.gmCellIncX &&
1831 gm1.gmCellIncY == gm2.gmCellIncY,
1832 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1833 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1834 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1835 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1836 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1839 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1840 #include "pshpack2.h"
1844 SHORT xAvgCharWidth;
1845 USHORT usWeightClass;
1846 USHORT usWidthClass;
1848 SHORT ySubscriptXSize;
1849 SHORT ySubscriptYSize;
1850 SHORT ySubscriptXOffset;
1851 SHORT ySubscriptYOffset;
1852 SHORT ySuperscriptXSize;
1853 SHORT ySuperscriptYSize;
1854 SHORT ySuperscriptXOffset;
1855 SHORT ySuperscriptYOffset;
1856 SHORT yStrikeoutSize;
1857 SHORT yStrikeoutPosition;
1860 ULONG ulUnicodeRange1;
1861 ULONG ulUnicodeRange2;
1862 ULONG ulUnicodeRange3;
1863 ULONG ulUnicodeRange4;
1866 USHORT usFirstCharIndex;
1867 USHORT usLastCharIndex;
1868 /* According to the Apple spec, original version didn't have the below fields,
1869 * version numbers were taked from the OpenType spec.
1871 /* version 0 (TrueType 1.5) */
1872 USHORT sTypoAscender;
1873 USHORT sTypoDescender;
1874 USHORT sTypoLineGap;
1876 USHORT usWinDescent;
1877 /* version 1 (TrueType 1.66) */
1878 ULONG ulCodePageRange1;
1879 ULONG ulCodePageRange2;
1880 /* version 2 (OpenType 1.2) */
1883 USHORT usDefaultChar;
1885 USHORT usMaxContext;
1887 #include "poppack.h"
1889 #ifdef WORDS_BIGENDIAN
1890 #define GET_BE_WORD(x) (x)
1892 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1895 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1896 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1897 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1898 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1900 static void test_text_metrics(const LOGFONTA *lf)
1903 HFONT hfont, hfont_old;
1906 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1911 const char *font_name = lf->lfFaceName;
1915 SetLastError(0xdeadbeef);
1916 hfont = CreateFontIndirectA(lf);
1917 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1919 hfont_old = SelectObject(hdc, hfont);
1921 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1922 if (size == GDI_ERROR)
1924 trace("OS/2 chunk was not found\n");
1927 if (size > sizeof(tt_os2))
1929 trace("got too large OS/2 chunk of size %u\n", size);
1930 size = sizeof(tt_os2);
1933 memset(&tt_os2, 0, sizeof(tt_os2));
1934 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1935 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1937 version = GET_BE_WORD(tt_os2.version);
1939 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
1940 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
1941 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
1942 break_char = GET_BE_WORD(tt_os2.usBreakChar);
1944 trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
1945 font_name, lf->lfCharSet, first_unicode_char, last_unicode_char, default_char, break_char,
1946 version, (LPCSTR)&tt_os2.achVendID);
1948 SetLastError(0xdeadbeef);
1949 ret = GetTextMetricsA(hdc, &tmA);
1950 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
1952 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1953 test_char = min(first_unicode_char - 1, 255);
1954 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
1955 font_name, tmA.tmFirstChar, test_char);
1957 if (lf->lfCharSet == SYMBOL_CHARSET)
1959 test_char = min(last_unicode_char - 0xf000, 255);
1960 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1961 font_name, tmA.tmLastChar, test_char);
1965 test_char = min(last_unicode_char, 255);
1966 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1967 font_name, tmA.tmLastChar, test_char);
1970 SetLastError(0xdeadbeef);
1971 ret = GetTextMetricsW(hdc, &tmW);
1972 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
1973 "GetTextMetricsW error %u\n", GetLastError());
1976 trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
1977 tmW.tmFirstChar, tmW.tmLastChar, tmA.tmFirstChar, tmA.tmLastChar,
1978 tmW.tmDefaultChar, tmA.tmDefaultChar, tmW.tmBreakChar, tmA.tmBreakChar);
1980 if (lf->lfCharSet == SYMBOL_CHARSET)
1982 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1983 * sets symbol range to 0 - f0ff
1985 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
1986 font_name, tmW.tmFirstChar);
1987 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1988 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1989 font_name, tmW.tmLastChar);
1991 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1992 font_name, tmW.tmDefaultChar);
1993 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1994 font_name, tmW.tmBreakChar);
1998 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
1999 font_name, tmW.tmFirstChar, first_unicode_char);
2000 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
2001 font_name, tmW.tmLastChar, last_unicode_char);
2003 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2004 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2005 tmW.tmDigitizedAspectX, ret);
2006 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2007 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2008 tmW.tmDigitizedAspectX, ret);
2011 test_negative_width(hdc, lf);
2014 SelectObject(hdc, hfont_old);
2015 DeleteObject(hfont);
2020 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2022 INT *enumed = (INT *)lParam;
2024 if (type == TRUETYPE_FONTTYPE)
2027 test_text_metrics(lf);
2032 static void test_GetTextMetrics(void)
2040 memset(&lf, 0, sizeof(lf));
2041 lf.lfCharSet = DEFAULT_CHARSET;
2043 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2044 trace("Tested metrics of %d truetype fonts\n", enumed);
2049 static void test_nonexistent_font(void)
2057 { "Times New Roman Baltic", 186 },
2058 { "Times New Roman CE", 238 },
2059 { "Times New Roman CYR", 204 },
2060 { "Times New Roman Greek", 161 },
2061 { "Times New Roman TUR", 162 }
2067 INT cs, expected_cs, i;
2068 char buf[LF_FACESIZE];
2070 if (!is_truetype_font_installed("Arial") ||
2071 !is_truetype_font_installed("Times New Roman"))
2073 skip("Arial or Times New Roman not installed\n");
2077 expected_cs = GetACP();
2078 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2080 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2083 expected_cs = csi.ciCharset;
2084 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2088 memset(&lf, 0, sizeof(lf));
2090 lf.lfWeight = FW_REGULAR;
2091 lf.lfCharSet = ANSI_CHARSET;
2092 lf.lfPitchAndFamily = FF_SWISS;
2093 strcpy(lf.lfFaceName, "Nonexistent font");
2094 hfont = CreateFontIndirectA(&lf);
2095 hfont = SelectObject(hdc, hfont);
2096 GetTextFaceA(hdc, sizeof(buf), buf);
2097 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2098 cs = GetTextCharset(hdc);
2099 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2100 DeleteObject(SelectObject(hdc, hfont));
2102 memset(&lf, 0, sizeof(lf));
2104 lf.lfWeight = FW_DONTCARE;
2105 strcpy(lf.lfFaceName, "Nonexistent font");
2106 hfont = CreateFontIndirectA(&lf);
2107 hfont = SelectObject(hdc, hfont);
2108 GetTextFaceA(hdc, sizeof(buf), buf);
2109 todo_wine /* Wine uses Arial for all substitutions */
2110 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2111 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2112 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2114 cs = GetTextCharset(hdc);
2115 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2116 DeleteObject(SelectObject(hdc, hfont));
2118 memset(&lf, 0, sizeof(lf));
2120 lf.lfWeight = FW_REGULAR;
2121 strcpy(lf.lfFaceName, "Nonexistent font");
2122 hfont = CreateFontIndirectA(&lf);
2123 hfont = SelectObject(hdc, hfont);
2124 GetTextFaceA(hdc, sizeof(buf), buf);
2125 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2126 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2127 cs = GetTextCharset(hdc);
2128 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2129 DeleteObject(SelectObject(hdc, hfont));
2131 memset(&lf, 0, sizeof(lf));
2133 lf.lfWeight = FW_DONTCARE;
2134 strcpy(lf.lfFaceName, "Times New Roman");
2135 hfont = CreateFontIndirectA(&lf);
2136 hfont = SelectObject(hdc, hfont);
2137 GetTextFaceA(hdc, sizeof(buf), buf);
2138 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2139 cs = GetTextCharset(hdc);
2140 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2141 DeleteObject(SelectObject(hdc, hfont));
2143 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2145 memset(&lf, 0, sizeof(lf));
2147 lf.lfWeight = FW_REGULAR;
2148 strcpy(lf.lfFaceName, font_subst[i].name);
2149 hfont = CreateFontIndirectA(&lf);
2150 hfont = SelectObject(hdc, hfont);
2151 cs = GetTextCharset(hdc);
2152 if (font_subst[i].charset == expected_cs)
2154 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2155 GetTextFaceA(hdc, sizeof(buf), buf);
2156 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2160 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2161 GetTextFaceA(hdc, sizeof(buf), buf);
2162 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2163 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2165 DeleteObject(SelectObject(hdc, hfont));
2167 memset(&lf, 0, sizeof(lf));
2169 lf.lfWeight = FW_DONTCARE;
2170 strcpy(lf.lfFaceName, font_subst[i].name);
2171 hfont = CreateFontIndirectA(&lf);
2172 hfont = SelectObject(hdc, hfont);
2173 GetTextFaceA(hdc, sizeof(buf), buf);
2174 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2175 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2176 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2177 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2179 cs = GetTextCharset(hdc);
2180 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2181 DeleteObject(SelectObject(hdc, hfont));
2187 static void test_GdiRealizationInfo(void)
2192 HFONT hfont, hfont_old;
2195 if(!pGdiRealizationInfo)
2197 skip("GdiRealizationInfo not available\n");
2203 memset(info, 0xcc, sizeof(info));
2204 r = pGdiRealizationInfo(hdc, info);
2205 ok(r != 0, "ret 0\n");
2206 ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
2207 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2209 if (!is_truetype_font_installed("Arial"))
2211 skip("skipping GdiRealizationInfo with truetype font\n");
2215 memset(&lf, 0, sizeof(lf));
2216 strcpy(lf.lfFaceName, "Arial");
2218 lf.lfWeight = FW_NORMAL;
2219 hfont = CreateFontIndirectA(&lf);
2220 hfont_old = SelectObject(hdc, hfont);
2222 memset(info, 0xcc, sizeof(info));
2223 r = pGdiRealizationInfo(hdc, info);
2224 ok(r != 0, "ret 0\n");
2225 ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
2226 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2228 DeleteObject(SelectObject(hdc, hfont_old));
2234 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2235 the nul in the count of characters copied when the face name buffer is not
2236 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2237 always includes it. */
2238 static void test_GetTextFace(void)
2240 static const char faceA[] = "Tahoma";
2241 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2244 char bufA[LF_FACESIZE];
2245 WCHAR bufW[LF_FACESIZE];
2251 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2252 f = CreateFontIndirectA(&fA);
2253 ok(f != NULL, "CreateFontIndirectA failed\n");
2256 g = SelectObject(dc, f);
2257 n = GetTextFaceA(dc, sizeof bufA, bufA);
2258 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2259 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2261 /* Play with the count arg. */
2263 n = GetTextFaceA(dc, 0, bufA);
2265 ok(n == 0, "GetTextFaceA returned %d\n", n);
2266 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2269 n = GetTextFaceA(dc, 1, bufA);
2270 ok(n == 0, "GetTextFaceA returned %d\n", n);
2271 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2273 bufA[0] = 'x'; bufA[1] = 'y';
2274 n = GetTextFaceA(dc, 2, bufA);
2275 ok(n == 1, "GetTextFaceA returned %d\n", n);
2276 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2278 n = GetTextFaceA(dc, 0, NULL);
2279 ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
2281 DeleteObject(SelectObject(dc, g));
2282 ReleaseDC(NULL, dc);
2285 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2286 f = CreateFontIndirectW(&fW);
2287 ok(f != NULL, "CreateFontIndirectW failed\n");
2290 g = SelectObject(dc, f);
2291 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2293 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2294 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2296 /* Play with the count arg. */
2298 n = GetTextFaceW(dc, 0, bufW);
2300 ok(n == 0, "GetTextFaceW returned %d\n", n);
2301 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2304 n = GetTextFaceW(dc, 1, bufW);
2306 ok(n == 1, "GetTextFaceW returned %d\n", n);
2307 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2309 bufW[0] = 'x'; bufW[1] = 'y';
2310 n = GetTextFaceW(dc, 2, bufW);
2312 ok(n == 2, "GetTextFaceW returned %d\n", n);
2313 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2315 n = GetTextFaceW(dc, 0, NULL);
2316 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2318 DeleteObject(SelectObject(dc, g));
2319 ReleaseDC(NULL, dc);
2328 test_outline_font();
2329 test_bitmap_font_metrics();
2330 test_GdiGetCharDimensions();
2331 test_GetCharABCWidths();
2332 test_text_extents();
2333 test_GetGlyphIndices();
2334 test_GetKerningPairs();
2335 test_GetOutlineTextMetrics();
2336 test_SetTextJustification();
2337 test_font_charset();
2338 test_GetFontUnicodeRanges();
2339 test_nonexistent_font();
2341 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2342 * I'd like to avoid them in this test.
2344 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2345 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2346 if (is_truetype_font_installed("Arial Black") &&
2347 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2349 test_EnumFontFamilies("", ANSI_CHARSET);
2350 test_EnumFontFamilies("", SYMBOL_CHARSET);
2351 test_EnumFontFamilies("", DEFAULT_CHARSET);
2354 skip("Arial Black or Symbol/Wingdings is not installed\n");
2355 test_GetTextMetrics();
2356 test_GdiRealizationInfo();