gdi32/tests: Allow some more rounding errors in glyph sizes.
[wine/gsoc_dplay.git] / dlls / gdi32 / tests / font.c
blobf305b3ae051e2383775ae232b14e889c7649d864
1 /*
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
22 #include <stdarg.h>
23 #include <assert.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winnls.h"
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;
63 return 0;
66 static BOOL is_truetype_font_installed(const char *name)
68 HDC hdc = GetDC(0);
69 BOOL ret = FALSE;
71 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
72 ret = TRUE;
74 ReleaseDC(0, hdc);
75 return ret;
78 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
80 return 0;
83 static BOOL is_font_installed(const char *name)
85 HDC hdc = GetDC(0);
86 BOOL ret = FALSE;
88 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
89 ret = TRUE;
91 ReleaseDC(0, hdc);
92 return ret;
95 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
97 LOGFONTA getobj_lf;
98 int ret, minlen = 0;
100 if (!hfont)
101 return;
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)
106 minlen++;
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);
118 if (hfont)
119 check_font(test, lf, hfont);
120 return hfont;
123 static void test_logfont(void)
125 LOGFONTA lf;
126 HFONT hfont;
128 memset(&lf, 0, sizeof lf);
130 lf.lfCharSet = ANSI_CHARSET;
131 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
132 lf.lfWeight = FW_DONTCARE;
133 lf.lfHeight = 16;
134 lf.lfWidth = 16;
135 lf.lfQuality = DEFAULT_QUALITY;
137 lstrcpyA(lf.lfFaceName, "Arial");
138 hfont = create_font("Arial", &lf);
139 DeleteObject(hfont);
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);
147 DeleteObject(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;
155 *lf = *elf;
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)
192 HFONT old_hfont;
193 LOGFONTA lf;
194 OUTLINETEXTMETRIC otm;
195 TEXTMETRICA tm;
196 SIZE size;
197 INT width_of_A, cx, cy;
198 UINT ret;
200 if (!hfont)
201 return;
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);
243 else
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);
260 if (lf.lfHeight)
262 if (lf.lfWidth)
263 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
265 else
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";
284 HDC hdc;
285 LOGFONTA bitmap_lf;
286 HFONT hfont, old_hfont;
287 TEXTMETRICA tm_orig;
288 SIZE size_orig;
289 INT ret, i, width_orig, height_orig, scale, lfWidth;
291 hdc = GetDC(0);
293 /* "System" has only 1 pixel size defined, otherwise the test breaks */
294 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
295 if (ret)
297 ReleaseDC(0, hdc);
298 trace("no bitmap fonts were found, skipping the test\n");
299 return;
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);
313 DeleteObject(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);
319 DeleteObject(hfont);
321 bitmap_lf.lfHeight = height_orig;
322 bitmap_lf.lfWidth = lfWidth;
324 /* test fractional scaling */
325 for (i = 1; i <= height_orig * 3; i++)
327 INT nearest_height;
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);
336 DeleteObject(hfont);
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);
344 DeleteObject(hfont);
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);
351 DeleteObject(hfont);
353 ReleaseDC(0, hdc);
356 /* Test how GDI scales outline font metrics */
357 static void test_outline_font(void)
359 static const char test_str[11] = "Test String";
360 HDC hdc;
361 LOGFONTA lf;
362 HFONT hfont, old_hfont;
363 OUTLINETEXTMETRICA otm;
364 SIZE size_orig;
365 INT width_orig, height_orig, lfWidth;
366 XFORM xform;
367 GLYPHMETRICS gm;
368 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
369 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
370 POINT pt;
371 INT ret;
373 if (!is_truetype_font_installed("Arial"))
375 skip("Arial is not installed\n");
376 return;
379 hdc = CreateCompatibleDC(0);
381 memset(&lf, 0, sizeof(lf));
382 strcpy(lf.lfFaceName, "Arial");
383 lf.lfHeight = 72;
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);
393 DeleteObject(hfont);
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);
405 DeleteObject(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);
415 DeleteObject(hfont);
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);
422 DeleteObject(hfont);
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);
429 DeleteObject(hfont);
431 /* test integer scaling 1x1 */
432 lf.lfHeight = height_orig;
433 lf.lfWidth = 0;
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 SetMapMode(hdc, MM_ANISOTROPIC);
457 /* test restrictions of compatibility mode GM_COMPATIBLE */
458 /* part 1: rescaling only X should not change font scaling on screen.
459 So compressing the X axis by 2 is not done, and this
460 appears as X scaling of 2 that no one requested. */
461 SetWindowExtEx(hdc, 100, 100, NULL);
462 SetViewportExtEx(hdc, 50, 100, NULL);
463 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
465 /* part 2: rescaling only Y should change font scaling.
466 As also X is scaled by a factor of 2, but this is not
467 requested by the DC transformation, we get a scaling factor
468 of 2 in the X coordinate. */
469 SetViewportExtEx(hdc, 100, 200, NULL);
470 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
472 /* restore scaling */
473 SetMapMode(hdc, MM_TEXT);
475 if (!SetGraphicsMode(hdc, GM_ADVANCED))
477 DeleteObject(hfont);
478 DeleteDC(hdc);
479 skip("GM_ADVANCED is not supported on this platform\n");
480 return;
483 xform.eM11 = 20.0f;
484 xform.eM12 = 0.0f;
485 xform.eM21 = 0.0f;
486 xform.eM22 = 20.0f;
487 xform.eDx = 0.0f;
488 xform.eDy = 0.0f;
490 SetLastError(0xdeadbeef);
491 ret = SetWorldTransform(hdc, &xform);
492 ok(ret, "SetWorldTransform error %u\n", GetLastError());
494 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
496 old_hfont = SelectObject(hdc, hfont);
497 /* with an identity matrix */
498 memset(&gm, 0, sizeof(gm));
499 SetLastError(0xdeadbeef);
500 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
501 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
502 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
503 pt.x = width_orig; pt.y = 0;
504 LPtoDP(hdc, &pt, 1);
505 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
506 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
507 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
508 /* with a custom matrix */
509 memset(&gm, 0, sizeof(gm));
510 SetLastError(0xdeadbeef);
511 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
512 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
513 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
514 pt.x = width_orig; pt.y = 0;
515 LPtoDP(hdc, &pt, 1);
516 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
517 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
518 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
519 SelectObject(hdc, old_hfont);
521 SetLastError(0xdeadbeef);
522 ret = SetMapMode(hdc, MM_LOMETRIC);
523 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
525 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
527 old_hfont = SelectObject(hdc, hfont);
528 /* with an identity matrix */
529 memset(&gm, 0, sizeof(gm));
530 SetLastError(0xdeadbeef);
531 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
532 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
533 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
534 pt.x = width_orig; pt.y = 0;
535 LPtoDP(hdc, &pt, 1);
536 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
537 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
538 /* with a custom matrix */
539 memset(&gm, 0, sizeof(gm));
540 SetLastError(0xdeadbeef);
541 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
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;
545 LPtoDP(hdc, &pt, 1);
546 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
547 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
548 SelectObject(hdc, old_hfont);
550 SetLastError(0xdeadbeef);
551 ret = SetMapMode(hdc, MM_TEXT);
552 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
554 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
556 old_hfont = SelectObject(hdc, hfont);
557 /* with an identity matrix */
558 memset(&gm, 0, sizeof(gm));
559 SetLastError(0xdeadbeef);
560 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
561 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
562 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
563 pt.x = width_orig; pt.y = 0;
564 LPtoDP(hdc, &pt, 1);
565 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
566 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
567 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
568 /* with a custom matrix */
569 memset(&gm, 0, sizeof(gm));
570 SetLastError(0xdeadbeef);
571 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
572 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
573 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
574 pt.x = width_orig; pt.y = 0;
575 LPtoDP(hdc, &pt, 1);
576 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
577 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
578 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
579 SelectObject(hdc, old_hfont);
581 DeleteObject(hfont);
582 DeleteDC(hdc);
585 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
587 LOGFONT *lf = (LOGFONT *)lParam;
589 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
591 *lf = *elf;
592 return 0; /* stop enumeration */
594 return 1; /* continue enumeration */
597 static void test_bitmap_font_metrics(void)
599 static const struct font_data
601 const char face_name[LF_FACESIZE];
602 int weight, height, ascent, descent, int_leading, ext_leading;
603 int ave_char_width, max_char_width;
604 DWORD ansi_bitfield;
605 } fd[] =
607 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
608 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
609 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
610 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
611 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
612 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
613 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
614 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
615 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
616 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
617 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
618 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
619 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
620 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
621 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
622 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
623 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
624 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
625 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
626 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
627 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
628 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
629 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
630 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
631 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
632 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
633 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
634 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
635 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
636 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
637 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
638 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
639 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
641 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
642 * require a new system.sfd for that font
644 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
645 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
646 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
647 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
648 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
649 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
650 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
651 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
652 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
653 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
654 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
655 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
656 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
657 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
658 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
659 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
660 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
661 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
662 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
663 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
664 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
666 /* FIXME: add "Terminal" */
668 HDC hdc;
669 LOGFONT lf;
670 HFONT hfont, old_hfont;
671 TEXTMETRIC tm;
672 INT ret, i;
674 hdc = CreateCompatibleDC(0);
675 assert(hdc);
677 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
679 int bit;
681 memset(&lf, 0, sizeof(lf));
683 lf.lfHeight = fd[i].height;
684 strcpy(lf.lfFaceName, fd[i].face_name);
686 for(bit = 0; bit < 32; bit++)
688 DWORD fs[2];
689 CHARSETINFO csi;
691 fs[0] = 1L << bit;
692 fs[1] = 0;
693 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
694 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
696 lf.lfCharSet = csi.ciCharset;
697 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
698 if (ret) continue;
700 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
702 hfont = create_font(lf.lfFaceName, &lf);
703 old_hfont = SelectObject(hdc, hfont);
704 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
706 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);
707 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);
708 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);
709 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);
710 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);
711 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);
712 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);
714 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
715 that make the max width bigger */
716 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
717 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);
719 SelectObject(hdc, old_hfont);
720 DeleteObject(hfont);
724 DeleteDC(hdc);
727 static void test_GdiGetCharDimensions(void)
729 HDC hdc;
730 TEXTMETRICW tm;
731 LONG ret;
732 SIZE size;
733 LONG avgwidth, height;
734 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
736 if (!pGdiGetCharDimensions)
738 skip("GdiGetCharDimensions not available on this platform\n");
739 return;
742 hdc = CreateCompatibleDC(NULL);
744 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
745 avgwidth = ((size.cx / 26) + 1) / 2;
747 ret = pGdiGetCharDimensions(hdc, &tm, &height);
748 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
749 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
751 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
752 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
754 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
755 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
757 height = 0;
758 ret = pGdiGetCharDimensions(hdc, NULL, &height);
759 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
760 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
762 DeleteDC(hdc);
765 static void test_GetCharABCWidths(void)
767 static const WCHAR str[] = {'a',0};
768 BOOL ret;
769 HDC hdc;
770 LOGFONTA lf;
771 HFONT hfont;
772 ABC abc[1];
773 WORD glyphs[1];
774 DWORD nb;
776 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
778 skip("GetCharABCWidthsW/I not available on this platform\n");
779 return;
782 memset(&lf, 0, sizeof(lf));
783 strcpy(lf.lfFaceName, "System");
784 lf.lfHeight = 20;
786 hfont = CreateFontIndirectA(&lf);
787 hdc = GetDC(0);
788 hfont = SelectObject(hdc, hfont);
790 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
791 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
793 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
794 ok(!ret, "GetCharABCWidthsI should have failed\n");
796 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
797 ok(!ret, "GetCharABCWidthsI should have failed\n");
799 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
800 ok(ret, "GetCharABCWidthsI should have succeeded\n");
802 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
803 ok(!ret, "GetCharABCWidthsW should have failed\n");
805 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
806 ok(!ret, "GetCharABCWidthsW should have failed\n");
808 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
809 ok(!ret, "GetCharABCWidthsW should have failed\n");
811 hfont = SelectObject(hdc, hfont);
812 DeleteObject(hfont);
813 ReleaseDC(NULL, hdc);
816 static void test_text_extents(void)
818 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
819 LPINT extents;
820 INT i, len, fit1, fit2;
821 LOGFONTA lf;
822 TEXTMETRICA tm;
823 HDC hdc;
824 HFONT hfont;
825 SIZE sz;
826 SIZE sz1, sz2;
828 memset(&lf, 0, sizeof(lf));
829 strcpy(lf.lfFaceName, "Arial");
830 lf.lfHeight = 20;
832 hfont = CreateFontIndirectA(&lf);
833 hdc = GetDC(0);
834 hfont = SelectObject(hdc, hfont);
835 GetTextMetricsA(hdc, &tm);
836 GetTextExtentPointA(hdc, "o", 1, &sz);
837 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
839 SetLastError(0xdeadbeef);
840 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
841 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
843 skip("Skipping remainder of text extents test on a Win9x platform\n");
844 hfont = SelectObject(hdc, hfont);
845 DeleteObject(hfont);
846 ReleaseDC(0, hdc);
847 return;
850 len = lstrlenW(wt);
851 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
852 extents[0] = 1; /* So that the increasing sequence test will fail
853 if the extents array is untouched. */
854 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
855 GetTextExtentPointW(hdc, wt, len, &sz2);
856 ok(sz1.cy == sz2.cy,
857 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
858 /* Because of the '\n' in the string GetTextExtentExPoint and
859 GetTextExtentPoint return different widths under Win2k, but
860 under WinXP they return the same width. So we don't test that
861 here. */
863 for (i = 1; i < len; ++i)
864 ok(extents[i-1] <= extents[i],
865 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
867 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
868 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
869 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
870 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
871 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
872 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
873 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
874 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
875 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
876 ok(extents[0] == extents[2] && extents[1] == extents[3],
877 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
878 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
879 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
880 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
881 HeapFree(GetProcessHeap(), 0, extents);
883 hfont = SelectObject(hdc, hfont);
884 DeleteObject(hfont);
885 ReleaseDC(NULL, hdc);
888 static void test_GetGlyphIndices(void)
890 HDC hdc;
891 HFONT hfont;
892 DWORD charcount;
893 LOGFONTA lf;
894 DWORD flags = 0;
895 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
896 WORD glyphs[(sizeof(testtext)/2)-1];
897 TEXTMETRIC textm;
898 HFONT hOldFont;
900 if (!pGetGlyphIndicesW) {
901 skip("GetGlyphIndicesW not available on platform\n");
902 return;
905 hdc = GetDC(0);
907 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
908 flags |= GGI_MARK_NONEXISTING_GLYPHS;
909 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
910 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
911 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
912 flags = 0;
913 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
914 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
915 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
916 textm.tmDefaultChar, glyphs[4]);
918 if(!is_font_installed("Tahoma"))
920 skip("Tahoma is not installed so skipping this test\n");
921 return;
923 memset(&lf, 0, sizeof(lf));
924 strcpy(lf.lfFaceName, "Tahoma");
925 lf.lfHeight = 20;
927 hfont = CreateFontIndirectA(&lf);
928 hOldFont = SelectObject(hdc, hfont);
929 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
930 flags |= GGI_MARK_NONEXISTING_GLYPHS;
931 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
932 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
933 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
934 flags = 0;
935 testtext[0] = textm.tmDefaultChar;
936 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
937 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
938 todo_wine ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
939 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
940 DeleteObject(SelectObject(hdc, hOldFont));
943 static void test_GetKerningPairs(void)
945 static const struct kerning_data
947 const char face_name[LF_FACESIZE];
948 LONG height;
949 /* some interesting fields from OUTLINETEXTMETRIC */
950 LONG tmHeight, tmAscent, tmDescent;
951 UINT otmEMSquare;
952 INT otmAscent;
953 INT otmDescent;
954 UINT otmLineGap;
955 UINT otmsCapEmHeight;
956 UINT otmsXHeight;
957 INT otmMacAscent;
958 INT otmMacDescent;
959 UINT otmMacLineGap;
960 UINT otmusMinimumPPEM;
961 /* small subset of kerning pairs to test */
962 DWORD total_kern_pairs;
963 const KERNINGPAIR kern_pair[26];
964 } kd[] =
966 {"Arial", 12, 12, 9, 3,
967 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
970 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
971 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
972 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
973 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
974 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
975 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
976 {933,970,+1},{933,972,-1}
979 {"Arial", -34, 39, 32, 7,
980 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
983 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
984 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
985 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
986 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
987 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
988 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
989 {933,970,+2},{933,972,-3}
992 { "Arial", 120, 120, 97, 23,
993 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
996 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
997 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
998 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
999 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1000 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1001 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1002 {933,970,+6},{933,972,-10}
1005 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1006 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1007 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1010 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1011 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1012 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1013 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1014 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1015 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1016 {933,970,+54},{933,972,-83}
1019 #endif
1021 LOGFONT lf;
1022 HFONT hfont, hfont_old;
1023 KERNINGPAIR *kern_pair;
1024 HDC hdc;
1025 DWORD total_kern_pairs, ret, i, n, matches;
1027 hdc = GetDC(0);
1029 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1030 * which may render this test unusable, so we're trying to avoid that.
1032 SetLastError(0xdeadbeef);
1033 GetKerningPairsW(hdc, 0, NULL);
1034 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1036 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1037 ReleaseDC(0, hdc);
1038 return;
1041 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1043 OUTLINETEXTMETRICW otm;
1045 if (!is_font_installed(kd[i].face_name))
1047 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1048 continue;
1051 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1053 memset(&lf, 0, sizeof(lf));
1054 strcpy(lf.lfFaceName, kd[i].face_name);
1055 lf.lfHeight = kd[i].height;
1056 hfont = CreateFontIndirect(&lf);
1057 assert(hfont != 0);
1059 hfont_old = SelectObject(hdc, hfont);
1061 SetLastError(0xdeadbeef);
1062 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1063 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1065 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1066 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1067 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1068 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1069 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1070 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1072 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1073 kd[i].otmEMSquare, otm.otmEMSquare);
1074 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1075 kd[i].otmAscent, otm.otmAscent);
1076 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1077 kd[i].otmDescent, otm.otmDescent);
1078 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1079 kd[i].otmLineGap, otm.otmLineGap);
1080 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1081 kd[i].otmMacDescent, otm.otmMacDescent);
1082 todo_wine {
1083 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1084 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1085 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1086 kd[i].otmsXHeight, otm.otmsXHeight);
1087 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1088 kd[i].otmMacAscent, otm.otmMacAscent);
1089 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1090 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1091 kd[i].otmMacLineGap, otm.otmMacLineGap);
1092 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1093 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1096 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1097 trace("total_kern_pairs %u\n", total_kern_pairs);
1098 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1100 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1101 SetLastError(0xdeadbeef);
1102 ret = GetKerningPairsW(hdc, 0, kern_pair);
1103 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1104 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1105 ok(ret == 0, "got %lu, expected 0\n", ret);
1106 #endif
1108 ret = GetKerningPairsW(hdc, 100, NULL);
1109 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1111 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1112 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1114 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1115 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1117 matches = 0;
1119 for (n = 0; n < ret; n++)
1121 DWORD j;
1122 #if 0
1123 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1124 trace("{'%c','%c',%d},\n",
1125 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1126 #endif
1127 for (j = 0; j < kd[i].total_kern_pairs; j++)
1129 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1130 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1132 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1133 "pair %d:%d got %d, expected %d\n",
1134 kern_pair[n].wFirst, kern_pair[n].wSecond,
1135 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1136 matches++;
1141 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1142 matches, kd[i].total_kern_pairs);
1144 HeapFree(GetProcessHeap(), 0, kern_pair);
1146 SelectObject(hdc, hfont_old);
1147 DeleteObject(hfont);
1150 ReleaseDC(0, hdc);
1153 static void test_GetOutlineTextMetrics(void)
1155 OUTLINETEXTMETRIC *otm;
1156 LOGFONT lf;
1157 HFONT hfont, hfont_old;
1158 HDC hdc;
1159 DWORD ret, otm_size;
1161 if (!is_font_installed("Arial"))
1163 skip("Arial is not installed\n");
1164 return;
1167 hdc = GetDC(0);
1169 memset(&lf, 0, sizeof(lf));
1170 strcpy(lf.lfFaceName, "Arial");
1171 lf.lfHeight = -13;
1172 lf.lfWeight = FW_NORMAL;
1173 lf.lfPitchAndFamily = DEFAULT_PITCH;
1174 lf.lfQuality = PROOF_QUALITY;
1175 hfont = CreateFontIndirect(&lf);
1176 assert(hfont != 0);
1178 hfont_old = SelectObject(hdc, hfont);
1179 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1180 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1182 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1184 memset(otm, 0xAA, otm_size);
1185 SetLastError(0xdeadbeef);
1186 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1187 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1188 ok(ret == 1 /* Win9x */ ||
1189 ret == otm->otmSize /* XP*/,
1190 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1191 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1193 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1194 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1195 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1196 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1199 memset(otm, 0xAA, otm_size);
1200 SetLastError(0xdeadbeef);
1201 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1202 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1203 ok(ret == 1 /* Win9x */ ||
1204 ret == otm->otmSize /* XP*/,
1205 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1206 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1208 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1209 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1210 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1211 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1214 /* ask about truncated data */
1215 memset(otm, 0xAA, otm_size);
1216 SetLastError(0xdeadbeef);
1217 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1218 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1219 ok(ret == 1 /* Win9x */ ||
1220 ret == otm->otmSize /* XP*/,
1221 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1222 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1224 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1225 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1226 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1228 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
1230 HeapFree(GetProcessHeap(), 0, otm);
1232 SelectObject(hdc, hfont_old);
1233 DeleteObject(hfont);
1235 ReleaseDC(0, hdc);
1238 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1240 INT x, y,
1241 breakCount,
1242 outputWidth = 0, /* to test TabbedTextOut() */
1243 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1244 areaWidth = clientArea->right - clientArea->left,
1245 nErrors = 0, e;
1246 BOOL lastExtent = FALSE;
1247 PSTR pFirstChar, pLastChar;
1248 SIZE size;
1249 TEXTMETRICA tm;
1250 struct err
1252 char extent[100];
1253 int GetTextExtentExPointWWidth;
1254 int TabbedTextOutWidth;
1255 } error[10];
1257 GetTextMetricsA(hdc, &tm);
1258 y = clientArea->top;
1259 do {
1260 breakCount = 0;
1261 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1262 pFirstChar = str;
1264 do {
1265 pLastChar = str;
1267 /* if not at the end of the string, ... */
1268 if (*str == '\0') break;
1269 /* ... add the next word to the current extent */
1270 while (*str != '\0' && *str++ != tm.tmBreakChar);
1271 breakCount++;
1272 SetTextJustification(hdc, 0, 0);
1273 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1274 } while ((int) size.cx < areaWidth);
1276 /* ignore trailing break chars */
1277 breakCount--;
1278 while (*(pLastChar - 1) == tm.tmBreakChar)
1280 pLastChar--;
1281 breakCount--;
1284 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1286 SetTextJustification(hdc, 0, 0);
1287 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1289 /* do not justify the last extent */
1290 if (*str != '\0' && breakCount > 0)
1292 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1293 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1294 justifiedWidth = size.cx;
1296 else lastExtent = TRUE;
1298 x = clientArea->left;
1300 outputWidth = LOWORD(TabbedTextOut(
1301 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1302 0, NULL, 0));
1303 /* catch errors and report them */
1304 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1306 memset(error[nErrors].extent, 0, 100);
1307 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1308 error[nErrors].TabbedTextOutWidth = outputWidth;
1309 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1310 nErrors++;
1313 y += size.cy;
1314 str = pLastChar;
1315 } while (*str && y < clientArea->bottom);
1317 for (e = 0; e < nErrors; e++)
1319 ok(error[e].TabbedTextOutWidth == areaWidth,
1320 "The output text (\"%s\") width should be %d, not %d.\n",
1321 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1322 /* The width returned by GetTextExtentPoint32() is exactly the same
1323 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1324 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1325 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1326 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1330 static void test_SetTextJustification(void)
1332 HDC hdc;
1333 RECT clientArea;
1334 LOGFONTA lf;
1335 HFONT hfont;
1336 HWND hwnd;
1337 static char testText[] =
1338 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1339 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1340 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1341 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1342 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1343 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1344 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1346 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1347 GetClientRect( hwnd, &clientArea );
1348 hdc = GetDC( hwnd );
1350 memset(&lf, 0, sizeof lf);
1351 lf.lfCharSet = ANSI_CHARSET;
1352 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1353 lf.lfWeight = FW_DONTCARE;
1354 lf.lfHeight = 20;
1355 lf.lfQuality = DEFAULT_QUALITY;
1356 lstrcpyA(lf.lfFaceName, "Times New Roman");
1357 hfont = create_font("Times New Roman", &lf);
1358 SelectObject(hdc, hfont);
1360 testJustification(hdc, testText, &clientArea);
1362 DeleteObject(hfont);
1363 ReleaseDC(hwnd, hdc);
1364 DestroyWindow(hwnd);
1367 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1369 HDC hdc;
1370 LOGFONTA lf;
1371 HFONT hfont, hfont_old;
1372 CHARSETINFO csi;
1373 FONTSIGNATURE fs;
1374 INT cs;
1375 DWORD i, ret;
1376 char name[64];
1378 assert(count <= 128);
1380 memset(&lf, 0, sizeof(lf));
1382 lf.lfCharSet = charset;
1383 lf.lfHeight = 10;
1384 lstrcpyA(lf.lfFaceName, "Arial");
1385 SetLastError(0xdeadbeef);
1386 hfont = CreateFontIndirectA(&lf);
1387 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1389 hdc = GetDC(0);
1390 hfont_old = SelectObject(hdc, hfont);
1392 cs = GetTextCharsetInfo(hdc, &fs, 0);
1393 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1395 SetLastError(0xdeadbeef);
1396 ret = GetTextFaceA(hdc, sizeof(name), name);
1397 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1399 if (charset == SYMBOL_CHARSET)
1401 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1402 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1404 else
1406 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1407 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1410 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1412 trace("Can't find codepage for charset %d\n", cs);
1413 ReleaseDC(0, hdc);
1414 return FALSE;
1416 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1418 if (unicode)
1420 char ansi_buf[128];
1421 WCHAR unicode_buf[128];
1423 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1425 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1427 SetLastError(0xdeadbeef);
1428 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1429 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1431 else
1433 char ansi_buf[128];
1435 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1437 SetLastError(0xdeadbeef);
1438 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1439 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1442 SelectObject(hdc, hfont_old);
1443 DeleteObject(hfont);
1445 ReleaseDC(0, hdc);
1447 return TRUE;
1450 static void test_font_charset(void)
1452 static struct charset_data
1454 INT charset;
1455 UINT code_page;
1456 WORD font_idxA[128], font_idxW[128];
1457 } cd[] =
1459 { ANSI_CHARSET, 1252 },
1460 { RUSSIAN_CHARSET, 1251 },
1461 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1463 int i;
1465 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1467 skip("Skipping the font charset test on a Win9x platform\n");
1468 return;
1471 if (!is_font_installed("Arial"))
1473 skip("Arial is not installed\n");
1474 return;
1477 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1479 if (cd[i].charset == SYMBOL_CHARSET)
1481 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1483 skip("Symbol or Wingdings is not installed\n");
1484 break;
1487 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1488 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1489 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1492 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1493 if (i > 2)
1495 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1496 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1498 else
1499 skip("Symbol or Wingdings is not installed\n");
1502 static void test_GetFontUnicodeRanges(void)
1504 LOGFONTA lf;
1505 HDC hdc;
1506 HFONT hfont, hfont_old;
1507 DWORD size;
1508 GLYPHSET *gs;
1510 if (!pGetFontUnicodeRanges)
1512 skip("GetFontUnicodeRanges not available before W2K\n");
1513 return;
1516 memset(&lf, 0, sizeof(lf));
1517 lstrcpyA(lf.lfFaceName, "Arial");
1518 hfont = create_font("Arial", &lf);
1520 hdc = GetDC(0);
1521 hfont_old = SelectObject(hdc, hfont);
1523 size = pGetFontUnicodeRanges(NULL, NULL);
1524 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1526 size = pGetFontUnicodeRanges(hdc, NULL);
1527 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1529 gs = HeapAlloc(GetProcessHeap(), 0, size);
1531 size = pGetFontUnicodeRanges(hdc, gs);
1532 ok(size, "GetFontUnicodeRanges failed\n");
1533 #if 0
1534 for (i = 0; i < gs->cRanges; i++)
1535 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1536 #endif
1537 trace("found %u ranges\n", gs->cRanges);
1539 HeapFree(GetProcessHeap(), 0, gs);
1541 SelectObject(hdc, hfont_old);
1542 DeleteObject(hfont);
1543 ReleaseDC(NULL, hdc);
1546 #define MAX_ENUM_FONTS 256
1548 struct enum_font_data
1550 int total;
1551 LOGFONT lf[MAX_ENUM_FONTS];
1554 struct enum_font_dataW
1556 int total;
1557 LOGFONTW lf[MAX_ENUM_FONTS];
1560 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1562 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1564 if (type != TRUETYPE_FONTTYPE) return 1;
1565 #if 0
1566 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1567 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1568 #endif
1569 if (efd->total < MAX_ENUM_FONTS)
1570 efd->lf[efd->total++] = *lf;
1572 return 1;
1575 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1577 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1579 if (type != TRUETYPE_FONTTYPE) return 1;
1581 if (efd->total < MAX_ENUM_FONTS)
1582 efd->lf[efd->total++] = *lf;
1584 return 1;
1587 static void get_charset_stats(struct enum_font_data *efd,
1588 int *ansi_charset, int *symbol_charset,
1589 int *russian_charset)
1591 int i;
1593 *ansi_charset = 0;
1594 *symbol_charset = 0;
1595 *russian_charset = 0;
1597 for (i = 0; i < efd->total; i++)
1599 switch (efd->lf[i].lfCharSet)
1601 case ANSI_CHARSET:
1602 (*ansi_charset)++;
1603 break;
1604 case SYMBOL_CHARSET:
1605 (*symbol_charset)++;
1606 break;
1607 case RUSSIAN_CHARSET:
1608 (*russian_charset)++;
1609 break;
1614 static void get_charset_statsW(struct enum_font_dataW *efd,
1615 int *ansi_charset, int *symbol_charset,
1616 int *russian_charset)
1618 int i;
1620 *ansi_charset = 0;
1621 *symbol_charset = 0;
1622 *russian_charset = 0;
1624 for (i = 0; i < efd->total; i++)
1626 switch (efd->lf[i].lfCharSet)
1628 case ANSI_CHARSET:
1629 (*ansi_charset)++;
1630 break;
1631 case SYMBOL_CHARSET:
1632 (*symbol_charset)++;
1633 break;
1634 case RUSSIAN_CHARSET:
1635 (*russian_charset)++;
1636 break;
1641 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1643 struct enum_font_data efd;
1644 struct enum_font_dataW efdw;
1645 LOGFONT lf;
1646 HDC hdc;
1647 int i, ret, ansi_charset, symbol_charset, russian_charset;
1649 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1651 if (*font_name && !is_truetype_font_installed(font_name))
1653 skip("%s is not installed\n", font_name);
1654 return;
1657 hdc = GetDC(0);
1659 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1660 * while EnumFontFamiliesEx doesn't.
1662 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1665 * Use EnumFontFamiliesW since win98 crashes when the
1666 * second parameter is NULL using EnumFontFamilies
1668 efd.total = 0;
1669 SetLastError(0xdeadbeef);
1670 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1671 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1672 if(ret)
1674 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1675 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1676 ansi_charset, symbol_charset, russian_charset);
1677 ok(efd.total == 0, "fonts enumerated: NULL\n");
1678 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1679 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1680 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1683 efd.total = 0;
1684 SetLastError(0xdeadbeef);
1685 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1686 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1687 if(ret)
1689 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1690 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1691 ansi_charset, symbol_charset, russian_charset);
1692 ok(efd.total == 0, "fonts enumerated: NULL\n");
1693 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1694 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1695 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1699 efd.total = 0;
1700 SetLastError(0xdeadbeef);
1701 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1702 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1703 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1704 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1705 ansi_charset, symbol_charset, russian_charset,
1706 *font_name ? font_name : "<empty>");
1707 if (*font_name)
1708 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1709 else
1710 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1711 for (i = 0; i < efd.total; i++)
1713 /* FIXME: remove completely once Wine is fixed */
1714 if (efd.lf[i].lfCharSet != font_charset)
1716 todo_wine
1717 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1719 else
1720 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1721 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1722 font_name, efd.lf[i].lfFaceName);
1725 memset(&lf, 0, sizeof(lf));
1726 lf.lfCharSet = ANSI_CHARSET;
1727 lstrcpy(lf.lfFaceName, font_name);
1728 efd.total = 0;
1729 SetLastError(0xdeadbeef);
1730 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1731 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1732 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1733 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1734 ansi_charset, symbol_charset, russian_charset,
1735 *font_name ? font_name : "<empty>");
1736 if (font_charset == SYMBOL_CHARSET)
1738 if (*font_name)
1739 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1740 else
1741 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1743 else
1745 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1746 for (i = 0; i < efd.total; i++)
1748 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1749 if (*font_name)
1750 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1751 font_name, efd.lf[i].lfFaceName);
1755 /* DEFAULT_CHARSET should enumerate all available charsets */
1756 memset(&lf, 0, sizeof(lf));
1757 lf.lfCharSet = DEFAULT_CHARSET;
1758 lstrcpy(lf.lfFaceName, font_name);
1759 efd.total = 0;
1760 SetLastError(0xdeadbeef);
1761 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1762 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1763 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1764 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1765 ansi_charset, symbol_charset, russian_charset,
1766 *font_name ? font_name : "<empty>");
1767 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1768 for (i = 0; i < efd.total; i++)
1770 if (*font_name)
1771 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1772 font_name, efd.lf[i].lfFaceName);
1774 if (*font_name)
1776 switch (font_charset)
1778 case ANSI_CHARSET:
1779 ok(ansi_charset > 0,
1780 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1781 ok(!symbol_charset,
1782 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1783 ok(russian_charset > 0,
1784 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1785 break;
1786 case SYMBOL_CHARSET:
1787 ok(!ansi_charset,
1788 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1789 ok(symbol_charset,
1790 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1791 ok(!russian_charset,
1792 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1793 break;
1794 case DEFAULT_CHARSET:
1795 ok(ansi_charset > 0,
1796 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1797 ok(symbol_charset > 0,
1798 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1799 ok(russian_charset > 0,
1800 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1801 break;
1804 else
1806 ok(ansi_charset > 0,
1807 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1808 ok(symbol_charset > 0,
1809 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1810 ok(russian_charset > 0,
1811 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1814 memset(&lf, 0, sizeof(lf));
1815 lf.lfCharSet = SYMBOL_CHARSET;
1816 lstrcpy(lf.lfFaceName, font_name);
1817 efd.total = 0;
1818 SetLastError(0xdeadbeef);
1819 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1820 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1821 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1822 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1823 ansi_charset, symbol_charset, russian_charset,
1824 *font_name ? font_name : "<empty>");
1825 if (*font_name && font_charset == ANSI_CHARSET)
1826 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1827 else
1829 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1830 for (i = 0; i < efd.total; i++)
1832 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1833 if (*font_name)
1834 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1835 font_name, efd.lf[i].lfFaceName);
1838 ok(!ansi_charset,
1839 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1840 ok(symbol_charset > 0,
1841 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1842 ok(!russian_charset,
1843 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1846 ReleaseDC(0, hdc);
1849 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1851 HFONT hfont, hfont_prev;
1852 DWORD ret;
1853 GLYPHMETRICS gm1, gm2;
1854 LOGFONTA lf2 = *lf;
1855 WORD idx;
1856 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1858 if(!pGetGlyphIndicesA)
1860 skip("GetGlyphIndicesA is unavailable\n");
1861 return;
1864 /* negative widths are handled just as positive ones */
1865 lf2.lfWidth = -lf->lfWidth;
1867 SetLastError(0xdeadbeef);
1868 hfont = CreateFontIndirectA(lf);
1869 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1870 check_font("original", lf, hfont);
1872 hfont_prev = SelectObject(hdc, hfont);
1874 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1875 if (ret == GDI_ERROR || idx == 0xffff)
1877 SelectObject(hdc, hfont_prev);
1878 DeleteObject(hfont);
1879 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1880 return;
1883 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1884 memset(&gm1, 0xab, sizeof(gm1));
1885 SetLastError(0xdeadbeef);
1886 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1887 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1889 SelectObject(hdc, hfont_prev);
1890 DeleteObject(hfont);
1892 SetLastError(0xdeadbeef);
1893 hfont = CreateFontIndirectA(&lf2);
1894 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1895 check_font("negative width", &lf2, hfont);
1897 hfont_prev = SelectObject(hdc, hfont);
1899 memset(&gm2, 0xbb, sizeof(gm2));
1900 SetLastError(0xdeadbeef);
1901 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1902 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1904 SelectObject(hdc, hfont_prev);
1905 DeleteObject(hfont);
1907 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1908 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1909 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1910 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1911 gm1.gmCellIncX == gm2.gmCellIncX &&
1912 gm1.gmCellIncY == gm2.gmCellIncY,
1913 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1914 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1915 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1916 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1917 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1920 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1921 #include "pshpack2.h"
1922 typedef struct
1924 USHORT version;
1925 SHORT xAvgCharWidth;
1926 USHORT usWeightClass;
1927 USHORT usWidthClass;
1928 SHORT fsType;
1929 SHORT ySubscriptXSize;
1930 SHORT ySubscriptYSize;
1931 SHORT ySubscriptXOffset;
1932 SHORT ySubscriptYOffset;
1933 SHORT ySuperscriptXSize;
1934 SHORT ySuperscriptYSize;
1935 SHORT ySuperscriptXOffset;
1936 SHORT ySuperscriptYOffset;
1937 SHORT yStrikeoutSize;
1938 SHORT yStrikeoutPosition;
1939 SHORT sFamilyClass;
1940 PANOSE panose;
1941 ULONG ulUnicodeRange1;
1942 ULONG ulUnicodeRange2;
1943 ULONG ulUnicodeRange3;
1944 ULONG ulUnicodeRange4;
1945 CHAR achVendID[4];
1946 USHORT fsSelection;
1947 USHORT usFirstCharIndex;
1948 USHORT usLastCharIndex;
1949 /* According to the Apple spec, original version didn't have the below fields,
1950 * version numbers were taked from the OpenType spec.
1952 /* version 0 (TrueType 1.5) */
1953 USHORT sTypoAscender;
1954 USHORT sTypoDescender;
1955 USHORT sTypoLineGap;
1956 USHORT usWinAscent;
1957 USHORT usWinDescent;
1958 /* version 1 (TrueType 1.66) */
1959 ULONG ulCodePageRange1;
1960 ULONG ulCodePageRange2;
1961 /* version 2 (OpenType 1.2) */
1962 SHORT sxHeight;
1963 SHORT sCapHeight;
1964 USHORT usDefaultChar;
1965 USHORT usBreakChar;
1966 USHORT usMaxContext;
1967 } TT_OS2_V2;
1968 #include "poppack.h"
1970 #ifdef WORDS_BIGENDIAN
1971 #define GET_BE_WORD(x) (x)
1972 #else
1973 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1974 #endif
1976 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1977 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1978 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1979 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1981 static void test_text_metrics(const LOGFONTA *lf)
1983 HDC hdc;
1984 HFONT hfont, hfont_old;
1985 TEXTMETRICA tmA;
1986 TEXTMETRICW tmW;
1987 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1988 INT test_char;
1989 TT_OS2_V2 tt_os2;
1990 USHORT version;
1991 LONG size, ret;
1992 const char *font_name = lf->lfFaceName;
1994 hdc = GetDC(0);
1996 SetLastError(0xdeadbeef);
1997 hfont = CreateFontIndirectA(lf);
1998 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2000 hfont_old = SelectObject(hdc, hfont);
2002 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2003 if (size == GDI_ERROR)
2005 trace("OS/2 chunk was not found\n");
2006 goto end_of_test;
2008 if (size > sizeof(tt_os2))
2010 trace("got too large OS/2 chunk of size %u\n", size);
2011 size = sizeof(tt_os2);
2014 memset(&tt_os2, 0, sizeof(tt_os2));
2015 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2016 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2018 version = GET_BE_WORD(tt_os2.version);
2020 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2021 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2022 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2023 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2025 trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
2026 font_name, lf->lfCharSet, first_unicode_char, last_unicode_char, default_char, break_char,
2027 version, (LPCSTR)&tt_os2.achVendID);
2029 SetLastError(0xdeadbeef);
2030 ret = GetTextMetricsA(hdc, &tmA);
2031 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2033 #if 0 /* FIXME: This doesn't appear to be what Windows does */
2034 test_char = min(first_unicode_char - 1, 255);
2035 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
2036 font_name, tmA.tmFirstChar, test_char);
2037 #endif
2038 if (lf->lfCharSet == SYMBOL_CHARSET)
2040 test_char = min(last_unicode_char - 0xf000, 255);
2041 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2042 font_name, tmA.tmLastChar, test_char);
2044 else
2046 test_char = min(last_unicode_char, 255);
2047 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2048 font_name, tmA.tmLastChar, test_char);
2051 SetLastError(0xdeadbeef);
2052 ret = GetTextMetricsW(hdc, &tmW);
2053 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2054 "GetTextMetricsW error %u\n", GetLastError());
2055 if (ret)
2057 trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
2058 tmW.tmFirstChar, tmW.tmLastChar, tmA.tmFirstChar, tmA.tmLastChar,
2059 tmW.tmDefaultChar, tmA.tmDefaultChar, tmW.tmBreakChar, tmA.tmBreakChar);
2061 if (lf->lfCharSet == SYMBOL_CHARSET)
2063 /* It appears that for fonts with SYMBOL_CHARSET Windows always
2064 * sets symbol range to 0 - f0ff
2066 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
2067 font_name, tmW.tmFirstChar);
2068 /* FIXME: Windows returns f0ff here, while Wine f0xx */
2069 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
2070 font_name, tmW.tmLastChar);
2072 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
2073 font_name, tmW.tmDefaultChar);
2074 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
2075 font_name, tmW.tmBreakChar);
2077 else
2079 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
2080 font_name, tmW.tmFirstChar, first_unicode_char);
2081 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
2082 font_name, tmW.tmLastChar, last_unicode_char);
2084 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2085 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2086 tmW.tmDigitizedAspectX, ret);
2087 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2088 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2089 tmW.tmDigitizedAspectX, ret);
2092 test_negative_width(hdc, lf);
2094 end_of_test:
2095 SelectObject(hdc, hfont_old);
2096 DeleteObject(hfont);
2098 ReleaseDC(0, hdc);
2101 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2103 INT *enumed = (INT *)lParam;
2105 if (type == TRUETYPE_FONTTYPE)
2107 (*enumed)++;
2108 test_text_metrics(lf);
2110 return 1;
2113 static void test_GetTextMetrics(void)
2115 LOGFONTA lf;
2116 HDC hdc;
2117 INT enumed;
2119 hdc = GetDC(0);
2121 memset(&lf, 0, sizeof(lf));
2122 lf.lfCharSet = DEFAULT_CHARSET;
2123 enumed = 0;
2124 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2125 trace("Tested metrics of %d truetype fonts\n", enumed);
2127 ReleaseDC(0, hdc);
2130 static void test_nonexistent_font(void)
2132 static const struct
2134 const char *name;
2135 int charset;
2136 } font_subst[] =
2138 { "Times New Roman Baltic", 186 },
2139 { "Times New Roman CE", 238 },
2140 { "Times New Roman CYR", 204 },
2141 { "Times New Roman Greek", 161 },
2142 { "Times New Roman TUR", 162 }
2144 LOGFONTA lf;
2145 HDC hdc;
2146 HFONT hfont;
2147 CHARSETINFO csi;
2148 INT cs, expected_cs, i;
2149 char buf[LF_FACESIZE];
2151 if (!is_truetype_font_installed("Arial") ||
2152 !is_truetype_font_installed("Times New Roman"))
2154 skip("Arial or Times New Roman not installed\n");
2155 return;
2158 expected_cs = GetACP();
2159 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2161 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2162 return;
2164 expected_cs = csi.ciCharset;
2165 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2167 hdc = GetDC(0);
2169 memset(&lf, 0, sizeof(lf));
2170 lf.lfHeight = 100;
2171 lf.lfWeight = FW_REGULAR;
2172 lf.lfCharSet = ANSI_CHARSET;
2173 lf.lfPitchAndFamily = FF_SWISS;
2174 strcpy(lf.lfFaceName, "Nonexistent font");
2175 hfont = CreateFontIndirectA(&lf);
2176 hfont = SelectObject(hdc, hfont);
2177 GetTextFaceA(hdc, sizeof(buf), buf);
2178 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2179 cs = GetTextCharset(hdc);
2180 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2181 DeleteObject(SelectObject(hdc, hfont));
2183 memset(&lf, 0, sizeof(lf));
2184 lf.lfHeight = -13;
2185 lf.lfWeight = FW_DONTCARE;
2186 strcpy(lf.lfFaceName, "Nonexistent font");
2187 hfont = CreateFontIndirectA(&lf);
2188 hfont = SelectObject(hdc, hfont);
2189 GetTextFaceA(hdc, sizeof(buf), buf);
2190 todo_wine /* Wine uses Arial for all substitutions */
2191 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2192 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2193 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2194 "Got %s\n", buf);
2195 cs = GetTextCharset(hdc);
2196 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2197 DeleteObject(SelectObject(hdc, hfont));
2199 memset(&lf, 0, sizeof(lf));
2200 lf.lfHeight = -13;
2201 lf.lfWeight = FW_REGULAR;
2202 strcpy(lf.lfFaceName, "Nonexistent font");
2203 hfont = CreateFontIndirectA(&lf);
2204 hfont = SelectObject(hdc, hfont);
2205 GetTextFaceA(hdc, sizeof(buf), buf);
2206 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2207 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2208 cs = GetTextCharset(hdc);
2209 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2210 DeleteObject(SelectObject(hdc, hfont));
2212 memset(&lf, 0, sizeof(lf));
2213 lf.lfHeight = -13;
2214 lf.lfWeight = FW_DONTCARE;
2215 strcpy(lf.lfFaceName, "Times New Roman");
2216 hfont = CreateFontIndirectA(&lf);
2217 hfont = SelectObject(hdc, hfont);
2218 GetTextFaceA(hdc, sizeof(buf), buf);
2219 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2220 cs = GetTextCharset(hdc);
2221 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2222 DeleteObject(SelectObject(hdc, hfont));
2224 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2226 memset(&lf, 0, sizeof(lf));
2227 lf.lfHeight = -13;
2228 lf.lfWeight = FW_REGULAR;
2229 strcpy(lf.lfFaceName, font_subst[i].name);
2230 hfont = CreateFontIndirectA(&lf);
2231 hfont = SelectObject(hdc, hfont);
2232 cs = GetTextCharset(hdc);
2233 if (font_subst[i].charset == expected_cs)
2235 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2236 GetTextFaceA(hdc, sizeof(buf), buf);
2237 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2239 else
2241 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2242 GetTextFaceA(hdc, sizeof(buf), buf);
2243 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2244 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2246 DeleteObject(SelectObject(hdc, hfont));
2248 memset(&lf, 0, sizeof(lf));
2249 lf.lfHeight = -13;
2250 lf.lfWeight = FW_DONTCARE;
2251 strcpy(lf.lfFaceName, font_subst[i].name);
2252 hfont = CreateFontIndirectA(&lf);
2253 hfont = SelectObject(hdc, hfont);
2254 GetTextFaceA(hdc, sizeof(buf), buf);
2255 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2256 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2257 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2258 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2259 "got %s\n", buf);
2260 cs = GetTextCharset(hdc);
2261 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2262 DeleteObject(SelectObject(hdc, hfont));
2265 ReleaseDC(0, hdc);
2268 static void test_GdiRealizationInfo(void)
2270 HDC hdc;
2271 DWORD info[4];
2272 BOOL r;
2273 HFONT hfont, hfont_old;
2274 LOGFONTA lf;
2276 if(!pGdiRealizationInfo)
2278 skip("GdiRealizationInfo not available\n");
2279 return;
2282 hdc = GetDC(0);
2284 memset(info, 0xcc, sizeof(info));
2285 r = pGdiRealizationInfo(hdc, info);
2286 ok(r != 0, "ret 0\n");
2287 ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
2288 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2290 if (!is_truetype_font_installed("Arial"))
2292 skip("skipping GdiRealizationInfo with truetype font\n");
2293 goto end;
2296 memset(&lf, 0, sizeof(lf));
2297 strcpy(lf.lfFaceName, "Arial");
2298 lf.lfHeight = 20;
2299 lf.lfWeight = FW_NORMAL;
2300 hfont = CreateFontIndirectA(&lf);
2301 hfont_old = SelectObject(hdc, hfont);
2303 memset(info, 0xcc, sizeof(info));
2304 r = pGdiRealizationInfo(hdc, info);
2305 ok(r != 0, "ret 0\n");
2306 ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
2307 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2309 DeleteObject(SelectObject(hdc, hfont_old));
2311 end:
2312 ReleaseDC(0, hdc);
2315 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2316 the nul in the count of characters copied when the face name buffer is not
2317 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2318 always includes it. */
2319 static void test_GetTextFace(void)
2321 static const char faceA[] = "Tahoma";
2322 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2323 LOGFONTA fA = {0};
2324 LOGFONTW fW = {0};
2325 char bufA[LF_FACESIZE];
2326 WCHAR bufW[LF_FACESIZE];
2327 HFONT f, g;
2328 HDC dc;
2329 int n;
2331 /* 'A' case. */
2332 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2333 f = CreateFontIndirectA(&fA);
2334 ok(f != NULL, "CreateFontIndirectA failed\n");
2336 dc = GetDC(NULL);
2337 g = SelectObject(dc, f);
2338 n = GetTextFaceA(dc, sizeof bufA, bufA);
2339 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2340 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2342 /* Play with the count arg. */
2343 bufA[0] = 'x';
2344 n = GetTextFaceA(dc, 0, bufA);
2345 ok(n == 0, "GetTextFaceA returned %d\n", n);
2346 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2348 bufA[0] = 'x';
2349 n = GetTextFaceA(dc, 1, bufA);
2350 ok(n == 0, "GetTextFaceA returned %d\n", n);
2351 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2353 bufA[0] = 'x'; bufA[1] = 'y';
2354 n = GetTextFaceA(dc, 2, bufA);
2355 ok(n == 1, "GetTextFaceA returned %d\n", n);
2356 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2358 n = GetTextFaceA(dc, 0, NULL);
2359 ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
2361 DeleteObject(SelectObject(dc, g));
2362 ReleaseDC(NULL, dc);
2364 /* 'W' case. */
2365 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2366 f = CreateFontIndirectW(&fW);
2367 ok(f != NULL, "CreateFontIndirectW failed\n");
2369 dc = GetDC(NULL);
2370 g = SelectObject(dc, f);
2371 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2372 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2373 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2375 /* Play with the count arg. */
2376 bufW[0] = 'x';
2377 n = GetTextFaceW(dc, 0, bufW);
2378 ok(n == 0, "GetTextFaceW returned %d\n", n);
2379 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2381 bufW[0] = 'x';
2382 n = GetTextFaceW(dc, 1, bufW);
2383 ok(n == 1, "GetTextFaceW returned %d\n", n);
2384 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2386 bufW[0] = 'x'; bufW[1] = 'y';
2387 n = GetTextFaceW(dc, 2, bufW);
2388 ok(n == 2, "GetTextFaceW returned %d\n", n);
2389 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2391 n = GetTextFaceW(dc, 0, NULL);
2392 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2394 DeleteObject(SelectObject(dc, g));
2395 ReleaseDC(NULL, dc);
2398 static void test_orientation(void)
2400 static const char test_str[11] = "Test String";
2401 HDC hdc;
2402 LOGFONTA lf;
2403 HFONT hfont, old_hfont;
2404 SIZE size;
2406 if (!is_truetype_font_installed("Arial"))
2408 skip("Arial is not installed\n");
2409 return;
2412 hdc = CreateCompatibleDC(0);
2413 memset(&lf, 0, sizeof(lf));
2414 lstrcpyA(lf.lfFaceName, "Arial");
2415 lf.lfHeight = 72;
2416 lf.lfOrientation = lf.lfEscapement = 900;
2417 hfont = create_font("orientation", &lf);
2418 old_hfont = SelectObject(hdc, hfont);
2419 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2420 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2421 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2422 SelectObject(hdc, old_hfont);
2423 DeleteObject(hfont);
2424 DeleteDC(hdc);
2427 START_TEST(font)
2429 init();
2431 test_logfont();
2432 test_bitmap_font();
2433 test_outline_font();
2434 test_bitmap_font_metrics();
2435 test_GdiGetCharDimensions();
2436 test_GetCharABCWidths();
2437 test_text_extents();
2438 test_GetGlyphIndices();
2439 test_GetKerningPairs();
2440 test_GetOutlineTextMetrics();
2441 test_SetTextJustification();
2442 test_font_charset();
2443 test_GetFontUnicodeRanges();
2444 test_nonexistent_font();
2445 test_orientation();
2447 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2448 * I'd like to avoid them in this test.
2450 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2451 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2452 if (is_truetype_font_installed("Arial Black") &&
2453 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2455 test_EnumFontFamilies("", ANSI_CHARSET);
2456 test_EnumFontFamilies("", SYMBOL_CHARSET);
2457 test_EnumFontFamilies("", DEFAULT_CHARSET);
2459 else
2460 skip("Arial Black or Symbol/Wingdings is not installed\n");
2461 test_GetTextMetrics();
2462 test_GdiRealizationInfo();
2463 test_GetTextFace();