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)) <= 6)
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)
193 OUTLINETEXTMETRIC otm;
196 INT width_of_A, cx, cy;
202 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
204 GetObjectA(hfont, sizeof(lf), &lf);
206 if (GetOutlineTextMetricsA(hdc, 0, NULL))
208 otm.otmSize = sizeof(otm) / 2;
209 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
210 ok(ret == sizeof(otm)/2 /* XP */ ||
211 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
213 memset(&otm, 0x1, sizeof(otm));
214 otm.otmSize = sizeof(otm);
215 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
216 ok(ret == sizeof(otm) /* XP */ ||
217 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
219 memset(&tm, 0x2, sizeof(tm));
220 ret = GetTextMetricsA(hdc, &tm);
221 ok(ret, "GetTextMetricsA failed\n");
222 /* the structure size is aligned */
223 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
225 ok(0, "tm != otm\n");
226 compare_tm(&tm, &otm.otmTextMetrics);
229 tm = otm.otmTextMetrics;
230 if (0) /* these metrics are scaled too, but with rounding errors */
232 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
233 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
235 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
236 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
237 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
238 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
239 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
240 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
244 ret = GetTextMetricsA(hdc, &tm);
245 ok(ret, "GetTextMetricsA failed\n");
248 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
249 cy = tm.tmHeight / tm_orig->tmHeight;
250 ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
251 scale_x, scale_y, cx, cy);
252 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
253 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
254 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
255 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
256 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
258 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
262 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
265 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
267 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
269 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
270 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
272 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
274 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 /* Test how GDI scales bitmap font metrics */
278 static void test_bitmap_font(void)
280 static const char test_str[11] = "Test String";
283 HFONT hfont, old_hfont;
286 INT ret, i, width_orig, height_orig, scale, lfWidth;
290 /* "System" has only 1 pixel size defined, otherwise the test breaks */
291 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
295 trace("no bitmap fonts were found, skipping the test\n");
299 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
301 height_orig = bitmap_lf.lfHeight;
302 lfWidth = bitmap_lf.lfWidth;
304 hfont = create_font("bitmap", &bitmap_lf);
305 old_hfont = SelectObject(hdc, hfont);
306 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
307 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
308 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
309 SelectObject(hdc, old_hfont);
312 bitmap_lf.lfHeight = 0;
313 bitmap_lf.lfWidth = 4;
314 hfont = create_font("bitmap", &bitmap_lf);
315 old_hfont = SelectObject(hdc, hfont);
316 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
317 SelectObject(hdc, old_hfont);
320 bitmap_lf.lfHeight = height_orig;
321 bitmap_lf.lfWidth = lfWidth;
323 /* test fractional scaling */
324 for (i = 1; i <= height_orig * 3; i++)
328 bitmap_lf.lfHeight = i;
329 hfont = create_font("fractional", &bitmap_lf);
330 scale = (i + height_orig - 1) / height_orig;
331 nearest_height = scale * height_orig;
332 /* XP allows not more than 10% deviation */
333 if (scale > 1 && nearest_height - i > nearest_height / 10) scale--;
334 old_hfont = SelectObject(hdc, hfont);
335 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
336 SelectObject(hdc, old_hfont);
340 /* test integer scaling 3x2 */
341 bitmap_lf.lfHeight = height_orig * 2;
342 bitmap_lf.lfWidth *= 3;
343 hfont = create_font("3x2", &bitmap_lf);
344 old_hfont = SelectObject(hdc, hfont);
345 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
346 SelectObject(hdc, old_hfont);
349 /* test integer scaling 3x3 */
350 bitmap_lf.lfHeight = height_orig * 3;
351 bitmap_lf.lfWidth = 0;
352 hfont = create_font("3x3", &bitmap_lf);
353 old_hfont = SelectObject(hdc, hfont);
354 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
355 SelectObject(hdc, old_hfont);
361 /* Test how GDI scales outline font metrics */
362 static void test_outline_font(void)
364 static const char test_str[11] = "Test String";
367 HFONT hfont, old_hfont;
368 OUTLINETEXTMETRICA otm;
370 INT width_orig, height_orig, lfWidth;
373 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
374 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
378 if (!is_truetype_font_installed("Arial"))
380 skip("Arial is not installed\n");
384 hdc = CreateCompatibleDC(0);
386 memset(&lf, 0, sizeof(lf));
387 strcpy(lf.lfFaceName, "Arial");
389 hfont = create_font("outline", &lf);
390 old_hfont = SelectObject(hdc, hfont);
391 otm.otmSize = sizeof(otm);
392 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
393 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
394 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
396 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
397 SelectObject(hdc, old_hfont);
400 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
401 lf.lfHeight = otm.otmEMSquare;
402 lf.lfHeight = -lf.lfHeight;
403 hfont = create_font("outline", &lf);
404 old_hfont = SelectObject(hdc, hfont);
405 otm.otmSize = sizeof(otm);
406 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
407 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
408 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
409 SelectObject(hdc, old_hfont);
412 height_orig = otm.otmTextMetrics.tmHeight;
413 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
415 /* test integer scaling 3x2 */
416 lf.lfHeight = height_orig * 2;
417 lf.lfWidth = lfWidth * 3;
418 hfont = create_font("3x2", &lf);
419 old_hfont = SelectObject(hdc, hfont);
420 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
421 SelectObject(hdc, old_hfont);
424 /* test integer scaling 3x3 */
425 lf.lfHeight = height_orig * 3;
426 lf.lfWidth = lfWidth * 3;
427 hfont = create_font("3x3", &lf);
428 old_hfont = SelectObject(hdc, hfont);
429 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
430 SelectObject(hdc, old_hfont);
433 /* test integer scaling 1x1 */
434 lf.lfHeight = height_orig * 1;
435 lf.lfWidth = lfWidth * 1;
436 hfont = create_font("1x1", &lf);
437 old_hfont = SelectObject(hdc, hfont);
438 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
439 SelectObject(hdc, old_hfont);
442 /* test integer scaling 1x1 */
443 lf.lfHeight = height_orig;
445 hfont = create_font("1x1", &lf);
446 old_hfont = SelectObject(hdc, hfont);
447 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
449 /* with an identity matrix */
450 memset(&gm, 0, sizeof(gm));
451 SetLastError(0xdeadbeef);
452 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
453 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
454 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
455 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
456 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
457 /* with a custom matrix */
458 memset(&gm, 0, sizeof(gm));
459 SetLastError(0xdeadbeef);
460 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
461 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
462 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
463 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
464 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
466 SetMapMode(hdc, MM_ANISOTROPIC);
467 /* test restrictions of compatibility mode GM_COMPATIBLE */
468 /* part 1: rescaling only X should not change font scaling on screen.
469 So compressing the X axis by 2 is not done, and this
470 appears as X scaling of 2 that no one requested. */
471 SetWindowExtEx(hdc, 100, 100, NULL);
472 SetViewportExtEx(hdc, 50, 100, NULL);
473 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
475 /* part 2: rescaling only Y should change font scaling.
476 As also X is scaled by a factor of 2, but this is not
477 requested by the DC transformation, we get a scaling factor
478 of 2 in the X coordinate. */
479 SetViewportExtEx(hdc, 100, 200, NULL);
480 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
482 /* restore scaling */
483 SetMapMode(hdc, MM_TEXT);
485 if (!SetGraphicsMode(hdc, GM_ADVANCED))
487 SelectObject(hdc, old_hfont);
490 skip("GM_ADVANCED is not supported on this platform\n");
501 SetLastError(0xdeadbeef);
502 ret = SetWorldTransform(hdc, &xform);
503 ok(ret, "SetWorldTransform error %u\n", GetLastError());
505 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
507 /* with an identity matrix */
508 memset(&gm, 0, sizeof(gm));
509 SetLastError(0xdeadbeef);
510 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
511 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
512 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
513 pt.x = width_orig; pt.y = 0;
515 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
516 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
517 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
518 /* with a custom matrix */
519 memset(&gm, 0, sizeof(gm));
520 SetLastError(0xdeadbeef);
521 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
522 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
523 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
524 pt.x = width_orig; pt.y = 0;
526 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
527 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
528 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
530 SetLastError(0xdeadbeef);
531 ret = SetMapMode(hdc, MM_LOMETRIC);
532 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
534 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
536 /* with an identity matrix */
537 memset(&gm, 0, sizeof(gm));
538 SetLastError(0xdeadbeef);
539 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
540 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
541 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
542 pt.x = width_orig; pt.y = 0;
544 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
545 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
546 /* with a custom matrix */
547 memset(&gm, 0, sizeof(gm));
548 SetLastError(0xdeadbeef);
549 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
550 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
551 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
552 pt.x = width_orig; pt.y = 0;
554 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
555 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
557 SetLastError(0xdeadbeef);
558 ret = SetMapMode(hdc, MM_TEXT);
559 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
561 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
563 /* with an identity matrix */
564 memset(&gm, 0, sizeof(gm));
565 SetLastError(0xdeadbeef);
566 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
567 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
568 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
569 pt.x = width_orig; pt.y = 0;
571 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
572 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
573 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
574 /* with a custom matrix */
575 memset(&gm, 0, sizeof(gm));
576 SetLastError(0xdeadbeef);
577 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
578 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
580 pt.x = width_orig; pt.y = 0;
582 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
583 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
584 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
586 SelectObject(hdc, old_hfont);
591 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
593 LOGFONT *lf = (LOGFONT *)lParam;
595 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
598 return 0; /* stop enumeration */
600 return 1; /* continue enumeration */
603 static void test_bitmap_font_metrics(void)
605 static const struct font_data
607 const char face_name[LF_FACESIZE];
608 int weight, height, ascent, descent, int_leading, ext_leading;
609 int ave_char_width, max_char_width;
613 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
614 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
615 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
616 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
617 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
618 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
619 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
620 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
621 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
622 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
623 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
624 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
625 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
626 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
627 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
628 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
629 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
630 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
631 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
632 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
633 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
634 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
635 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
636 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
637 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
638 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
639 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
640 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
641 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
642 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
643 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
644 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
645 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
647 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
648 * require a new system.sfd for that font
650 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
651 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
652 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
653 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
654 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
655 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
656 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
657 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
658 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
659 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
660 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
661 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
662 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
663 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
664 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
665 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
666 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
667 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
668 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
669 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
670 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
672 /* FIXME: add "Terminal" */
676 HFONT hfont, old_hfont;
680 hdc = CreateCompatibleDC(0);
683 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
687 memset(&lf, 0, sizeof(lf));
689 lf.lfHeight = fd[i].height;
690 strcpy(lf.lfFaceName, fd[i].face_name);
692 for(bit = 0; bit < 32; bit++)
699 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
700 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
702 lf.lfCharSet = csi.ciCharset;
703 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
706 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
708 hfont = create_font(lf.lfFaceName, &lf);
709 old_hfont = SelectObject(hdc, hfont);
710 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
712 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);
713 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);
714 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);
715 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);
716 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);
717 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);
718 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);
720 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
721 that make the max width bigger */
722 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
723 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);
725 SelectObject(hdc, old_hfont);
733 static void test_GdiGetCharDimensions(void)
739 LONG avgwidth, height;
740 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
742 if (!pGdiGetCharDimensions)
744 skip("GdiGetCharDimensions not available on this platform\n");
748 hdc = CreateCompatibleDC(NULL);
750 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
751 avgwidth = ((size.cx / 26) + 1) / 2;
753 ret = pGdiGetCharDimensions(hdc, &tm, &height);
754 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
755 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
757 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
758 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
760 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
761 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
764 ret = pGdiGetCharDimensions(hdc, NULL, &height);
765 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
766 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
771 static void test_GetCharABCWidths(void)
773 static const WCHAR str[] = {'a',0};
782 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
784 skip("GetCharABCWidthsW/I not available on this platform\n");
788 memset(&lf, 0, sizeof(lf));
789 strcpy(lf.lfFaceName, "System");
792 hfont = CreateFontIndirectA(&lf);
794 hfont = SelectObject(hdc, hfont);
796 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
797 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
799 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
800 ok(!ret, "GetCharABCWidthsI should have failed\n");
802 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
803 ok(!ret, "GetCharABCWidthsI should have failed\n");
805 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
806 ok(ret, "GetCharABCWidthsI should have succeeded\n");
808 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
809 ok(!ret, "GetCharABCWidthsW should have failed\n");
811 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
812 ok(!ret, "GetCharABCWidthsW should have failed\n");
814 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
815 ok(!ret, "GetCharABCWidthsW should have failed\n");
817 hfont = SelectObject(hdc, hfont);
819 ReleaseDC(NULL, hdc);
822 static void test_text_extents(void)
824 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
826 INT i, len, fit1, fit2;
834 memset(&lf, 0, sizeof(lf));
835 strcpy(lf.lfFaceName, "Arial");
838 hfont = CreateFontIndirectA(&lf);
840 hfont = SelectObject(hdc, hfont);
841 GetTextMetricsA(hdc, &tm);
842 GetTextExtentPointA(hdc, "o", 1, &sz);
843 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
845 SetLastError(0xdeadbeef);
846 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
847 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
849 skip("Skipping remainder of text extents test on a Win9x platform\n");
850 hfont = SelectObject(hdc, hfont);
857 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
858 extents[0] = 1; /* So that the increasing sequence test will fail
859 if the extents array is untouched. */
860 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
861 GetTextExtentPointW(hdc, wt, len, &sz2);
863 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
864 /* Because of the '\n' in the string GetTextExtentExPoint and
865 GetTextExtentPoint return different widths under Win2k, but
866 under WinXP they return the same width. So we don't test that
869 for (i = 1; i < len; ++i)
870 ok(extents[i-1] <= extents[i],
871 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
873 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
874 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
875 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
876 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
877 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
878 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
879 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
880 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
881 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
882 ok(extents[0] == extents[2] && extents[1] == extents[3],
883 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
884 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
885 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
886 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
887 HeapFree(GetProcessHeap(), 0, extents);
889 hfont = SelectObject(hdc, hfont);
891 ReleaseDC(NULL, hdc);
894 static void test_GetGlyphIndices(void)
901 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
902 WORD glyphs[(sizeof(testtext)/2)-1];
906 if (!pGetGlyphIndicesW) {
907 skip("GetGlyphIndicesW not available on platform\n");
913 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
914 flags |= GGI_MARK_NONEXISTING_GLYPHS;
915 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
916 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
917 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
919 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
920 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
921 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
922 textm.tmDefaultChar, glyphs[4]);
924 if(!is_font_installed("Tahoma"))
926 skip("Tahoma is not installed so skipping this test\n");
929 memset(&lf, 0, sizeof(lf));
930 strcpy(lf.lfFaceName, "Tahoma");
933 hfont = CreateFontIndirectA(&lf);
934 hOldFont = SelectObject(hdc, hfont);
935 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
936 flags |= GGI_MARK_NONEXISTING_GLYPHS;
937 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
938 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
939 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
941 testtext[0] = textm.tmDefaultChar;
942 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
943 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
944 todo_wine ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
945 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
946 DeleteObject(SelectObject(hdc, hOldFont));
949 static void test_GetKerningPairs(void)
951 static const struct kerning_data
953 const char face_name[LF_FACESIZE];
955 /* some interesting fields from OUTLINETEXTMETRIC */
956 LONG tmHeight, tmAscent, tmDescent;
961 UINT otmsCapEmHeight;
966 UINT otmusMinimumPPEM;
967 /* small subset of kerning pairs to test */
968 DWORD total_kern_pairs;
969 const KERNINGPAIR kern_pair[26];
972 {"Arial", 12, 12, 9, 3,
973 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
976 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
977 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
978 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
979 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
980 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
981 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
982 {933,970,+1},{933,972,-1}
985 {"Arial", -34, 39, 32, 7,
986 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
989 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
990 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
991 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
992 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
993 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
994 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
995 {933,970,+2},{933,972,-3}
998 { "Arial", 120, 120, 97, 23,
999 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1002 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1003 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1004 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1005 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1006 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1007 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1008 {933,970,+6},{933,972,-10}
1011 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1012 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1013 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1016 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1017 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1018 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1019 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1020 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1021 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1022 {933,970,+54},{933,972,-83}
1028 HFONT hfont, hfont_old;
1029 KERNINGPAIR *kern_pair;
1031 DWORD total_kern_pairs, ret, i, n, matches;
1035 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1036 * which may render this test unusable, so we're trying to avoid that.
1038 SetLastError(0xdeadbeef);
1039 GetKerningPairsW(hdc, 0, NULL);
1040 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1042 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1047 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1049 OUTLINETEXTMETRICW otm;
1051 if (!is_font_installed(kd[i].face_name))
1053 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1057 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1059 memset(&lf, 0, sizeof(lf));
1060 strcpy(lf.lfFaceName, kd[i].face_name);
1061 lf.lfHeight = kd[i].height;
1062 hfont = CreateFontIndirect(&lf);
1065 hfont_old = SelectObject(hdc, hfont);
1067 SetLastError(0xdeadbeef);
1068 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1069 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1071 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1072 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1073 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1074 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1075 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1076 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1078 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1079 kd[i].otmEMSquare, otm.otmEMSquare);
1080 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1081 kd[i].otmAscent, otm.otmAscent);
1082 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1083 kd[i].otmDescent, otm.otmDescent);
1084 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1085 kd[i].otmLineGap, otm.otmLineGap);
1086 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1087 kd[i].otmMacDescent, otm.otmMacDescent);
1089 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1090 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1091 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1092 kd[i].otmsXHeight, otm.otmsXHeight);
1093 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1094 kd[i].otmMacAscent, otm.otmMacAscent);
1095 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1096 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1097 kd[i].otmMacLineGap, otm.otmMacLineGap);
1098 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1099 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1102 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1103 trace("total_kern_pairs %u\n", total_kern_pairs);
1104 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1106 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1107 SetLastError(0xdeadbeef);
1108 ret = GetKerningPairsW(hdc, 0, kern_pair);
1109 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1110 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1111 ok(ret == 0, "got %lu, expected 0\n", ret);
1114 ret = GetKerningPairsW(hdc, 100, NULL);
1115 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1117 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1118 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1120 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1121 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1125 for (n = 0; n < ret; n++)
1129 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1130 trace("{'%c','%c',%d},\n",
1131 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1133 for (j = 0; j < kd[i].total_kern_pairs; j++)
1135 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1136 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1138 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1139 "pair %d:%d got %d, expected %d\n",
1140 kern_pair[n].wFirst, kern_pair[n].wSecond,
1141 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1147 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1148 matches, kd[i].total_kern_pairs);
1150 HeapFree(GetProcessHeap(), 0, kern_pair);
1152 SelectObject(hdc, hfont_old);
1153 DeleteObject(hfont);
1159 static void test_GetOutlineTextMetrics(void)
1161 OUTLINETEXTMETRIC *otm;
1163 HFONT hfont, hfont_old;
1165 DWORD ret, otm_size;
1167 if (!is_font_installed("Arial"))
1169 skip("Arial is not installed\n");
1175 memset(&lf, 0, sizeof(lf));
1176 strcpy(lf.lfFaceName, "Arial");
1178 lf.lfWeight = FW_NORMAL;
1179 lf.lfPitchAndFamily = DEFAULT_PITCH;
1180 lf.lfQuality = PROOF_QUALITY;
1181 hfont = CreateFontIndirect(&lf);
1184 hfont_old = SelectObject(hdc, hfont);
1185 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1186 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1188 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1190 memset(otm, 0xAA, otm_size);
1191 SetLastError(0xdeadbeef);
1192 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1193 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1194 ok(ret == 1 /* Win9x */ ||
1195 ret == otm->otmSize /* XP*/,
1196 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1197 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1199 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1200 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1201 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1202 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1205 memset(otm, 0xAA, otm_size);
1206 SetLastError(0xdeadbeef);
1207 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1208 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1209 ok(ret == 1 /* Win9x */ ||
1210 ret == otm->otmSize /* XP*/,
1211 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1212 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1214 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1215 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1216 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1217 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1220 /* ask about truncated data */
1221 memset(otm, 0xAA, otm_size);
1222 SetLastError(0xdeadbeef);
1223 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1224 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1225 ok(ret == 1 /* Win9x */ ||
1226 ret == otm->otmSize /* XP*/,
1227 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1228 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1230 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1231 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1232 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1234 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
1236 HeapFree(GetProcessHeap(), 0, otm);
1238 SelectObject(hdc, hfont_old);
1239 DeleteObject(hfont);
1244 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1248 outputWidth = 0, /* to test TabbedTextOut() */
1249 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1250 areaWidth = clientArea->right - clientArea->left,
1252 BOOL lastExtent = FALSE;
1253 PSTR pFirstChar, pLastChar;
1259 int GetTextExtentExPointWWidth;
1260 int TabbedTextOutWidth;
1263 GetTextMetricsA(hdc, &tm);
1264 y = clientArea->top;
1267 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1273 /* if not at the end of the string, ... */
1274 if (*str == '\0') break;
1275 /* ... add the next word to the current extent */
1276 while (*str != '\0' && *str++ != tm.tmBreakChar);
1278 SetTextJustification(hdc, 0, 0);
1279 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1280 } while ((int) size.cx < areaWidth);
1282 /* ignore trailing break chars */
1284 while (*(pLastChar - 1) == tm.tmBreakChar)
1290 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1292 SetTextJustification(hdc, 0, 0);
1293 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1295 /* do not justify the last extent */
1296 if (*str != '\0' && breakCount > 0)
1298 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1299 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1300 justifiedWidth = size.cx;
1302 else lastExtent = TRUE;
1304 x = clientArea->left;
1306 outputWidth = LOWORD(TabbedTextOut(
1307 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1309 /* catch errors and report them */
1310 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1312 memset(error[nErrors].extent, 0, 100);
1313 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1314 error[nErrors].TabbedTextOutWidth = outputWidth;
1315 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1321 } while (*str && y < clientArea->bottom);
1323 for (e = 0; e < nErrors; e++)
1325 ok(error[e].TabbedTextOutWidth == areaWidth,
1326 "The output text (\"%s\") width should be %d, not %d.\n",
1327 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1328 /* The width returned by GetTextExtentPoint32() is exactly the same
1329 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1330 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1331 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1332 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1336 static void test_SetTextJustification(void)
1343 static char testText[] =
1344 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1345 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1346 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1347 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1348 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1349 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1350 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1352 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1353 GetClientRect( hwnd, &clientArea );
1354 hdc = GetDC( hwnd );
1356 memset(&lf, 0, sizeof lf);
1357 lf.lfCharSet = ANSI_CHARSET;
1358 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1359 lf.lfWeight = FW_DONTCARE;
1361 lf.lfQuality = DEFAULT_QUALITY;
1362 lstrcpyA(lf.lfFaceName, "Times New Roman");
1363 hfont = create_font("Times New Roman", &lf);
1364 SelectObject(hdc, hfont);
1366 testJustification(hdc, testText, &clientArea);
1368 DeleteObject(hfont);
1369 ReleaseDC(hwnd, hdc);
1370 DestroyWindow(hwnd);
1373 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1377 HFONT hfont, hfont_old;
1384 assert(count <= 128);
1386 memset(&lf, 0, sizeof(lf));
1388 lf.lfCharSet = charset;
1390 lstrcpyA(lf.lfFaceName, "Arial");
1391 SetLastError(0xdeadbeef);
1392 hfont = CreateFontIndirectA(&lf);
1393 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1396 hfont_old = SelectObject(hdc, hfont);
1398 cs = GetTextCharsetInfo(hdc, &fs, 0);
1399 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1401 SetLastError(0xdeadbeef);
1402 ret = GetTextFaceA(hdc, sizeof(name), name);
1403 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1405 if (charset == SYMBOL_CHARSET)
1407 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1408 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1412 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1413 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1416 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1418 trace("Can't find codepage for charset %d\n", cs);
1422 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1427 WCHAR unicode_buf[128];
1429 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1431 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1433 SetLastError(0xdeadbeef);
1434 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1435 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1441 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1443 SetLastError(0xdeadbeef);
1444 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1445 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1448 SelectObject(hdc, hfont_old);
1449 DeleteObject(hfont);
1456 static void test_font_charset(void)
1458 static struct charset_data
1462 WORD font_idxA[128], font_idxW[128];
1465 { ANSI_CHARSET, 1252 },
1466 { RUSSIAN_CHARSET, 1251 },
1467 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1471 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1473 skip("Skipping the font charset test on a Win9x platform\n");
1477 if (!is_font_installed("Arial"))
1479 skip("Arial is not installed\n");
1483 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1485 if (cd[i].charset == SYMBOL_CHARSET)
1487 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1489 skip("Symbol or Wingdings is not installed\n");
1493 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1494 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1495 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1498 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1501 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1502 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1505 skip("Symbol or Wingdings is not installed\n");
1508 static void test_GetFontUnicodeRanges(void)
1512 HFONT hfont, hfont_old;
1516 if (!pGetFontUnicodeRanges)
1518 skip("GetFontUnicodeRanges not available before W2K\n");
1522 memset(&lf, 0, sizeof(lf));
1523 lstrcpyA(lf.lfFaceName, "Arial");
1524 hfont = create_font("Arial", &lf);
1527 hfont_old = SelectObject(hdc, hfont);
1529 size = pGetFontUnicodeRanges(NULL, NULL);
1530 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1532 size = pGetFontUnicodeRanges(hdc, NULL);
1533 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1535 gs = HeapAlloc(GetProcessHeap(), 0, size);
1537 size = pGetFontUnicodeRanges(hdc, gs);
1538 ok(size, "GetFontUnicodeRanges failed\n");
1540 for (i = 0; i < gs->cRanges; i++)
1541 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1543 trace("found %u ranges\n", gs->cRanges);
1545 HeapFree(GetProcessHeap(), 0, gs);
1547 SelectObject(hdc, hfont_old);
1548 DeleteObject(hfont);
1549 ReleaseDC(NULL, hdc);
1552 #define MAX_ENUM_FONTS 256
1554 struct enum_font_data
1557 LOGFONT lf[MAX_ENUM_FONTS];
1560 struct enum_font_dataW
1563 LOGFONTW lf[MAX_ENUM_FONTS];
1566 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1568 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1570 if (type != TRUETYPE_FONTTYPE) return 1;
1572 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1573 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1575 if (efd->total < MAX_ENUM_FONTS)
1576 efd->lf[efd->total++] = *lf;
1581 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1583 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1585 if (type != TRUETYPE_FONTTYPE) return 1;
1587 if (efd->total < MAX_ENUM_FONTS)
1588 efd->lf[efd->total++] = *lf;
1593 static void get_charset_stats(struct enum_font_data *efd,
1594 int *ansi_charset, int *symbol_charset,
1595 int *russian_charset)
1600 *symbol_charset = 0;
1601 *russian_charset = 0;
1603 for (i = 0; i < efd->total; i++)
1605 switch (efd->lf[i].lfCharSet)
1610 case SYMBOL_CHARSET:
1611 (*symbol_charset)++;
1613 case RUSSIAN_CHARSET:
1614 (*russian_charset)++;
1620 static void get_charset_statsW(struct enum_font_dataW *efd,
1621 int *ansi_charset, int *symbol_charset,
1622 int *russian_charset)
1627 *symbol_charset = 0;
1628 *russian_charset = 0;
1630 for (i = 0; i < efd->total; i++)
1632 switch (efd->lf[i].lfCharSet)
1637 case SYMBOL_CHARSET:
1638 (*symbol_charset)++;
1640 case RUSSIAN_CHARSET:
1641 (*russian_charset)++;
1647 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1649 struct enum_font_data efd;
1650 struct enum_font_dataW efdw;
1653 int i, ret, ansi_charset, symbol_charset, russian_charset;
1655 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1657 if (*font_name && !is_truetype_font_installed(font_name))
1659 skip("%s is not installed\n", font_name);
1665 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1666 * while EnumFontFamiliesEx doesn't.
1668 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1671 * Use EnumFontFamiliesW since win98 crashes when the
1672 * second parameter is NULL using EnumFontFamilies
1675 SetLastError(0xdeadbeef);
1676 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1677 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1680 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1681 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1682 ansi_charset, symbol_charset, russian_charset);
1683 ok(efd.total == 0, "fonts enumerated: NULL\n");
1684 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1685 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1686 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1690 SetLastError(0xdeadbeef);
1691 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1692 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1695 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1696 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1697 ansi_charset, symbol_charset, russian_charset);
1698 ok(efd.total == 0, "fonts enumerated: NULL\n");
1699 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1700 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1701 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1706 SetLastError(0xdeadbeef);
1707 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1708 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1709 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1710 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1711 ansi_charset, symbol_charset, russian_charset,
1712 *font_name ? font_name : "<empty>");
1714 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1716 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1717 for (i = 0; i < efd.total; i++)
1719 /* FIXME: remove completely once Wine is fixed */
1720 if (efd.lf[i].lfCharSet != font_charset)
1723 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1726 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1727 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1728 font_name, efd.lf[i].lfFaceName);
1731 memset(&lf, 0, sizeof(lf));
1732 lf.lfCharSet = ANSI_CHARSET;
1733 lstrcpy(lf.lfFaceName, font_name);
1735 SetLastError(0xdeadbeef);
1736 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1737 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1738 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1739 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1740 ansi_charset, symbol_charset, russian_charset,
1741 *font_name ? font_name : "<empty>");
1742 if (font_charset == SYMBOL_CHARSET)
1745 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1747 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1751 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1752 for (i = 0; i < efd.total; i++)
1754 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1756 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1757 font_name, efd.lf[i].lfFaceName);
1761 /* DEFAULT_CHARSET should enumerate all available charsets */
1762 memset(&lf, 0, sizeof(lf));
1763 lf.lfCharSet = DEFAULT_CHARSET;
1764 lstrcpy(lf.lfFaceName, font_name);
1766 SetLastError(0xdeadbeef);
1767 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1768 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1769 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1770 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1771 ansi_charset, symbol_charset, russian_charset,
1772 *font_name ? font_name : "<empty>");
1773 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1774 for (i = 0; i < efd.total; i++)
1777 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1778 font_name, efd.lf[i].lfFaceName);
1782 switch (font_charset)
1785 ok(ansi_charset > 0,
1786 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1788 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1789 ok(russian_charset > 0,
1790 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1792 case SYMBOL_CHARSET:
1794 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1796 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1797 ok(!russian_charset,
1798 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1800 case DEFAULT_CHARSET:
1801 ok(ansi_charset > 0,
1802 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1803 ok(symbol_charset > 0,
1804 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1805 ok(russian_charset > 0,
1806 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1812 ok(ansi_charset > 0,
1813 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1814 ok(symbol_charset > 0,
1815 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1816 ok(russian_charset > 0,
1817 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1820 memset(&lf, 0, sizeof(lf));
1821 lf.lfCharSet = SYMBOL_CHARSET;
1822 lstrcpy(lf.lfFaceName, font_name);
1824 SetLastError(0xdeadbeef);
1825 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1826 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1827 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1828 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1829 ansi_charset, symbol_charset, russian_charset,
1830 *font_name ? font_name : "<empty>");
1831 if (*font_name && font_charset == ANSI_CHARSET)
1832 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1835 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1836 for (i = 0; i < efd.total; i++)
1838 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1840 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1841 font_name, efd.lf[i].lfFaceName);
1845 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1846 ok(symbol_charset > 0,
1847 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1848 ok(!russian_charset,
1849 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1855 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1857 HFONT hfont, hfont_prev;
1859 GLYPHMETRICS gm1, gm2;
1862 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1864 if(!pGetGlyphIndicesA)
1866 skip("GetGlyphIndicesA is unavailable\n");
1870 /* negative widths are handled just as positive ones */
1871 lf2.lfWidth = -lf->lfWidth;
1873 SetLastError(0xdeadbeef);
1874 hfont = CreateFontIndirectA(lf);
1875 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1876 check_font("original", lf, hfont);
1878 hfont_prev = SelectObject(hdc, hfont);
1880 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1881 if (ret == GDI_ERROR || idx == 0xffff)
1883 SelectObject(hdc, hfont_prev);
1884 DeleteObject(hfont);
1885 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1889 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1890 memset(&gm1, 0xab, sizeof(gm1));
1891 SetLastError(0xdeadbeef);
1892 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1893 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1895 SelectObject(hdc, hfont_prev);
1896 DeleteObject(hfont);
1898 SetLastError(0xdeadbeef);
1899 hfont = CreateFontIndirectA(&lf2);
1900 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1901 check_font("negative width", &lf2, hfont);
1903 hfont_prev = SelectObject(hdc, hfont);
1905 memset(&gm2, 0xbb, sizeof(gm2));
1906 SetLastError(0xdeadbeef);
1907 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1908 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1910 SelectObject(hdc, hfont_prev);
1911 DeleteObject(hfont);
1913 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1914 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1915 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1916 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1917 gm1.gmCellIncX == gm2.gmCellIncX &&
1918 gm1.gmCellIncY == gm2.gmCellIncY,
1919 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1920 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1921 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1922 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1923 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1926 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1927 #include "pshpack2.h"
1931 SHORT xAvgCharWidth;
1932 USHORT usWeightClass;
1933 USHORT usWidthClass;
1935 SHORT ySubscriptXSize;
1936 SHORT ySubscriptYSize;
1937 SHORT ySubscriptXOffset;
1938 SHORT ySubscriptYOffset;
1939 SHORT ySuperscriptXSize;
1940 SHORT ySuperscriptYSize;
1941 SHORT ySuperscriptXOffset;
1942 SHORT ySuperscriptYOffset;
1943 SHORT yStrikeoutSize;
1944 SHORT yStrikeoutPosition;
1947 ULONG ulUnicodeRange1;
1948 ULONG ulUnicodeRange2;
1949 ULONG ulUnicodeRange3;
1950 ULONG ulUnicodeRange4;
1953 USHORT usFirstCharIndex;
1954 USHORT usLastCharIndex;
1955 /* According to the Apple spec, original version didn't have the below fields,
1956 * version numbers were taked from the OpenType spec.
1958 /* version 0 (TrueType 1.5) */
1959 USHORT sTypoAscender;
1960 USHORT sTypoDescender;
1961 USHORT sTypoLineGap;
1963 USHORT usWinDescent;
1964 /* version 1 (TrueType 1.66) */
1965 ULONG ulCodePageRange1;
1966 ULONG ulCodePageRange2;
1967 /* version 2 (OpenType 1.2) */
1970 USHORT usDefaultChar;
1972 USHORT usMaxContext;
1974 #include "poppack.h"
1976 #ifdef WORDS_BIGENDIAN
1977 #define GET_BE_WORD(x) (x)
1979 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1982 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1983 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1984 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1985 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1987 static void test_text_metrics(const LOGFONTA *lf)
1990 HFONT hfont, hfont_old;
1993 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1998 const char *font_name = lf->lfFaceName;
2002 SetLastError(0xdeadbeef);
2003 hfont = CreateFontIndirectA(lf);
2004 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2006 hfont_old = SelectObject(hdc, hfont);
2008 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2009 if (size == GDI_ERROR)
2011 trace("OS/2 chunk was not found\n");
2014 if (size > sizeof(tt_os2))
2016 trace("got too large OS/2 chunk of size %u\n", size);
2017 size = sizeof(tt_os2);
2020 memset(&tt_os2, 0, sizeof(tt_os2));
2021 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2022 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2024 version = GET_BE_WORD(tt_os2.version);
2026 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2027 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2028 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2029 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2031 trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
2032 font_name, lf->lfCharSet, first_unicode_char, last_unicode_char, default_char, break_char,
2033 version, (LPCSTR)&tt_os2.achVendID);
2035 SetLastError(0xdeadbeef);
2036 ret = GetTextMetricsA(hdc, &tmA);
2037 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2039 #if 0 /* FIXME: This doesn't appear to be what Windows does */
2040 test_char = min(first_unicode_char - 1, 255);
2041 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
2042 font_name, tmA.tmFirstChar, test_char);
2044 if (lf->lfCharSet == SYMBOL_CHARSET)
2046 test_char = min(last_unicode_char - 0xf000, 255);
2047 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2048 font_name, tmA.tmLastChar, test_char);
2052 test_char = min(last_unicode_char, 255);
2053 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2054 font_name, tmA.tmLastChar, test_char);
2057 SetLastError(0xdeadbeef);
2058 ret = GetTextMetricsW(hdc, &tmW);
2059 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2060 "GetTextMetricsW error %u\n", GetLastError());
2063 trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
2064 tmW.tmFirstChar, tmW.tmLastChar, tmA.tmFirstChar, tmA.tmLastChar,
2065 tmW.tmDefaultChar, tmA.tmDefaultChar, tmW.tmBreakChar, tmA.tmBreakChar);
2067 if (lf->lfCharSet == SYMBOL_CHARSET)
2069 /* It appears that for fonts with SYMBOL_CHARSET Windows always
2070 * sets symbol range to 0 - f0ff
2072 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
2073 font_name, tmW.tmFirstChar);
2074 /* FIXME: Windows returns f0ff here, while Wine f0xx */
2075 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
2076 font_name, tmW.tmLastChar);
2078 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
2079 font_name, tmW.tmDefaultChar);
2080 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
2081 font_name, tmW.tmBreakChar);
2085 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
2086 font_name, tmW.tmFirstChar, first_unicode_char);
2087 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
2088 font_name, tmW.tmLastChar, last_unicode_char);
2090 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2091 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2092 tmW.tmDigitizedAspectX, ret);
2093 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2094 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2095 tmW.tmDigitizedAspectX, ret);
2098 test_negative_width(hdc, lf);
2101 SelectObject(hdc, hfont_old);
2102 DeleteObject(hfont);
2107 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2109 INT *enumed = (INT *)lParam;
2111 if (type == TRUETYPE_FONTTYPE)
2114 test_text_metrics(lf);
2119 static void test_GetTextMetrics(void)
2127 memset(&lf, 0, sizeof(lf));
2128 lf.lfCharSet = DEFAULT_CHARSET;
2130 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2131 trace("Tested metrics of %d truetype fonts\n", enumed);
2136 static void test_nonexistent_font(void)
2144 { "Times New Roman Baltic", 186 },
2145 { "Times New Roman CE", 238 },
2146 { "Times New Roman CYR", 204 },
2147 { "Times New Roman Greek", 161 },
2148 { "Times New Roman TUR", 162 }
2154 INT cs, expected_cs, i;
2155 char buf[LF_FACESIZE];
2157 if (!is_truetype_font_installed("Arial") ||
2158 !is_truetype_font_installed("Times New Roman"))
2160 skip("Arial or Times New Roman not installed\n");
2164 expected_cs = GetACP();
2165 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2167 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2170 expected_cs = csi.ciCharset;
2171 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2175 memset(&lf, 0, sizeof(lf));
2177 lf.lfWeight = FW_REGULAR;
2178 lf.lfCharSet = ANSI_CHARSET;
2179 lf.lfPitchAndFamily = FF_SWISS;
2180 strcpy(lf.lfFaceName, "Nonexistent font");
2181 hfont = CreateFontIndirectA(&lf);
2182 hfont = SelectObject(hdc, hfont);
2183 GetTextFaceA(hdc, sizeof(buf), buf);
2184 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2185 cs = GetTextCharset(hdc);
2186 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2187 DeleteObject(SelectObject(hdc, hfont));
2189 memset(&lf, 0, sizeof(lf));
2191 lf.lfWeight = FW_DONTCARE;
2192 strcpy(lf.lfFaceName, "Nonexistent font");
2193 hfont = CreateFontIndirectA(&lf);
2194 hfont = SelectObject(hdc, hfont);
2195 GetTextFaceA(hdc, sizeof(buf), buf);
2196 todo_wine /* Wine uses Arial for all substitutions */
2197 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2198 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2199 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2201 cs = GetTextCharset(hdc);
2202 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2203 DeleteObject(SelectObject(hdc, hfont));
2205 memset(&lf, 0, sizeof(lf));
2207 lf.lfWeight = FW_REGULAR;
2208 strcpy(lf.lfFaceName, "Nonexistent font");
2209 hfont = CreateFontIndirectA(&lf);
2210 hfont = SelectObject(hdc, hfont);
2211 GetTextFaceA(hdc, sizeof(buf), buf);
2212 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2213 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2214 cs = GetTextCharset(hdc);
2215 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2216 DeleteObject(SelectObject(hdc, hfont));
2218 memset(&lf, 0, sizeof(lf));
2220 lf.lfWeight = FW_DONTCARE;
2221 strcpy(lf.lfFaceName, "Times New Roman");
2222 hfont = CreateFontIndirectA(&lf);
2223 hfont = SelectObject(hdc, hfont);
2224 GetTextFaceA(hdc, sizeof(buf), buf);
2225 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2226 cs = GetTextCharset(hdc);
2227 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2228 DeleteObject(SelectObject(hdc, hfont));
2230 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2232 memset(&lf, 0, sizeof(lf));
2234 lf.lfWeight = FW_REGULAR;
2235 strcpy(lf.lfFaceName, font_subst[i].name);
2236 hfont = CreateFontIndirectA(&lf);
2237 hfont = SelectObject(hdc, hfont);
2238 cs = GetTextCharset(hdc);
2239 if (font_subst[i].charset == expected_cs)
2241 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2242 GetTextFaceA(hdc, sizeof(buf), buf);
2243 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2247 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2248 GetTextFaceA(hdc, sizeof(buf), buf);
2249 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2250 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2252 DeleteObject(SelectObject(hdc, hfont));
2254 memset(&lf, 0, sizeof(lf));
2256 lf.lfWeight = FW_DONTCARE;
2257 strcpy(lf.lfFaceName, font_subst[i].name);
2258 hfont = CreateFontIndirectA(&lf);
2259 hfont = SelectObject(hdc, hfont);
2260 GetTextFaceA(hdc, sizeof(buf), buf);
2261 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2262 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2263 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2264 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2266 cs = GetTextCharset(hdc);
2267 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2268 DeleteObject(SelectObject(hdc, hfont));
2274 static void test_GdiRealizationInfo(void)
2279 HFONT hfont, hfont_old;
2282 if(!pGdiRealizationInfo)
2284 skip("GdiRealizationInfo not available\n");
2290 memset(info, 0xcc, sizeof(info));
2291 r = pGdiRealizationInfo(hdc, info);
2292 ok(r != 0, "ret 0\n");
2293 ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
2294 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2296 if (!is_truetype_font_installed("Arial"))
2298 skip("skipping GdiRealizationInfo with truetype font\n");
2302 memset(&lf, 0, sizeof(lf));
2303 strcpy(lf.lfFaceName, "Arial");
2305 lf.lfWeight = FW_NORMAL;
2306 hfont = CreateFontIndirectA(&lf);
2307 hfont_old = SelectObject(hdc, hfont);
2309 memset(info, 0xcc, sizeof(info));
2310 r = pGdiRealizationInfo(hdc, info);
2311 ok(r != 0, "ret 0\n");
2312 ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
2313 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2315 DeleteObject(SelectObject(hdc, hfont_old));
2321 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2322 the nul in the count of characters copied when the face name buffer is not
2323 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2324 always includes it. */
2325 static void test_GetTextFace(void)
2327 static const char faceA[] = "Tahoma";
2328 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2331 char bufA[LF_FACESIZE];
2332 WCHAR bufW[LF_FACESIZE];
2337 if(!is_font_installed("Tahoma"))
2339 skip("Tahoma is not installed so skipping this test\n");
2344 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2345 f = CreateFontIndirectA(&fA);
2346 ok(f != NULL, "CreateFontIndirectA failed\n");
2349 g = SelectObject(dc, f);
2350 n = GetTextFaceA(dc, sizeof bufA, bufA);
2351 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2352 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2354 /* Play with the count arg. */
2356 n = GetTextFaceA(dc, 0, bufA);
2357 ok(n == 0, "GetTextFaceA returned %d\n", n);
2358 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2361 n = GetTextFaceA(dc, 1, bufA);
2362 ok(n == 0, "GetTextFaceA returned %d\n", n);
2363 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2365 bufA[0] = 'x'; bufA[1] = 'y';
2366 n = GetTextFaceA(dc, 2, bufA);
2367 ok(n == 1, "GetTextFaceA returned %d\n", n);
2368 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2370 n = GetTextFaceA(dc, 0, NULL);
2371 ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
2373 DeleteObject(SelectObject(dc, g));
2374 ReleaseDC(NULL, dc);
2377 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2378 SetLastError(0xdeadbeef);
2379 f = CreateFontIndirectW(&fW);
2380 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2382 win_skip("CreateFontIndirectW is not implemented\n");
2385 ok(f != NULL, "CreateFontIndirectW failed\n");
2388 g = SelectObject(dc, f);
2389 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2390 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2391 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2393 /* Play with the count arg. */
2395 n = GetTextFaceW(dc, 0, bufW);
2396 ok(n == 0, "GetTextFaceW returned %d\n", n);
2397 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2400 n = GetTextFaceW(dc, 1, bufW);
2401 ok(n == 1, "GetTextFaceW returned %d\n", n);
2402 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2404 bufW[0] = 'x'; bufW[1] = 'y';
2405 n = GetTextFaceW(dc, 2, bufW);
2406 ok(n == 2, "GetTextFaceW returned %d\n", n);
2407 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2409 n = GetTextFaceW(dc, 0, NULL);
2410 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2412 DeleteObject(SelectObject(dc, g));
2413 ReleaseDC(NULL, dc);
2416 static void test_orientation(void)
2418 static const char test_str[11] = "Test String";
2421 HFONT hfont, old_hfont;
2424 if (!is_truetype_font_installed("Arial"))
2426 skip("Arial is not installed\n");
2430 hdc = CreateCompatibleDC(0);
2431 memset(&lf, 0, sizeof(lf));
2432 lstrcpyA(lf.lfFaceName, "Arial");
2434 lf.lfOrientation = lf.lfEscapement = 900;
2435 hfont = create_font("orientation", &lf);
2436 old_hfont = SelectObject(hdc, hfont);
2437 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2438 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2439 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2440 SelectObject(hdc, old_hfont);
2441 DeleteObject(hfont);
2451 test_outline_font();
2452 test_bitmap_font_metrics();
2453 test_GdiGetCharDimensions();
2454 test_GetCharABCWidths();
2455 test_text_extents();
2456 test_GetGlyphIndices();
2457 test_GetKerningPairs();
2458 test_GetOutlineTextMetrics();
2459 test_SetTextJustification();
2460 test_font_charset();
2461 test_GetFontUnicodeRanges();
2462 test_nonexistent_font();
2465 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2466 * I'd like to avoid them in this test.
2468 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2469 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2470 if (is_truetype_font_installed("Arial Black") &&
2471 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2473 test_EnumFontFamilies("", ANSI_CHARSET);
2474 test_EnumFontFamilies("", SYMBOL_CHARSET);
2475 test_EnumFontFamilies("", DEFAULT_CHARSET);
2478 skip("Arial Black or Symbol/Wingdings is not installed\n");
2479 test_GetTextMetrics();
2480 test_GdiRealizationInfo();