push abf7776878978b0406e974646c5bcfcf789b045c
[wine/hacks.git] / dlls / gdi32 / tests / font.c
blob868661c0d09a5f3b355d5aad1656d8d28757d14b
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 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1537 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1539 if (type != TRUETYPE_FONTTYPE) return 1;
1540 #if 0
1541 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1542 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1543 #endif
1544 if (efd->total < MAX_ENUM_FONTS)
1545 efd->lf[efd->total++] = *lf;
1547 return 1;
1550 static void get_charset_stats(struct enum_font_data *efd,
1551 int *ansi_charset, int *symbol_charset,
1552 int *russian_charset)
1554 int i;
1556 *ansi_charset = 0;
1557 *symbol_charset = 0;
1558 *russian_charset = 0;
1560 for (i = 0; i < efd->total; i++)
1562 switch (efd->lf[i].lfCharSet)
1564 case ANSI_CHARSET:
1565 (*ansi_charset)++;
1566 break;
1567 case SYMBOL_CHARSET:
1568 (*symbol_charset)++;
1569 break;
1570 case RUSSIAN_CHARSET:
1571 (*russian_charset)++;
1572 break;
1577 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1579 struct enum_font_data efd;
1580 LOGFONT lf;
1581 HDC hdc;
1582 int i, ret, ansi_charset, symbol_charset, russian_charset;
1584 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1586 if (*font_name && !is_truetype_font_installed(font_name))
1588 skip("%s is not installed\n", font_name);
1589 return;
1592 hdc = GetDC(0);
1594 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1595 * while EnumFontFamiliesEx doesn't.
1597 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1599 efd.total = 0;
1600 SetLastError(0xdeadbeef);
1601 ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1602 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1603 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1604 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1605 ansi_charset, symbol_charset, russian_charset);
1606 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1607 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1608 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1609 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1611 efd.total = 0;
1612 SetLastError(0xdeadbeef);
1613 ret = EnumFontFamiliesEx(hdc, NULL, arial_enum_proc, (LPARAM)&efd, 0);
1614 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1615 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1616 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1617 ansi_charset, symbol_charset, russian_charset);
1618 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1619 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1620 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1621 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1624 efd.total = 0;
1625 SetLastError(0xdeadbeef);
1626 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1627 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1628 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1629 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1630 ansi_charset, symbol_charset, russian_charset,
1631 *font_name ? font_name : "<empty>");
1632 if (*font_name)
1633 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1634 else
1635 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1636 for (i = 0; i < efd.total; i++)
1638 /* FIXME: remove completely once Wine is fixed */
1639 if (efd.lf[i].lfCharSet != font_charset)
1641 todo_wine
1642 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1644 else
1645 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1646 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1647 font_name, efd.lf[i].lfFaceName);
1650 memset(&lf, 0, sizeof(lf));
1651 lf.lfCharSet = ANSI_CHARSET;
1652 lstrcpy(lf.lfFaceName, font_name);
1653 efd.total = 0;
1654 SetLastError(0xdeadbeef);
1655 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1656 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1657 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1658 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1659 ansi_charset, symbol_charset, russian_charset,
1660 *font_name ? font_name : "<empty>");
1661 if (font_charset == SYMBOL_CHARSET)
1663 if (*font_name)
1664 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1665 else
1666 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1668 else
1670 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1671 for (i = 0; i < efd.total; i++)
1673 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1674 if (*font_name)
1675 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1676 font_name, efd.lf[i].lfFaceName);
1680 /* DEFAULT_CHARSET should enumerate all available charsets */
1681 memset(&lf, 0, sizeof(lf));
1682 lf.lfCharSet = DEFAULT_CHARSET;
1683 lstrcpy(lf.lfFaceName, font_name);
1684 efd.total = 0;
1685 SetLastError(0xdeadbeef);
1686 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1687 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1688 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1689 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1690 ansi_charset, symbol_charset, russian_charset,
1691 *font_name ? font_name : "<empty>");
1692 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1693 for (i = 0; i < efd.total; i++)
1695 if (*font_name)
1696 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1697 font_name, efd.lf[i].lfFaceName);
1699 if (*font_name)
1701 switch (font_charset)
1703 case ANSI_CHARSET:
1704 ok(ansi_charset > 0,
1705 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1706 ok(!symbol_charset,
1707 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1708 ok(russian_charset > 0,
1709 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1710 break;
1711 case SYMBOL_CHARSET:
1712 ok(!ansi_charset,
1713 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1714 ok(symbol_charset,
1715 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1716 ok(!russian_charset,
1717 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1718 break;
1719 case DEFAULT_CHARSET:
1720 ok(ansi_charset > 0,
1721 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1722 ok(symbol_charset > 0,
1723 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1724 ok(russian_charset > 0,
1725 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1726 break;
1729 else
1731 ok(ansi_charset > 0,
1732 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1733 ok(symbol_charset > 0,
1734 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1735 ok(russian_charset > 0,
1736 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1739 memset(&lf, 0, sizeof(lf));
1740 lf.lfCharSet = SYMBOL_CHARSET;
1741 lstrcpy(lf.lfFaceName, font_name);
1742 efd.total = 0;
1743 SetLastError(0xdeadbeef);
1744 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1745 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1746 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1747 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1748 ansi_charset, symbol_charset, russian_charset,
1749 *font_name ? font_name : "<empty>");
1750 if (*font_name && font_charset == ANSI_CHARSET)
1751 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1752 else
1754 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1755 for (i = 0; i < efd.total; i++)
1757 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1758 if (*font_name)
1759 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1760 font_name, efd.lf[i].lfFaceName);
1763 ok(!ansi_charset,
1764 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1765 ok(symbol_charset > 0,
1766 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1767 ok(!russian_charset,
1768 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1771 ReleaseDC(0, hdc);
1774 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1776 HFONT hfont, hfont_prev;
1777 DWORD ret;
1778 GLYPHMETRICS gm1, gm2;
1779 LOGFONTA lf2 = *lf;
1780 WORD idx;
1781 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1783 /* negative widths are handled just as positive ones */
1784 lf2.lfWidth = -lf->lfWidth;
1786 SetLastError(0xdeadbeef);
1787 hfont = CreateFontIndirectA(lf);
1788 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1789 check_font("original", lf, hfont);
1791 hfont_prev = SelectObject(hdc, hfont);
1793 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1794 if (ret == GDI_ERROR || idx == 0xffff)
1796 SelectObject(hdc, hfont_prev);
1797 DeleteObject(hfont);
1798 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1799 return;
1802 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1803 memset(&gm1, 0xab, sizeof(gm1));
1804 SetLastError(0xdeadbeef);
1805 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1806 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1808 SelectObject(hdc, hfont_prev);
1809 DeleteObject(hfont);
1811 SetLastError(0xdeadbeef);
1812 hfont = CreateFontIndirectA(&lf2);
1813 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1814 check_font("negative width", &lf2, hfont);
1816 hfont_prev = SelectObject(hdc, hfont);
1818 memset(&gm2, 0xbb, sizeof(gm2));
1819 SetLastError(0xdeadbeef);
1820 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1821 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1823 SelectObject(hdc, hfont_prev);
1824 DeleteObject(hfont);
1826 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1827 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1828 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1829 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1830 gm1.gmCellIncX == gm2.gmCellIncX &&
1831 gm1.gmCellIncY == gm2.gmCellIncY,
1832 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1833 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1834 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1835 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1836 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1839 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1840 #include "pshpack2.h"
1841 typedef struct
1843 USHORT version;
1844 SHORT xAvgCharWidth;
1845 USHORT usWeightClass;
1846 USHORT usWidthClass;
1847 SHORT fsType;
1848 SHORT ySubscriptXSize;
1849 SHORT ySubscriptYSize;
1850 SHORT ySubscriptXOffset;
1851 SHORT ySubscriptYOffset;
1852 SHORT ySuperscriptXSize;
1853 SHORT ySuperscriptYSize;
1854 SHORT ySuperscriptXOffset;
1855 SHORT ySuperscriptYOffset;
1856 SHORT yStrikeoutSize;
1857 SHORT yStrikeoutPosition;
1858 SHORT sFamilyClass;
1859 PANOSE panose;
1860 ULONG ulUnicodeRange1;
1861 ULONG ulUnicodeRange2;
1862 ULONG ulUnicodeRange3;
1863 ULONG ulUnicodeRange4;
1864 CHAR achVendID[4];
1865 USHORT fsSelection;
1866 USHORT usFirstCharIndex;
1867 USHORT usLastCharIndex;
1868 /* According to the Apple spec, original version didn't have the below fields,
1869 * version numbers were taked from the OpenType spec.
1871 /* version 0 (TrueType 1.5) */
1872 USHORT sTypoAscender;
1873 USHORT sTypoDescender;
1874 USHORT sTypoLineGap;
1875 USHORT usWinAscent;
1876 USHORT usWinDescent;
1877 /* version 1 (TrueType 1.66) */
1878 ULONG ulCodePageRange1;
1879 ULONG ulCodePageRange2;
1880 /* version 2 (OpenType 1.2) */
1881 SHORT sxHeight;
1882 SHORT sCapHeight;
1883 USHORT usDefaultChar;
1884 USHORT usBreakChar;
1885 USHORT usMaxContext;
1886 } TT_OS2_V2;
1887 #include "poppack.h"
1889 #ifdef WORDS_BIGENDIAN
1890 #define GET_BE_WORD(x) (x)
1891 #else
1892 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1893 #endif
1895 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1896 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1897 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1898 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1900 static void test_text_metrics(const LOGFONTA *lf)
1902 HDC hdc;
1903 HFONT hfont, hfont_old;
1904 TEXTMETRICA tmA;
1905 TEXTMETRICW tmW;
1906 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1907 INT test_char;
1908 TT_OS2_V2 tt_os2;
1909 USHORT version;
1910 LONG size, ret;
1911 const char *font_name = lf->lfFaceName;
1913 hdc = GetDC(0);
1915 SetLastError(0xdeadbeef);
1916 hfont = CreateFontIndirectA(lf);
1917 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1919 hfont_old = SelectObject(hdc, hfont);
1921 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1922 if (size == GDI_ERROR)
1924 trace("OS/2 chunk was not found\n");
1925 goto end_of_test;
1927 if (size > sizeof(tt_os2))
1929 trace("got too large OS/2 chunk of size %u\n", size);
1930 size = sizeof(tt_os2);
1933 memset(&tt_os2, 0, sizeof(tt_os2));
1934 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1935 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1937 version = GET_BE_WORD(tt_os2.version);
1939 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
1940 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
1941 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
1942 break_char = GET_BE_WORD(tt_os2.usBreakChar);
1944 trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
1945 font_name, lf->lfCharSet, first_unicode_char, last_unicode_char, default_char, break_char,
1946 version, (LPCSTR)&tt_os2.achVendID);
1948 SetLastError(0xdeadbeef);
1949 ret = GetTextMetricsA(hdc, &tmA);
1950 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
1952 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1953 test_char = min(first_unicode_char - 1, 255);
1954 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
1955 font_name, tmA.tmFirstChar, test_char);
1956 #endif
1957 if (lf->lfCharSet == SYMBOL_CHARSET)
1959 test_char = min(last_unicode_char - 0xf000, 255);
1960 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1961 font_name, tmA.tmLastChar, test_char);
1963 else
1965 test_char = min(last_unicode_char, 255);
1966 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1967 font_name, tmA.tmLastChar, test_char);
1970 SetLastError(0xdeadbeef);
1971 ret = GetTextMetricsW(hdc, &tmW);
1972 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
1973 "GetTextMetricsW error %u\n", GetLastError());
1974 if (ret)
1976 trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
1977 tmW.tmFirstChar, tmW.tmLastChar, tmA.tmFirstChar, tmA.tmLastChar,
1978 tmW.tmDefaultChar, tmA.tmDefaultChar, tmW.tmBreakChar, tmA.tmBreakChar);
1980 if (lf->lfCharSet == SYMBOL_CHARSET)
1982 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1983 * sets symbol range to 0 - f0ff
1985 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
1986 font_name, tmW.tmFirstChar);
1987 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1988 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1989 font_name, tmW.tmLastChar);
1991 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1992 font_name, tmW.tmDefaultChar);
1993 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1994 font_name, tmW.tmBreakChar);
1996 else
1998 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
1999 font_name, tmW.tmFirstChar, first_unicode_char);
2000 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
2001 font_name, tmW.tmLastChar, last_unicode_char);
2003 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2004 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2005 tmW.tmDigitizedAspectX, ret);
2006 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2007 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2008 tmW.tmDigitizedAspectX, ret);
2011 test_negative_width(hdc, lf);
2013 end_of_test:
2014 SelectObject(hdc, hfont_old);
2015 DeleteObject(hfont);
2017 ReleaseDC(0, hdc);
2020 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2022 INT *enumed = (INT *)lParam;
2024 if (type == TRUETYPE_FONTTYPE)
2026 (*enumed)++;
2027 test_text_metrics(lf);
2029 return 1;
2032 static void test_GetTextMetrics(void)
2034 LOGFONTA lf;
2035 HDC hdc;
2036 INT enumed;
2038 hdc = GetDC(0);
2040 memset(&lf, 0, sizeof(lf));
2041 lf.lfCharSet = DEFAULT_CHARSET;
2042 enumed = 0;
2043 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2044 trace("Tested metrics of %d truetype fonts\n", enumed);
2046 ReleaseDC(0, hdc);
2049 static void test_nonexistent_font(void)
2051 static const struct
2053 const char *name;
2054 int charset;
2055 } font_subst[] =
2057 { "Times New Roman Baltic", 186 },
2058 { "Times New Roman CE", 238 },
2059 { "Times New Roman CYR", 204 },
2060 { "Times New Roman Greek", 161 },
2061 { "Times New Roman TUR", 162 }
2063 LOGFONTA lf;
2064 HDC hdc;
2065 HFONT hfont;
2066 CHARSETINFO csi;
2067 INT cs, expected_cs, i;
2068 char buf[LF_FACESIZE];
2070 if (!is_truetype_font_installed("Arial") ||
2071 !is_truetype_font_installed("Times New Roman"))
2073 skip("Arial or Times New Roman not installed\n");
2074 return;
2077 expected_cs = GetACP();
2078 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2080 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2081 return;
2083 expected_cs = csi.ciCharset;
2084 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2086 hdc = GetDC(0);
2088 memset(&lf, 0, sizeof(lf));
2089 lf.lfHeight = 100;
2090 lf.lfWeight = FW_REGULAR;
2091 lf.lfCharSet = ANSI_CHARSET;
2092 lf.lfPitchAndFamily = FF_SWISS;
2093 strcpy(lf.lfFaceName, "Nonexistent font");
2094 hfont = CreateFontIndirectA(&lf);
2095 hfont = SelectObject(hdc, hfont);
2096 GetTextFaceA(hdc, sizeof(buf), buf);
2097 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2098 cs = GetTextCharset(hdc);
2099 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2100 DeleteObject(SelectObject(hdc, hfont));
2102 memset(&lf, 0, sizeof(lf));
2103 lf.lfHeight = -13;
2104 lf.lfWeight = FW_DONTCARE;
2105 strcpy(lf.lfFaceName, "Nonexistent font");
2106 hfont = CreateFontIndirectA(&lf);
2107 hfont = SelectObject(hdc, hfont);
2108 GetTextFaceA(hdc, sizeof(buf), buf);
2109 todo_wine /* Wine uses Arial for all substitutions */
2110 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2111 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2112 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2113 "Got %s\n", buf);
2114 cs = GetTextCharset(hdc);
2115 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2116 DeleteObject(SelectObject(hdc, hfont));
2118 memset(&lf, 0, sizeof(lf));
2119 lf.lfHeight = -13;
2120 lf.lfWeight = FW_REGULAR;
2121 strcpy(lf.lfFaceName, "Nonexistent font");
2122 hfont = CreateFontIndirectA(&lf);
2123 hfont = SelectObject(hdc, hfont);
2124 GetTextFaceA(hdc, sizeof(buf), buf);
2125 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2126 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2127 cs = GetTextCharset(hdc);
2128 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2129 DeleteObject(SelectObject(hdc, hfont));
2131 memset(&lf, 0, sizeof(lf));
2132 lf.lfHeight = -13;
2133 lf.lfWeight = FW_DONTCARE;
2134 strcpy(lf.lfFaceName, "Times New Roman");
2135 hfont = CreateFontIndirectA(&lf);
2136 hfont = SelectObject(hdc, hfont);
2137 GetTextFaceA(hdc, sizeof(buf), buf);
2138 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2139 cs = GetTextCharset(hdc);
2140 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2141 DeleteObject(SelectObject(hdc, hfont));
2143 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2145 memset(&lf, 0, sizeof(lf));
2146 lf.lfHeight = -13;
2147 lf.lfWeight = FW_REGULAR;
2148 strcpy(lf.lfFaceName, font_subst[i].name);
2149 hfont = CreateFontIndirectA(&lf);
2150 hfont = SelectObject(hdc, hfont);
2151 cs = GetTextCharset(hdc);
2152 if (font_subst[i].charset == expected_cs)
2154 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2155 GetTextFaceA(hdc, sizeof(buf), buf);
2156 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2158 else
2160 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2161 GetTextFaceA(hdc, sizeof(buf), buf);
2162 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2163 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2165 DeleteObject(SelectObject(hdc, hfont));
2167 memset(&lf, 0, sizeof(lf));
2168 lf.lfHeight = -13;
2169 lf.lfWeight = FW_DONTCARE;
2170 strcpy(lf.lfFaceName, font_subst[i].name);
2171 hfont = CreateFontIndirectA(&lf);
2172 hfont = SelectObject(hdc, hfont);
2173 GetTextFaceA(hdc, sizeof(buf), buf);
2174 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2175 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2176 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2177 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2178 "got %s\n", buf);
2179 cs = GetTextCharset(hdc);
2180 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2181 DeleteObject(SelectObject(hdc, hfont));
2184 ReleaseDC(0, hdc);
2187 static void test_GdiRealizationInfo(void)
2189 HDC hdc;
2190 DWORD info[4];
2191 BOOL r;
2192 HFONT hfont, hfont_old;
2193 LOGFONTA lf;
2195 if(!pGdiRealizationInfo)
2197 skip("GdiRealizationInfo not available\n");
2198 return;
2201 hdc = GetDC(0);
2203 memset(info, 0xcc, sizeof(info));
2204 r = pGdiRealizationInfo(hdc, info);
2205 ok(r != 0, "ret 0\n");
2206 ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
2207 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2209 if (!is_truetype_font_installed("Arial"))
2211 skip("skipping GdiRealizationInfo with truetype font\n");
2212 goto end;
2215 memset(&lf, 0, sizeof(lf));
2216 strcpy(lf.lfFaceName, "Arial");
2217 lf.lfHeight = 20;
2218 lf.lfWeight = FW_NORMAL;
2219 hfont = CreateFontIndirectA(&lf);
2220 hfont_old = SelectObject(hdc, hfont);
2222 memset(info, 0xcc, sizeof(info));
2223 r = pGdiRealizationInfo(hdc, info);
2224 ok(r != 0, "ret 0\n");
2225 ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
2226 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2228 DeleteObject(SelectObject(hdc, hfont_old));
2230 end:
2231 ReleaseDC(0, hdc);
2234 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2235 the nul in the count of characters copied when the face name buffer is not
2236 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2237 always includes it. */
2238 static void test_GetTextFace(void)
2240 static const char faceA[] = "Tahoma";
2241 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2242 LOGFONTA fA = {0};
2243 LOGFONTW fW = {0};
2244 char bufA[LF_FACESIZE];
2245 WCHAR bufW[LF_FACESIZE];
2246 HFONT f, g;
2247 HDC dc;
2248 int n;
2250 /* 'A' case. */
2251 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2252 f = CreateFontIndirectA(&fA);
2253 ok(f != NULL, "CreateFontIndirectA failed\n");
2255 dc = GetDC(NULL);
2256 g = SelectObject(dc, f);
2257 n = GetTextFaceA(dc, sizeof bufA, bufA);
2258 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2259 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2261 /* Play with the count arg. */
2262 bufA[0] = 'x';
2263 n = GetTextFaceA(dc, 0, bufA);
2264 ok(n == 0, "GetTextFaceA returned %d\n", n);
2265 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2267 bufA[0] = 'x';
2268 n = GetTextFaceA(dc, 1, bufA);
2269 ok(n == 0, "GetTextFaceA returned %d\n", n);
2270 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2272 bufA[0] = 'x'; bufA[1] = 'y';
2273 n = GetTextFaceA(dc, 2, bufA);
2274 ok(n == 1, "GetTextFaceA returned %d\n", n);
2275 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2277 n = GetTextFaceA(dc, 0, NULL);
2278 ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
2280 DeleteObject(SelectObject(dc, g));
2281 ReleaseDC(NULL, dc);
2283 /* 'W' case. */
2284 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2285 f = CreateFontIndirectW(&fW);
2286 ok(f != NULL, "CreateFontIndirectW failed\n");
2288 dc = GetDC(NULL);
2289 g = SelectObject(dc, f);
2290 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2291 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2292 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2294 /* Play with the count arg. */
2295 bufW[0] = 'x';
2296 n = GetTextFaceW(dc, 0, bufW);
2297 ok(n == 0, "GetTextFaceW returned %d\n", n);
2298 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2300 bufW[0] = 'x';
2301 n = GetTextFaceW(dc, 1, bufW);
2302 ok(n == 1, "GetTextFaceW returned %d\n", n);
2303 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2305 bufW[0] = 'x'; bufW[1] = 'y';
2306 n = GetTextFaceW(dc, 2, bufW);
2307 ok(n == 2, "GetTextFaceW returned %d\n", n);
2308 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2310 n = GetTextFaceW(dc, 0, NULL);
2311 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2313 DeleteObject(SelectObject(dc, g));
2314 ReleaseDC(NULL, dc);
2317 START_TEST(font)
2319 init();
2321 test_logfont();
2322 test_bitmap_font();
2323 test_outline_font();
2324 test_bitmap_font_metrics();
2325 test_GdiGetCharDimensions();
2326 test_GetCharABCWidths();
2327 test_text_extents();
2328 test_GetGlyphIndices();
2329 test_GetKerningPairs();
2330 test_GetOutlineTextMetrics();
2331 test_SetTextJustification();
2332 test_font_charset();
2333 test_GetFontUnicodeRanges();
2334 test_nonexistent_font();
2336 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2337 * I'd like to avoid them in this test.
2339 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2340 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2341 if (is_truetype_font_installed("Arial Black") &&
2342 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2344 test_EnumFontFamilies("", ANSI_CHARSET);
2345 test_EnumFontFamilies("", SYMBOL_CHARSET);
2346 test_EnumFontFamilies("", DEFAULT_CHARSET);
2348 else
2349 skip("Arial Black or Symbol/Wingdings is not installed\n");
2350 test_GetTextMetrics();
2351 test_GdiRealizationInfo();
2352 test_GetTextFace();