gdi32: Fix two tests that fail for all platforms.
[wine.git] / dlls / gdi32 / tests / font.c
blob8769b2fa165d877e99eca8cb65798f72698da96c
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 if (!SetGraphicsMode(hdc, GM_ADVANCED))
458 DeleteObject(hfont);
459 DeleteDC(hdc);
460 skip("GM_ADVANCED is not supported on this platform\n");
461 return;
464 xform.eM11 = 20.0f;
465 xform.eM12 = 0.0f;
466 xform.eM21 = 0.0f;
467 xform.eM22 = 20.0f;
468 xform.eDx = 0.0f;
469 xform.eDy = 0.0f;
471 SetLastError(0xdeadbeef);
472 ret = SetWorldTransform(hdc, &xform);
473 ok(ret, "SetWorldTransform error %u\n", GetLastError());
475 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
477 old_hfont = SelectObject(hdc, hfont);
478 /* with an identity matrix */
479 memset(&gm, 0, sizeof(gm));
480 SetLastError(0xdeadbeef);
481 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
482 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
483 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
484 pt.x = width_orig; pt.y = 0;
485 LPtoDP(hdc, &pt, 1);
486 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
487 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
488 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
489 /* with a custom matrix */
490 memset(&gm, 0, sizeof(gm));
491 SetLastError(0xdeadbeef);
492 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
493 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
495 pt.x = width_orig; pt.y = 0;
496 LPtoDP(hdc, &pt, 1);
497 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
498 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
499 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
500 SelectObject(hdc, old_hfont);
502 SetLastError(0xdeadbeef);
503 ret = SetMapMode(hdc, MM_LOMETRIC);
504 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
506 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
508 old_hfont = SelectObject(hdc, hfont);
509 /* with an identity matrix */
510 memset(&gm, 0, sizeof(gm));
511 SetLastError(0xdeadbeef);
512 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
513 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
514 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
515 pt.x = width_orig; pt.y = 0;
516 LPtoDP(hdc, &pt, 1);
517 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
518 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
519 /* with a custom matrix */
520 memset(&gm, 0, sizeof(gm));
521 SetLastError(0xdeadbeef);
522 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
523 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
524 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
525 pt.x = width_orig; pt.y = 0;
526 LPtoDP(hdc, &pt, 1);
527 ok(gm.gmCellIncX == (pt.x + 1)/2, "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
528 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
529 SelectObject(hdc, old_hfont);
531 SetLastError(0xdeadbeef);
532 ret = SetMapMode(hdc, MM_TEXT);
533 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
535 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
537 old_hfont = SelectObject(hdc, hfont);
538 /* with an identity matrix */
539 memset(&gm, 0, sizeof(gm));
540 SetLastError(0xdeadbeef);
541 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
542 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
543 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
544 pt.x = width_orig; pt.y = 0;
545 LPtoDP(hdc, &pt, 1);
546 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
547 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
548 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
549 /* with a custom matrix */
550 memset(&gm, 0, sizeof(gm));
551 SetLastError(0xdeadbeef);
552 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
553 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
554 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
555 pt.x = width_orig; pt.y = 0;
556 LPtoDP(hdc, &pt, 1);
557 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
558 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
559 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
560 SelectObject(hdc, old_hfont);
562 DeleteObject(hfont);
563 DeleteDC(hdc);
566 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
568 LOGFONT *lf = (LOGFONT *)lParam;
570 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
572 *lf = *elf;
573 return 0; /* stop enumeration */
575 return 1; /* continue enumeration */
578 static void test_bitmap_font_metrics(void)
580 static const struct font_data
582 const char face_name[LF_FACESIZE];
583 int weight, height, ascent, descent, int_leading, ext_leading;
584 int ave_char_width, max_char_width;
585 DWORD ansi_bitfield;
586 } fd[] =
588 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
589 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
590 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
591 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
592 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
593 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
594 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
595 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
596 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
597 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
598 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
599 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
600 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
601 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
602 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
603 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
604 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
605 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
606 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
607 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
608 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
609 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
610 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
611 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
612 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
613 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
614 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
615 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
616 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
617 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
618 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
619 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
620 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
622 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
623 * require a new system.sfd for that font
625 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
626 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
627 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
628 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
629 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
630 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
631 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
632 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
633 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
634 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
635 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
636 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
637 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
638 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
639 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
640 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
641 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
642 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
643 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
644 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
645 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
647 /* FIXME: add "Terminal" */
649 HDC hdc;
650 LOGFONT lf;
651 HFONT hfont, old_hfont;
652 TEXTMETRIC tm;
653 INT ret, i;
655 hdc = CreateCompatibleDC(0);
656 assert(hdc);
658 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
660 int bit;
662 memset(&lf, 0, sizeof(lf));
664 lf.lfHeight = fd[i].height;
665 strcpy(lf.lfFaceName, fd[i].face_name);
667 for(bit = 0; bit < 32; bit++)
669 DWORD fs[2];
670 CHARSETINFO csi;
672 fs[0] = 1L << bit;
673 fs[1] = 0;
674 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
675 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
677 lf.lfCharSet = csi.ciCharset;
678 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
679 if (ret) continue;
681 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
683 hfont = create_font(lf.lfFaceName, &lf);
684 old_hfont = SelectObject(hdc, hfont);
685 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
687 ok(tm.tmWeight == fd[i].weight, "%s(%d): tm.tmWeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmWeight, fd[i].weight);
688 ok(tm.tmHeight == fd[i].height, "%s(%d): tm.tmHeight %d != %d\n", fd[i].face_name, fd[i].height, tm.tmHeight, fd[i].height);
689 ok(tm.tmAscent == fd[i].ascent, "%s(%d): tm.tmAscent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAscent, fd[i].ascent);
690 ok(tm.tmDescent == fd[i].descent, "%s(%d): tm.tmDescent %d != %d\n", fd[i].face_name, fd[i].height, tm.tmDescent, fd[i].descent);
691 ok(tm.tmInternalLeading == fd[i].int_leading, "%s(%d): tm.tmInternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmInternalLeading, fd[i].int_leading);
692 ok(tm.tmExternalLeading == fd[i].ext_leading, "%s(%d): tm.tmExternalLeading %d != %d\n", fd[i].face_name, fd[i].height, tm.tmExternalLeading, fd[i].ext_leading);
693 ok(tm.tmAveCharWidth == fd[i].ave_char_width, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmAveCharWidth, fd[i].ave_char_width);
695 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
696 that make the max width bigger */
697 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
698 ok(tm.tmMaxCharWidth == fd[i].max_char_width, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd[i].face_name, fd[i].height, tm.tmMaxCharWidth, fd[i].max_char_width);
700 SelectObject(hdc, old_hfont);
701 DeleteObject(hfont);
705 DeleteDC(hdc);
708 static void test_GdiGetCharDimensions(void)
710 HDC hdc;
711 TEXTMETRICW tm;
712 LONG ret;
713 SIZE size;
714 LONG avgwidth, height;
715 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
717 if (!pGdiGetCharDimensions)
719 skip("GdiGetCharDimensions not available on this platform\n");
720 return;
723 hdc = CreateCompatibleDC(NULL);
725 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
726 avgwidth = ((size.cx / 26) + 1) / 2;
728 ret = pGdiGetCharDimensions(hdc, &tm, &height);
729 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
730 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
732 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
733 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
735 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
736 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
738 height = 0;
739 ret = pGdiGetCharDimensions(hdc, NULL, &height);
740 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
741 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
743 DeleteDC(hdc);
746 static void test_GetCharABCWidths(void)
748 static const WCHAR str[] = {'a',0};
749 BOOL ret;
750 HDC hdc;
751 LOGFONTA lf;
752 HFONT hfont;
753 ABC abc[1];
754 WORD glyphs[1];
755 DWORD nb;
757 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
759 skip("GetCharABCWidthsW/I not available on this platform\n");
760 return;
763 memset(&lf, 0, sizeof(lf));
764 strcpy(lf.lfFaceName, "System");
765 lf.lfHeight = 20;
767 hfont = CreateFontIndirectA(&lf);
768 hdc = GetDC(0);
769 hfont = SelectObject(hdc, hfont);
771 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
772 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
774 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
775 ok(!ret, "GetCharABCWidthsI should have failed\n");
777 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
778 ok(!ret, "GetCharABCWidthsI should have failed\n");
780 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
781 ok(ret, "GetCharABCWidthsI should have succeeded\n");
783 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
784 ok(!ret, "GetCharABCWidthsW should have failed\n");
786 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
787 ok(!ret, "GetCharABCWidthsW should have failed\n");
789 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
790 ok(!ret, "GetCharABCWidthsW should have failed\n");
792 hfont = SelectObject(hdc, hfont);
793 DeleteObject(hfont);
794 ReleaseDC(NULL, hdc);
797 static void test_text_extents(void)
799 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
800 LPINT extents;
801 INT i, len, fit1, fit2;
802 LOGFONTA lf;
803 TEXTMETRICA tm;
804 HDC hdc;
805 HFONT hfont;
806 SIZE sz;
807 SIZE sz1, sz2;
809 memset(&lf, 0, sizeof(lf));
810 strcpy(lf.lfFaceName, "Arial");
811 lf.lfHeight = 20;
813 hfont = CreateFontIndirectA(&lf);
814 hdc = GetDC(0);
815 hfont = SelectObject(hdc, hfont);
816 GetTextMetricsA(hdc, &tm);
817 GetTextExtentPointA(hdc, "o", 1, &sz);
818 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
820 SetLastError(0xdeadbeef);
821 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
822 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
824 skip("Skipping remainder of text extents test on a Win9x platform\n");
825 hfont = SelectObject(hdc, hfont);
826 DeleteObject(hfont);
827 ReleaseDC(0, hdc);
828 return;
831 len = lstrlenW(wt);
832 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
833 extents[0] = 1; /* So that the increasing sequence test will fail
834 if the extents array is untouched. */
835 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
836 GetTextExtentPointW(hdc, wt, len, &sz2);
837 ok(sz1.cy == sz2.cy,
838 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
839 /* Because of the '\n' in the string GetTextExtentExPoint and
840 GetTextExtentPoint return different widths under Win2k, but
841 under WinXP they return the same width. So we don't test that
842 here. */
844 for (i = 1; i < len; ++i)
845 ok(extents[i-1] <= extents[i],
846 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
848 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
849 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
850 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
851 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
852 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
853 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
854 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
855 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
856 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
857 ok(extents[0] == extents[2] && extents[1] == extents[3],
858 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
859 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
860 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
861 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
862 HeapFree(GetProcessHeap(), 0, extents);
864 hfont = SelectObject(hdc, hfont);
865 DeleteObject(hfont);
866 ReleaseDC(NULL, hdc);
869 static void test_GetGlyphIndices(void)
871 HDC hdc;
872 HFONT hfont;
873 DWORD charcount;
874 LOGFONTA lf;
875 DWORD flags = 0;
876 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
877 WORD glyphs[(sizeof(testtext)/2)-1];
878 TEXTMETRIC textm;
879 HFONT hOldFont;
881 if (!pGetGlyphIndicesW) {
882 skip("GetGlyphIndicesW not available on platform\n");
883 return;
886 hdc = GetDC(0);
888 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
889 flags |= GGI_MARK_NONEXISTING_GLYPHS;
890 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
891 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
892 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
893 flags = 0;
894 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
895 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
896 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
897 textm.tmDefaultChar, glyphs[4]);
899 if(!is_font_installed("Tahoma"))
901 skip("Tahoma is not installed so skipping this test\n");
902 return;
904 memset(&lf, 0, sizeof(lf));
905 strcpy(lf.lfFaceName, "Tahoma");
906 lf.lfHeight = 20;
908 hfont = CreateFontIndirectA(&lf);
909 hOldFont = SelectObject(hdc, hfont);
910 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
911 flags |= GGI_MARK_NONEXISTING_GLYPHS;
912 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
913 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
914 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
915 flags = 0;
916 testtext[0] = textm.tmDefaultChar;
917 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
918 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
919 todo_wine ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
920 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
921 DeleteObject(SelectObject(hdc, hOldFont));
924 static void test_GetKerningPairs(void)
926 static const struct kerning_data
928 const char face_name[LF_FACESIZE];
929 LONG height;
930 /* some interesting fields from OUTLINETEXTMETRIC */
931 LONG tmHeight, tmAscent, tmDescent;
932 UINT otmEMSquare;
933 INT otmAscent;
934 INT otmDescent;
935 UINT otmLineGap;
936 UINT otmsCapEmHeight;
937 UINT otmsXHeight;
938 INT otmMacAscent;
939 INT otmMacDescent;
940 UINT otmMacLineGap;
941 UINT otmusMinimumPPEM;
942 /* small subset of kerning pairs to test */
943 DWORD total_kern_pairs;
944 const KERNINGPAIR kern_pair[26];
945 } kd[] =
947 {"Arial", 12, 12, 9, 3,
948 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
951 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
952 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
953 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
954 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
955 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
956 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
957 {933,970,+1},{933,972,-1}
960 {"Arial", -34, 39, 32, 7,
961 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
964 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
965 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
966 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
967 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
968 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
969 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
970 {933,970,+2},{933,972,-3}
973 { "Arial", 120, 120, 97, 23,
974 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
977 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
978 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
979 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
980 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
981 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
982 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
983 {933,970,+6},{933,972,-10}
986 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
987 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
988 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
991 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
992 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
993 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
994 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
995 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
996 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
997 {933,970,+54},{933,972,-83}
1000 #endif
1002 LOGFONT lf;
1003 HFONT hfont, hfont_old;
1004 KERNINGPAIR *kern_pair;
1005 HDC hdc;
1006 DWORD total_kern_pairs, ret, i, n, matches;
1008 hdc = GetDC(0);
1010 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1011 * which may render this test unusable, so we're trying to avoid that.
1013 SetLastError(0xdeadbeef);
1014 GetKerningPairsW(hdc, 0, NULL);
1015 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1017 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1018 ReleaseDC(0, hdc);
1019 return;
1022 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1024 OUTLINETEXTMETRICW otm;
1026 if (!is_font_installed(kd[i].face_name))
1028 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1029 continue;
1032 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1034 memset(&lf, 0, sizeof(lf));
1035 strcpy(lf.lfFaceName, kd[i].face_name);
1036 lf.lfHeight = kd[i].height;
1037 hfont = CreateFontIndirect(&lf);
1038 assert(hfont != 0);
1040 hfont_old = SelectObject(hdc, hfont);
1042 SetLastError(0xdeadbeef);
1043 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1044 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1046 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1047 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1048 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1049 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1050 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1051 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1053 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1054 kd[i].otmEMSquare, otm.otmEMSquare);
1055 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1056 kd[i].otmAscent, otm.otmAscent);
1057 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1058 kd[i].otmDescent, otm.otmDescent);
1059 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1060 kd[i].otmLineGap, otm.otmLineGap);
1061 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1062 kd[i].otmMacDescent, otm.otmMacDescent);
1063 todo_wine {
1064 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1065 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1066 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1067 kd[i].otmsXHeight, otm.otmsXHeight);
1068 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1069 kd[i].otmMacAscent, otm.otmMacAscent);
1070 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1071 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1072 kd[i].otmMacLineGap, otm.otmMacLineGap);
1073 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1074 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1077 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1078 trace("total_kern_pairs %u\n", total_kern_pairs);
1079 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1081 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1082 SetLastError(0xdeadbeef);
1083 ret = GetKerningPairsW(hdc, 0, kern_pair);
1084 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1085 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1086 ok(ret == 0, "got %lu, expected 0\n", ret);
1087 #endif
1089 ret = GetKerningPairsW(hdc, 100, NULL);
1090 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1092 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1093 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1095 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1096 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1098 matches = 0;
1100 for (n = 0; n < ret; n++)
1102 DWORD j;
1103 #if 0
1104 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1105 trace("{'%c','%c',%d},\n",
1106 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1107 #endif
1108 for (j = 0; j < kd[i].total_kern_pairs; j++)
1110 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1111 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1113 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1114 "pair %d:%d got %d, expected %d\n",
1115 kern_pair[n].wFirst, kern_pair[n].wSecond,
1116 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1117 matches++;
1122 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1123 matches, kd[i].total_kern_pairs);
1125 HeapFree(GetProcessHeap(), 0, kern_pair);
1127 SelectObject(hdc, hfont_old);
1128 DeleteObject(hfont);
1131 ReleaseDC(0, hdc);
1134 static void test_GetOutlineTextMetrics(void)
1136 OUTLINETEXTMETRIC *otm;
1137 LOGFONT lf;
1138 HFONT hfont, hfont_old;
1139 HDC hdc;
1140 DWORD ret, otm_size;
1142 if (!is_font_installed("Arial"))
1144 skip("Arial is not installed\n");
1145 return;
1148 hdc = GetDC(0);
1150 memset(&lf, 0, sizeof(lf));
1151 strcpy(lf.lfFaceName, "Arial");
1152 lf.lfHeight = -13;
1153 lf.lfWeight = FW_NORMAL;
1154 lf.lfPitchAndFamily = DEFAULT_PITCH;
1155 lf.lfQuality = PROOF_QUALITY;
1156 hfont = CreateFontIndirect(&lf);
1157 assert(hfont != 0);
1159 hfont_old = SelectObject(hdc, hfont);
1160 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1161 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1163 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1165 memset(otm, 0xAA, otm_size);
1166 SetLastError(0xdeadbeef);
1167 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1168 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1169 ok(ret == 1 /* Win9x */ ||
1170 ret == otm->otmSize /* XP*/,
1171 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1172 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1174 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1175 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1176 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1177 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1180 memset(otm, 0xAA, otm_size);
1181 SetLastError(0xdeadbeef);
1182 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1183 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1184 ok(ret == 1 /* Win9x */ ||
1185 ret == otm->otmSize /* XP*/,
1186 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1187 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1189 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1190 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1191 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1192 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1195 /* ask about truncated data */
1196 memset(otm, 0xAA, otm_size);
1197 SetLastError(0xdeadbeef);
1198 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1199 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1200 ok(ret == 1 /* Win9x */ ||
1201 ret == otm->otmSize /* XP*/,
1202 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1203 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1205 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1206 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1207 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1209 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
1211 HeapFree(GetProcessHeap(), 0, otm);
1213 SelectObject(hdc, hfont_old);
1214 DeleteObject(hfont);
1216 ReleaseDC(0, hdc);
1219 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1221 INT x, y,
1222 breakCount,
1223 outputWidth = 0, /* to test TabbedTextOut() */
1224 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1225 areaWidth = clientArea->right - clientArea->left,
1226 nErrors = 0, e;
1227 BOOL lastExtent = FALSE;
1228 PSTR pFirstChar, pLastChar;
1229 SIZE size;
1230 TEXTMETRICA tm;
1231 struct err
1233 char extent[100];
1234 int GetTextExtentExPointWWidth;
1235 int TabbedTextOutWidth;
1236 } error[10];
1238 GetTextMetricsA(hdc, &tm);
1239 y = clientArea->top;
1240 do {
1241 breakCount = 0;
1242 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1243 pFirstChar = str;
1245 do {
1246 pLastChar = str;
1248 /* if not at the end of the string, ... */
1249 if (*str == '\0') break;
1250 /* ... add the next word to the current extent */
1251 while (*str != '\0' && *str++ != tm.tmBreakChar);
1252 breakCount++;
1253 SetTextJustification(hdc, 0, 0);
1254 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1255 } while ((int) size.cx < areaWidth);
1257 /* ignore trailing break chars */
1258 breakCount--;
1259 while (*(pLastChar - 1) == tm.tmBreakChar)
1261 pLastChar--;
1262 breakCount--;
1265 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1267 SetTextJustification(hdc, 0, 0);
1268 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1270 /* do not justify the last extent */
1271 if (*str != '\0' && breakCount > 0)
1273 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1274 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1275 justifiedWidth = size.cx;
1277 else lastExtent = TRUE;
1279 x = clientArea->left;
1281 outputWidth = LOWORD(TabbedTextOut(
1282 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1283 0, NULL, 0));
1284 /* catch errors and report them */
1285 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1287 memset(error[nErrors].extent, 0, 100);
1288 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1289 error[nErrors].TabbedTextOutWidth = outputWidth;
1290 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1291 nErrors++;
1294 y += size.cy;
1295 str = pLastChar;
1296 } while (*str && y < clientArea->bottom);
1298 for (e = 0; e < nErrors; e++)
1300 ok(error[e].TabbedTextOutWidth == areaWidth,
1301 "The output text (\"%s\") width should be %d, not %d.\n",
1302 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1303 /* The width returned by GetTextExtentPoint32() is exactly the same
1304 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1305 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1306 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1307 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1311 static void test_SetTextJustification(void)
1313 HDC hdc;
1314 RECT clientArea;
1315 LOGFONTA lf;
1316 HFONT hfont;
1317 HWND hwnd;
1318 static char testText[] =
1319 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1320 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1321 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1322 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1323 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1324 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1325 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1327 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1328 GetClientRect( hwnd, &clientArea );
1329 hdc = GetDC( hwnd );
1331 memset(&lf, 0, sizeof lf);
1332 lf.lfCharSet = ANSI_CHARSET;
1333 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1334 lf.lfWeight = FW_DONTCARE;
1335 lf.lfHeight = 20;
1336 lf.lfQuality = DEFAULT_QUALITY;
1337 lstrcpyA(lf.lfFaceName, "Times New Roman");
1338 hfont = create_font("Times New Roman", &lf);
1339 SelectObject(hdc, hfont);
1341 testJustification(hdc, testText, &clientArea);
1343 DeleteObject(hfont);
1344 ReleaseDC(hwnd, hdc);
1345 DestroyWindow(hwnd);
1348 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1350 HDC hdc;
1351 LOGFONTA lf;
1352 HFONT hfont, hfont_old;
1353 CHARSETINFO csi;
1354 FONTSIGNATURE fs;
1355 INT cs;
1356 DWORD i, ret;
1357 char name[64];
1359 assert(count <= 128);
1361 memset(&lf, 0, sizeof(lf));
1363 lf.lfCharSet = charset;
1364 lf.lfHeight = 10;
1365 lstrcpyA(lf.lfFaceName, "Arial");
1366 SetLastError(0xdeadbeef);
1367 hfont = CreateFontIndirectA(&lf);
1368 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1370 hdc = GetDC(0);
1371 hfont_old = SelectObject(hdc, hfont);
1373 cs = GetTextCharsetInfo(hdc, &fs, 0);
1374 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1376 SetLastError(0xdeadbeef);
1377 ret = GetTextFaceA(hdc, sizeof(name), name);
1378 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1380 if (charset == SYMBOL_CHARSET)
1382 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1383 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1385 else
1387 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1388 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1391 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1393 trace("Can't find codepage for charset %d\n", cs);
1394 ReleaseDC(0, hdc);
1395 return FALSE;
1397 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1399 if (unicode)
1401 char ansi_buf[128];
1402 WCHAR unicode_buf[128];
1404 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1406 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1408 SetLastError(0xdeadbeef);
1409 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1410 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1412 else
1414 char ansi_buf[128];
1416 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1418 SetLastError(0xdeadbeef);
1419 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1420 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1423 SelectObject(hdc, hfont_old);
1424 DeleteObject(hfont);
1426 ReleaseDC(0, hdc);
1428 return TRUE;
1431 static void test_font_charset(void)
1433 static struct charset_data
1435 INT charset;
1436 UINT code_page;
1437 WORD font_idxA[128], font_idxW[128];
1438 } cd[] =
1440 { ANSI_CHARSET, 1252 },
1441 { RUSSIAN_CHARSET, 1251 },
1442 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1444 int i;
1446 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1448 skip("Skipping the font charset test on a Win9x platform\n");
1449 return;
1452 if (!is_font_installed("Arial"))
1454 skip("Arial is not installed\n");
1455 return;
1458 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1460 if (cd[i].charset == SYMBOL_CHARSET)
1462 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1464 skip("Symbol or Wingdings is not installed\n");
1465 break;
1468 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1469 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1470 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1473 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1474 if (i > 2)
1476 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1477 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1479 else
1480 skip("Symbol or Wingdings is not installed\n");
1483 static void test_GetFontUnicodeRanges(void)
1485 LOGFONTA lf;
1486 HDC hdc;
1487 HFONT hfont, hfont_old;
1488 DWORD size;
1489 GLYPHSET *gs;
1491 if (!pGetFontUnicodeRanges)
1493 skip("GetFontUnicodeRanges not available before W2K\n");
1494 return;
1497 memset(&lf, 0, sizeof(lf));
1498 lstrcpyA(lf.lfFaceName, "Arial");
1499 hfont = create_font("Arial", &lf);
1501 hdc = GetDC(0);
1502 hfont_old = SelectObject(hdc, hfont);
1504 size = pGetFontUnicodeRanges(NULL, NULL);
1505 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1507 size = pGetFontUnicodeRanges(hdc, NULL);
1508 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1510 gs = HeapAlloc(GetProcessHeap(), 0, size);
1512 size = pGetFontUnicodeRanges(hdc, gs);
1513 ok(size, "GetFontUnicodeRanges failed\n");
1514 #if 0
1515 for (i = 0; i < gs->cRanges; i++)
1516 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1517 #endif
1518 trace("found %u ranges\n", gs->cRanges);
1520 HeapFree(GetProcessHeap(), 0, gs);
1522 SelectObject(hdc, hfont_old);
1523 DeleteObject(hfont);
1524 ReleaseDC(NULL, hdc);
1527 #define MAX_ENUM_FONTS 256
1529 struct enum_font_data
1531 int total;
1532 LOGFONT lf[MAX_ENUM_FONTS];
1535 struct enum_font_dataW
1537 int total;
1538 LOGFONTW lf[MAX_ENUM_FONTS];
1541 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1543 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1545 if (type != TRUETYPE_FONTTYPE) return 1;
1546 #if 0
1547 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1548 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1549 #endif
1550 if (efd->total < MAX_ENUM_FONTS)
1551 efd->lf[efd->total++] = *lf;
1553 return 1;
1556 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1558 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1560 if (type != TRUETYPE_FONTTYPE) return 1;
1562 if (efd->total < MAX_ENUM_FONTS)
1563 efd->lf[efd->total++] = *lf;
1565 return 1;
1568 static void get_charset_stats(struct enum_font_data *efd,
1569 int *ansi_charset, int *symbol_charset,
1570 int *russian_charset)
1572 int i;
1574 *ansi_charset = 0;
1575 *symbol_charset = 0;
1576 *russian_charset = 0;
1578 for (i = 0; i < efd->total; i++)
1580 switch (efd->lf[i].lfCharSet)
1582 case ANSI_CHARSET:
1583 (*ansi_charset)++;
1584 break;
1585 case SYMBOL_CHARSET:
1586 (*symbol_charset)++;
1587 break;
1588 case RUSSIAN_CHARSET:
1589 (*russian_charset)++;
1590 break;
1595 static void get_charset_statsW(struct enum_font_dataW *efd,
1596 int *ansi_charset, int *symbol_charset,
1597 int *russian_charset)
1599 int i;
1601 *ansi_charset = 0;
1602 *symbol_charset = 0;
1603 *russian_charset = 0;
1605 for (i = 0; i < efd->total; i++)
1607 switch (efd->lf[i].lfCharSet)
1609 case ANSI_CHARSET:
1610 (*ansi_charset)++;
1611 break;
1612 case SYMBOL_CHARSET:
1613 (*symbol_charset)++;
1614 break;
1615 case RUSSIAN_CHARSET:
1616 (*russian_charset)++;
1617 break;
1622 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1624 struct enum_font_data efd;
1625 struct enum_font_dataW efdw;
1626 LOGFONT lf;
1627 HDC hdc;
1628 int i, ret, ansi_charset, symbol_charset, russian_charset;
1630 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1632 if (*font_name && !is_truetype_font_installed(font_name))
1634 skip("%s is not installed\n", font_name);
1635 return;
1638 hdc = GetDC(0);
1640 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1641 * while EnumFontFamiliesEx doesn't.
1643 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1646 * Use EnumFontFamiliesW since win98 crashes when the
1647 * second parameter is NULL using EnumFontFamilies
1649 efd.total = 0;
1650 SetLastError(0xdeadbeef);
1651 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1652 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1653 if(ret)
1655 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1656 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1657 ansi_charset, symbol_charset, russian_charset);
1658 ok(efd.total == 0, "fonts enumerated: NULL\n");
1659 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1660 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1661 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1664 efd.total = 0;
1665 SetLastError(0xdeadbeef);
1666 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1667 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1668 if(ret)
1670 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1671 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1672 ansi_charset, symbol_charset, russian_charset);
1673 ok(efd.total == 0, "fonts enumerated: NULL\n");
1674 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1675 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1676 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1680 efd.total = 0;
1681 SetLastError(0xdeadbeef);
1682 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1683 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1684 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1685 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1686 ansi_charset, symbol_charset, russian_charset,
1687 *font_name ? font_name : "<empty>");
1688 if (*font_name)
1689 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1690 else
1691 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1692 for (i = 0; i < efd.total; i++)
1694 /* FIXME: remove completely once Wine is fixed */
1695 if (efd.lf[i].lfCharSet != font_charset)
1697 todo_wine
1698 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1700 else
1701 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1702 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1703 font_name, efd.lf[i].lfFaceName);
1706 memset(&lf, 0, sizeof(lf));
1707 lf.lfCharSet = ANSI_CHARSET;
1708 lstrcpy(lf.lfFaceName, font_name);
1709 efd.total = 0;
1710 SetLastError(0xdeadbeef);
1711 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1712 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1713 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1714 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1715 ansi_charset, symbol_charset, russian_charset,
1716 *font_name ? font_name : "<empty>");
1717 if (font_charset == SYMBOL_CHARSET)
1719 if (*font_name)
1720 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1721 else
1722 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1724 else
1726 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1727 for (i = 0; i < efd.total; i++)
1729 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1730 if (*font_name)
1731 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1732 font_name, efd.lf[i].lfFaceName);
1736 /* DEFAULT_CHARSET should enumerate all available charsets */
1737 memset(&lf, 0, sizeof(lf));
1738 lf.lfCharSet = DEFAULT_CHARSET;
1739 lstrcpy(lf.lfFaceName, font_name);
1740 efd.total = 0;
1741 SetLastError(0xdeadbeef);
1742 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1743 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1744 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1745 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1746 ansi_charset, symbol_charset, russian_charset,
1747 *font_name ? font_name : "<empty>");
1748 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1749 for (i = 0; i < efd.total; i++)
1751 if (*font_name)
1752 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1753 font_name, efd.lf[i].lfFaceName);
1755 if (*font_name)
1757 switch (font_charset)
1759 case ANSI_CHARSET:
1760 ok(ansi_charset > 0,
1761 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1762 ok(!symbol_charset,
1763 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1764 ok(russian_charset > 0,
1765 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1766 break;
1767 case SYMBOL_CHARSET:
1768 ok(!ansi_charset,
1769 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1770 ok(symbol_charset,
1771 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1772 ok(!russian_charset,
1773 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1774 break;
1775 case DEFAULT_CHARSET:
1776 ok(ansi_charset > 0,
1777 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1778 ok(symbol_charset > 0,
1779 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1780 ok(russian_charset > 0,
1781 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1782 break;
1785 else
1787 ok(ansi_charset > 0,
1788 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1789 ok(symbol_charset > 0,
1790 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1791 ok(russian_charset > 0,
1792 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1795 memset(&lf, 0, sizeof(lf));
1796 lf.lfCharSet = SYMBOL_CHARSET;
1797 lstrcpy(lf.lfFaceName, font_name);
1798 efd.total = 0;
1799 SetLastError(0xdeadbeef);
1800 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1801 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1802 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1803 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1804 ansi_charset, symbol_charset, russian_charset,
1805 *font_name ? font_name : "<empty>");
1806 if (*font_name && font_charset == ANSI_CHARSET)
1807 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1808 else
1810 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1811 for (i = 0; i < efd.total; i++)
1813 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1814 if (*font_name)
1815 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1816 font_name, efd.lf[i].lfFaceName);
1819 ok(!ansi_charset,
1820 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1821 ok(symbol_charset > 0,
1822 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1823 ok(!russian_charset,
1824 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1827 ReleaseDC(0, hdc);
1830 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1832 HFONT hfont, hfont_prev;
1833 DWORD ret;
1834 GLYPHMETRICS gm1, gm2;
1835 LOGFONTA lf2 = *lf;
1836 WORD idx;
1837 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1839 if(!pGetGlyphIndicesA)
1841 skip("GetGlyphIndicesA is unavailable\n");
1842 return;
1845 /* negative widths are handled just as positive ones */
1846 lf2.lfWidth = -lf->lfWidth;
1848 SetLastError(0xdeadbeef);
1849 hfont = CreateFontIndirectA(lf);
1850 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1851 check_font("original", lf, hfont);
1853 hfont_prev = SelectObject(hdc, hfont);
1855 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1856 if (ret == GDI_ERROR || idx == 0xffff)
1858 SelectObject(hdc, hfont_prev);
1859 DeleteObject(hfont);
1860 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1861 return;
1864 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1865 memset(&gm1, 0xab, sizeof(gm1));
1866 SetLastError(0xdeadbeef);
1867 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1868 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1870 SelectObject(hdc, hfont_prev);
1871 DeleteObject(hfont);
1873 SetLastError(0xdeadbeef);
1874 hfont = CreateFontIndirectA(&lf2);
1875 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1876 check_font("negative width", &lf2, hfont);
1878 hfont_prev = SelectObject(hdc, hfont);
1880 memset(&gm2, 0xbb, sizeof(gm2));
1881 SetLastError(0xdeadbeef);
1882 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1883 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1885 SelectObject(hdc, hfont_prev);
1886 DeleteObject(hfont);
1888 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1889 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1890 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1891 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1892 gm1.gmCellIncX == gm2.gmCellIncX &&
1893 gm1.gmCellIncY == gm2.gmCellIncY,
1894 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1895 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1896 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1897 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1898 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1901 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1902 #include "pshpack2.h"
1903 typedef struct
1905 USHORT version;
1906 SHORT xAvgCharWidth;
1907 USHORT usWeightClass;
1908 USHORT usWidthClass;
1909 SHORT fsType;
1910 SHORT ySubscriptXSize;
1911 SHORT ySubscriptYSize;
1912 SHORT ySubscriptXOffset;
1913 SHORT ySubscriptYOffset;
1914 SHORT ySuperscriptXSize;
1915 SHORT ySuperscriptYSize;
1916 SHORT ySuperscriptXOffset;
1917 SHORT ySuperscriptYOffset;
1918 SHORT yStrikeoutSize;
1919 SHORT yStrikeoutPosition;
1920 SHORT sFamilyClass;
1921 PANOSE panose;
1922 ULONG ulUnicodeRange1;
1923 ULONG ulUnicodeRange2;
1924 ULONG ulUnicodeRange3;
1925 ULONG ulUnicodeRange4;
1926 CHAR achVendID[4];
1927 USHORT fsSelection;
1928 USHORT usFirstCharIndex;
1929 USHORT usLastCharIndex;
1930 /* According to the Apple spec, original version didn't have the below fields,
1931 * version numbers were taked from the OpenType spec.
1933 /* version 0 (TrueType 1.5) */
1934 USHORT sTypoAscender;
1935 USHORT sTypoDescender;
1936 USHORT sTypoLineGap;
1937 USHORT usWinAscent;
1938 USHORT usWinDescent;
1939 /* version 1 (TrueType 1.66) */
1940 ULONG ulCodePageRange1;
1941 ULONG ulCodePageRange2;
1942 /* version 2 (OpenType 1.2) */
1943 SHORT sxHeight;
1944 SHORT sCapHeight;
1945 USHORT usDefaultChar;
1946 USHORT usBreakChar;
1947 USHORT usMaxContext;
1948 } TT_OS2_V2;
1949 #include "poppack.h"
1951 #ifdef WORDS_BIGENDIAN
1952 #define GET_BE_WORD(x) (x)
1953 #else
1954 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1955 #endif
1957 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1958 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1959 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1960 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1962 static void test_text_metrics(const LOGFONTA *lf)
1964 HDC hdc;
1965 HFONT hfont, hfont_old;
1966 TEXTMETRICA tmA;
1967 TEXTMETRICW tmW;
1968 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1969 INT test_char;
1970 TT_OS2_V2 tt_os2;
1971 USHORT version;
1972 LONG size, ret;
1973 const char *font_name = lf->lfFaceName;
1975 hdc = GetDC(0);
1977 SetLastError(0xdeadbeef);
1978 hfont = CreateFontIndirectA(lf);
1979 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1981 hfont_old = SelectObject(hdc, hfont);
1983 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1984 if (size == GDI_ERROR)
1986 trace("OS/2 chunk was not found\n");
1987 goto end_of_test;
1989 if (size > sizeof(tt_os2))
1991 trace("got too large OS/2 chunk of size %u\n", size);
1992 size = sizeof(tt_os2);
1995 memset(&tt_os2, 0, sizeof(tt_os2));
1996 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1997 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1999 version = GET_BE_WORD(tt_os2.version);
2001 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2002 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2003 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2004 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2006 trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
2007 font_name, lf->lfCharSet, first_unicode_char, last_unicode_char, default_char, break_char,
2008 version, (LPCSTR)&tt_os2.achVendID);
2010 SetLastError(0xdeadbeef);
2011 ret = GetTextMetricsA(hdc, &tmA);
2012 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2014 #if 0 /* FIXME: This doesn't appear to be what Windows does */
2015 test_char = min(first_unicode_char - 1, 255);
2016 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
2017 font_name, tmA.tmFirstChar, test_char);
2018 #endif
2019 if (lf->lfCharSet == SYMBOL_CHARSET)
2021 test_char = min(last_unicode_char - 0xf000, 255);
2022 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2023 font_name, tmA.tmLastChar, test_char);
2025 else
2027 test_char = min(last_unicode_char, 255);
2028 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2029 font_name, tmA.tmLastChar, test_char);
2032 SetLastError(0xdeadbeef);
2033 ret = GetTextMetricsW(hdc, &tmW);
2034 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2035 "GetTextMetricsW error %u\n", GetLastError());
2036 if (ret)
2038 trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
2039 tmW.tmFirstChar, tmW.tmLastChar, tmA.tmFirstChar, tmA.tmLastChar,
2040 tmW.tmDefaultChar, tmA.tmDefaultChar, tmW.tmBreakChar, tmA.tmBreakChar);
2042 if (lf->lfCharSet == SYMBOL_CHARSET)
2044 /* It appears that for fonts with SYMBOL_CHARSET Windows always
2045 * sets symbol range to 0 - f0ff
2047 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
2048 font_name, tmW.tmFirstChar);
2049 /* FIXME: Windows returns f0ff here, while Wine f0xx */
2050 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
2051 font_name, tmW.tmLastChar);
2053 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
2054 font_name, tmW.tmDefaultChar);
2055 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
2056 font_name, tmW.tmBreakChar);
2058 else
2060 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
2061 font_name, tmW.tmFirstChar, first_unicode_char);
2062 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
2063 font_name, tmW.tmLastChar, last_unicode_char);
2065 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2066 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2067 tmW.tmDigitizedAspectX, ret);
2068 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2069 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2070 tmW.tmDigitizedAspectX, ret);
2073 test_negative_width(hdc, lf);
2075 end_of_test:
2076 SelectObject(hdc, hfont_old);
2077 DeleteObject(hfont);
2079 ReleaseDC(0, hdc);
2082 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2084 INT *enumed = (INT *)lParam;
2086 if (type == TRUETYPE_FONTTYPE)
2088 (*enumed)++;
2089 test_text_metrics(lf);
2091 return 1;
2094 static void test_GetTextMetrics(void)
2096 LOGFONTA lf;
2097 HDC hdc;
2098 INT enumed;
2100 hdc = GetDC(0);
2102 memset(&lf, 0, sizeof(lf));
2103 lf.lfCharSet = DEFAULT_CHARSET;
2104 enumed = 0;
2105 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2106 trace("Tested metrics of %d truetype fonts\n", enumed);
2108 ReleaseDC(0, hdc);
2111 static void test_nonexistent_font(void)
2113 static const struct
2115 const char *name;
2116 int charset;
2117 } font_subst[] =
2119 { "Times New Roman Baltic", 186 },
2120 { "Times New Roman CE", 238 },
2121 { "Times New Roman CYR", 204 },
2122 { "Times New Roman Greek", 161 },
2123 { "Times New Roman TUR", 162 }
2125 LOGFONTA lf;
2126 HDC hdc;
2127 HFONT hfont;
2128 CHARSETINFO csi;
2129 INT cs, expected_cs, i;
2130 char buf[LF_FACESIZE];
2132 if (!is_truetype_font_installed("Arial") ||
2133 !is_truetype_font_installed("Times New Roman"))
2135 skip("Arial or Times New Roman not installed\n");
2136 return;
2139 expected_cs = GetACP();
2140 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2142 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2143 return;
2145 expected_cs = csi.ciCharset;
2146 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2148 hdc = GetDC(0);
2150 memset(&lf, 0, sizeof(lf));
2151 lf.lfHeight = 100;
2152 lf.lfWeight = FW_REGULAR;
2153 lf.lfCharSet = ANSI_CHARSET;
2154 lf.lfPitchAndFamily = FF_SWISS;
2155 strcpy(lf.lfFaceName, "Nonexistent font");
2156 hfont = CreateFontIndirectA(&lf);
2157 hfont = SelectObject(hdc, hfont);
2158 GetTextFaceA(hdc, sizeof(buf), buf);
2159 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2160 cs = GetTextCharset(hdc);
2161 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2162 DeleteObject(SelectObject(hdc, hfont));
2164 memset(&lf, 0, sizeof(lf));
2165 lf.lfHeight = -13;
2166 lf.lfWeight = FW_DONTCARE;
2167 strcpy(lf.lfFaceName, "Nonexistent font");
2168 hfont = CreateFontIndirectA(&lf);
2169 hfont = SelectObject(hdc, hfont);
2170 GetTextFaceA(hdc, sizeof(buf), buf);
2171 todo_wine /* Wine uses Arial for all substitutions */
2172 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2173 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2174 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2175 "Got %s\n", buf);
2176 cs = GetTextCharset(hdc);
2177 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2178 DeleteObject(SelectObject(hdc, hfont));
2180 memset(&lf, 0, sizeof(lf));
2181 lf.lfHeight = -13;
2182 lf.lfWeight = FW_REGULAR;
2183 strcpy(lf.lfFaceName, "Nonexistent font");
2184 hfont = CreateFontIndirectA(&lf);
2185 hfont = SelectObject(hdc, hfont);
2186 GetTextFaceA(hdc, sizeof(buf), buf);
2187 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2188 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2189 cs = GetTextCharset(hdc);
2190 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2191 DeleteObject(SelectObject(hdc, hfont));
2193 memset(&lf, 0, sizeof(lf));
2194 lf.lfHeight = -13;
2195 lf.lfWeight = FW_DONTCARE;
2196 strcpy(lf.lfFaceName, "Times New Roman");
2197 hfont = CreateFontIndirectA(&lf);
2198 hfont = SelectObject(hdc, hfont);
2199 GetTextFaceA(hdc, sizeof(buf), buf);
2200 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2201 cs = GetTextCharset(hdc);
2202 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2203 DeleteObject(SelectObject(hdc, hfont));
2205 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2207 memset(&lf, 0, sizeof(lf));
2208 lf.lfHeight = -13;
2209 lf.lfWeight = FW_REGULAR;
2210 strcpy(lf.lfFaceName, font_subst[i].name);
2211 hfont = CreateFontIndirectA(&lf);
2212 hfont = SelectObject(hdc, hfont);
2213 cs = GetTextCharset(hdc);
2214 if (font_subst[i].charset == expected_cs)
2216 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2217 GetTextFaceA(hdc, sizeof(buf), buf);
2218 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2220 else
2222 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2223 GetTextFaceA(hdc, sizeof(buf), buf);
2224 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2225 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2227 DeleteObject(SelectObject(hdc, hfont));
2229 memset(&lf, 0, sizeof(lf));
2230 lf.lfHeight = -13;
2231 lf.lfWeight = FW_DONTCARE;
2232 strcpy(lf.lfFaceName, font_subst[i].name);
2233 hfont = CreateFontIndirectA(&lf);
2234 hfont = SelectObject(hdc, hfont);
2235 GetTextFaceA(hdc, sizeof(buf), buf);
2236 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2237 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2238 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2239 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2240 "got %s\n", buf);
2241 cs = GetTextCharset(hdc);
2242 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2243 DeleteObject(SelectObject(hdc, hfont));
2246 ReleaseDC(0, hdc);
2249 static void test_GdiRealizationInfo(void)
2251 HDC hdc;
2252 DWORD info[4];
2253 BOOL r;
2254 HFONT hfont, hfont_old;
2255 LOGFONTA lf;
2257 if(!pGdiRealizationInfo)
2259 skip("GdiRealizationInfo not available\n");
2260 return;
2263 hdc = GetDC(0);
2265 memset(info, 0xcc, sizeof(info));
2266 r = pGdiRealizationInfo(hdc, info);
2267 ok(r != 0, "ret 0\n");
2268 ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
2269 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2271 if (!is_truetype_font_installed("Arial"))
2273 skip("skipping GdiRealizationInfo with truetype font\n");
2274 goto end;
2277 memset(&lf, 0, sizeof(lf));
2278 strcpy(lf.lfFaceName, "Arial");
2279 lf.lfHeight = 20;
2280 lf.lfWeight = FW_NORMAL;
2281 hfont = CreateFontIndirectA(&lf);
2282 hfont_old = SelectObject(hdc, hfont);
2284 memset(info, 0xcc, sizeof(info));
2285 r = pGdiRealizationInfo(hdc, info);
2286 ok(r != 0, "ret 0\n");
2287 ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
2288 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2290 DeleteObject(SelectObject(hdc, hfont_old));
2292 end:
2293 ReleaseDC(0, hdc);
2296 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2297 the nul in the count of characters copied when the face name buffer is not
2298 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2299 always includes it. */
2300 static void test_GetTextFace(void)
2302 static const char faceA[] = "Tahoma";
2303 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2304 LOGFONTA fA = {0};
2305 LOGFONTW fW = {0};
2306 char bufA[LF_FACESIZE];
2307 WCHAR bufW[LF_FACESIZE];
2308 HFONT f, g;
2309 HDC dc;
2310 int n;
2312 /* 'A' case. */
2313 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2314 f = CreateFontIndirectA(&fA);
2315 ok(f != NULL, "CreateFontIndirectA failed\n");
2317 dc = GetDC(NULL);
2318 g = SelectObject(dc, f);
2319 n = GetTextFaceA(dc, sizeof bufA, bufA);
2320 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2321 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2323 /* Play with the count arg. */
2324 bufA[0] = 'x';
2325 n = GetTextFaceA(dc, 0, bufA);
2326 ok(n == 0, "GetTextFaceA returned %d\n", n);
2327 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2329 bufA[0] = 'x';
2330 n = GetTextFaceA(dc, 1, bufA);
2331 ok(n == 0, "GetTextFaceA returned %d\n", n);
2332 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2334 bufA[0] = 'x'; bufA[1] = 'y';
2335 n = GetTextFaceA(dc, 2, bufA);
2336 ok(n == 1, "GetTextFaceA returned %d\n", n);
2337 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2339 n = GetTextFaceA(dc, 0, NULL);
2340 ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
2342 DeleteObject(SelectObject(dc, g));
2343 ReleaseDC(NULL, dc);
2345 /* 'W' case. */
2346 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2347 f = CreateFontIndirectW(&fW);
2348 ok(f != NULL, "CreateFontIndirectW failed\n");
2350 dc = GetDC(NULL);
2351 g = SelectObject(dc, f);
2352 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2353 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2354 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2356 /* Play with the count arg. */
2357 bufW[0] = 'x';
2358 n = GetTextFaceW(dc, 0, bufW);
2359 ok(n == 0, "GetTextFaceW returned %d\n", n);
2360 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2362 bufW[0] = 'x';
2363 n = GetTextFaceW(dc, 1, bufW);
2364 ok(n == 1, "GetTextFaceW returned %d\n", n);
2365 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2367 bufW[0] = 'x'; bufW[1] = 'y';
2368 n = GetTextFaceW(dc, 2, bufW);
2369 ok(n == 2, "GetTextFaceW returned %d\n", n);
2370 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2372 n = GetTextFaceW(dc, 0, NULL);
2373 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2375 DeleteObject(SelectObject(dc, g));
2376 ReleaseDC(NULL, dc);
2379 START_TEST(font)
2381 init();
2383 test_logfont();
2384 test_bitmap_font();
2385 test_outline_font();
2386 test_bitmap_font_metrics();
2387 test_GdiGetCharDimensions();
2388 test_GetCharABCWidths();
2389 test_text_extents();
2390 test_GetGlyphIndices();
2391 test_GetKerningPairs();
2392 test_GetOutlineTextMetrics();
2393 test_SetTextJustification();
2394 test_font_charset();
2395 test_GetFontUnicodeRanges();
2396 test_nonexistent_font();
2398 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2399 * I'd like to avoid them in this test.
2401 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2402 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2403 if (is_truetype_font_installed("Arial Black") &&
2404 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2406 test_EnumFontFamilies("", ANSI_CHARSET);
2407 test_EnumFontFamilies("", SYMBOL_CHARSET);
2408 test_EnumFontFamilies("", DEFAULT_CHARSET);
2410 else
2411 skip("Arial Black or Symbol/Wingdings is not installed\n");
2412 test_GetTextMetrics();
2413 test_GdiRealizationInfo();
2414 test_GetTextFace();