gdi32/tests: GetTextFaceA called with a NULL buffer returns 0 on win98 and winMe.
[wine/hacks.git] / dlls / gdi32 / tests / font.c
blobdce15fc7986c67046f0f47038c1c8fae80038e9b
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)) <= 6)
34 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
36 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
37 BOOL (WINAPI *pGetCharABCWidthsI)(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPABC abc);
38 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
39 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
40 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
41 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
42 BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *);
44 static HMODULE hgdi32 = 0;
46 static void init(void)
48 hgdi32 = GetModuleHandleA("gdi32.dll");
50 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
51 pGetCharABCWidthsI = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsI");
52 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
53 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
54 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
55 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
56 pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo");
59 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
61 if (type != TRUETYPE_FONTTYPE) return 1;
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, &getobj_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 LOGFONTA lf;
193 OUTLINETEXTMETRIC otm;
194 TEXTMETRICA tm;
195 SIZE size;
196 INT width_of_A, cx, cy;
197 UINT ret;
199 if (!hfont)
200 return;
202 ok(GetCurrentObject(hdc, OBJ_FONT) == hfont, "hfont should be selected\n");
204 GetObjectA(hfont, sizeof(lf), &lf);
206 if (GetOutlineTextMetricsA(hdc, 0, NULL))
208 otm.otmSize = sizeof(otm) / 2;
209 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
210 ok(ret == sizeof(otm)/2 /* XP */ ||
211 ret == 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret);
213 memset(&otm, 0x1, sizeof(otm));
214 otm.otmSize = sizeof(otm);
215 ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
216 ok(ret == sizeof(otm) /* XP */ ||
217 ret == 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret);
219 memset(&tm, 0x2, sizeof(tm));
220 ret = GetTextMetricsA(hdc, &tm);
221 ok(ret, "GetTextMetricsA failed\n");
222 /* the structure size is aligned */
223 if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
225 ok(0, "tm != otm\n");
226 compare_tm(&tm, &otm.otmTextMetrics);
229 tm = otm.otmTextMetrics;
230 if (0) /* these metrics are scaled too, but with rounding errors */
232 ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
233 ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
235 ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
236 ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
237 ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
238 ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
239 ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
240 ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
242 else
244 ret = GetTextMetricsA(hdc, &tm);
245 ok(ret, "GetTextMetricsA failed\n");
248 cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
249 cy = tm.tmHeight / tm_orig->tmHeight;
250 ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
251 scale_x, scale_y, cx, cy);
252 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
253 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
254 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
255 ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
256 ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
258 ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
259 if (lf.lfHeight)
261 if (lf.lfWidth)
262 ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
264 else
265 ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
267 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
269 ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
270 ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
272 GetCharWidthA(hdc, 'A', 'A', &width_of_A);
274 ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
277 /* Test how GDI scales bitmap font metrics */
278 static void test_bitmap_font(void)
280 static const char test_str[11] = "Test String";
281 HDC hdc;
282 LOGFONTA bitmap_lf;
283 HFONT hfont, old_hfont;
284 TEXTMETRICA tm_orig;
285 SIZE size_orig;
286 INT ret, i, width_orig, height_orig, scale, lfWidth;
288 hdc = GetDC(0);
290 /* "System" has only 1 pixel size defined, otherwise the test breaks */
291 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
292 if (ret)
294 ReleaseDC(0, hdc);
295 trace("no bitmap fonts were found, skipping the test\n");
296 return;
299 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
301 height_orig = bitmap_lf.lfHeight;
302 lfWidth = bitmap_lf.lfWidth;
304 hfont = create_font("bitmap", &bitmap_lf);
305 old_hfont = SelectObject(hdc, hfont);
306 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
307 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
308 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
309 SelectObject(hdc, old_hfont);
310 DeleteObject(hfont);
312 bitmap_lf.lfHeight = 0;
313 bitmap_lf.lfWidth = 4;
314 hfont = create_font("bitmap", &bitmap_lf);
315 old_hfont = SelectObject(hdc, hfont);
316 test_font_metrics(hdc, hfont, 0, 4, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
317 SelectObject(hdc, old_hfont);
318 DeleteObject(hfont);
320 bitmap_lf.lfHeight = height_orig;
321 bitmap_lf.lfWidth = lfWidth;
323 /* test fractional scaling */
324 for (i = 1; i <= height_orig * 3; i++)
326 INT nearest_height;
328 bitmap_lf.lfHeight = i;
329 hfont = create_font("fractional", &bitmap_lf);
330 scale = (i + height_orig - 1) / height_orig;
331 nearest_height = scale * height_orig;
332 /* XP allows not more than 10% deviation */
333 if (scale > 1 && nearest_height - i > nearest_height / 10) scale--;
334 old_hfont = SelectObject(hdc, hfont);
335 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, scale);
336 SelectObject(hdc, old_hfont);
337 DeleteObject(hfont);
340 /* test integer scaling 3x2 */
341 bitmap_lf.lfHeight = height_orig * 2;
342 bitmap_lf.lfWidth *= 3;
343 hfont = create_font("3x2", &bitmap_lf);
344 old_hfont = SelectObject(hdc, hfont);
345 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
346 SelectObject(hdc, old_hfont);
347 DeleteObject(hfont);
349 /* test integer scaling 3x3 */
350 bitmap_lf.lfHeight = height_orig * 3;
351 bitmap_lf.lfWidth = 0;
352 hfont = create_font("3x3", &bitmap_lf);
353 old_hfont = SelectObject(hdc, hfont);
354 test_font_metrics(hdc, hfont, bitmap_lf.lfHeight, 0, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
355 SelectObject(hdc, old_hfont);
356 DeleteObject(hfont);
358 ReleaseDC(0, hdc);
361 /* Test how GDI scales outline font metrics */
362 static void test_outline_font(void)
364 static const char test_str[11] = "Test String";
365 HDC hdc, hdc_2;
366 LOGFONTA lf;
367 HFONT hfont, old_hfont, old_hfont_2;
368 OUTLINETEXTMETRICA otm;
369 SIZE size_orig;
370 INT width_orig, height_orig, lfWidth;
371 XFORM xform;
372 GLYPHMETRICS gm;
373 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
374 MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
375 POINT pt;
376 INT ret;
378 if (!is_truetype_font_installed("Arial"))
380 skip("Arial is not installed\n");
381 return;
384 hdc = CreateCompatibleDC(0);
386 memset(&lf, 0, sizeof(lf));
387 strcpy(lf.lfFaceName, "Arial");
388 lf.lfHeight = 72;
389 hfont = create_font("outline", &lf);
390 old_hfont = SelectObject(hdc, hfont);
391 otm.otmSize = sizeof(otm);
392 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
393 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
394 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
396 test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
397 SelectObject(hdc, old_hfont);
398 DeleteObject(hfont);
400 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
401 lf.lfHeight = otm.otmEMSquare;
402 lf.lfHeight = -lf.lfHeight;
403 hfont = create_font("outline", &lf);
404 old_hfont = SelectObject(hdc, hfont);
405 otm.otmSize = sizeof(otm);
406 ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
407 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
408 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
409 SelectObject(hdc, old_hfont);
410 DeleteObject(hfont);
412 height_orig = otm.otmTextMetrics.tmHeight;
413 lfWidth = otm.otmTextMetrics.tmAveCharWidth;
415 /* test integer scaling 3x2 */
416 lf.lfHeight = height_orig * 2;
417 lf.lfWidth = lfWidth * 3;
418 hfont = create_font("3x2", &lf);
419 old_hfont = SelectObject(hdc, hfont);
420 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
421 SelectObject(hdc, old_hfont);
422 DeleteObject(hfont);
424 /* test integer scaling 3x3 */
425 lf.lfHeight = height_orig * 3;
426 lf.lfWidth = lfWidth * 3;
427 hfont = create_font("3x3", &lf);
428 old_hfont = SelectObject(hdc, hfont);
429 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
430 SelectObject(hdc, old_hfont);
431 DeleteObject(hfont);
433 /* test integer scaling 1x1 */
434 lf.lfHeight = height_orig * 1;
435 lf.lfWidth = lfWidth * 1;
436 hfont = create_font("1x1", &lf);
437 old_hfont = SelectObject(hdc, hfont);
438 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
439 SelectObject(hdc, old_hfont);
440 DeleteObject(hfont);
442 /* test integer scaling 1x1 */
443 lf.lfHeight = height_orig;
444 lf.lfWidth = 0;
445 hfont = create_font("1x1", &lf);
446 old_hfont = SelectObject(hdc, hfont);
447 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
449 /* with an identity matrix */
450 memset(&gm, 0, sizeof(gm));
451 SetLastError(0xdeadbeef);
452 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
453 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
454 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
455 ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
456 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
457 /* with a custom matrix */
458 memset(&gm, 0, sizeof(gm));
459 SetLastError(0xdeadbeef);
460 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
461 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
462 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
463 ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
464 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
466 /* Test that changing the DC transformation affects only the font
467 * selected on this DC and doesn't affect the same font selected on
468 * another DC.
470 hdc_2 = CreateCompatibleDC(0);
471 old_hfont_2 = SelectObject(hdc_2, hfont);
472 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
474 SetMapMode(hdc, MM_ANISOTROPIC);
476 /* font metrics on another DC should be unchanged */
477 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
479 /* test restrictions of compatibility mode GM_COMPATIBLE */
480 /* part 1: rescaling only X should not change font scaling on screen.
481 So compressing the X axis by 2 is not done, and this
482 appears as X scaling of 2 that no one requested. */
483 SetWindowExtEx(hdc, 100, 100, NULL);
484 SetViewportExtEx(hdc, 50, 100, NULL);
485 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
486 /* font metrics on another DC should be unchanged */
487 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
489 /* part 2: rescaling only Y should change font scaling.
490 As also X is scaled by a factor of 2, but this is not
491 requested by the DC transformation, we get a scaling factor
492 of 2 in the X coordinate. */
493 SetViewportExtEx(hdc, 100, 200, NULL);
494 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 2, 1);
495 /* font metrics on another DC should be unchanged */
496 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
498 /* restore scaling */
499 SetMapMode(hdc, MM_TEXT);
501 /* font metrics on another DC should be unchanged */
502 test_font_metrics(hdc_2, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
504 SelectObject(hdc_2, old_hfont_2);
505 DeleteDC(hdc_2);
507 if (!SetGraphicsMode(hdc, GM_ADVANCED))
509 SelectObject(hdc, old_hfont);
510 DeleteObject(hfont);
511 DeleteDC(hdc);
512 skip("GM_ADVANCED is not supported on this platform\n");
513 return;
516 xform.eM11 = 20.0f;
517 xform.eM12 = 0.0f;
518 xform.eM21 = 0.0f;
519 xform.eM22 = 20.0f;
520 xform.eDx = 0.0f;
521 xform.eDy = 0.0f;
523 SetLastError(0xdeadbeef);
524 ret = SetWorldTransform(hdc, &xform);
525 ok(ret, "SetWorldTransform error %u\n", GetLastError());
527 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
529 /* with an identity matrix */
530 memset(&gm, 0, sizeof(gm));
531 SetLastError(0xdeadbeef);
532 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
533 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
534 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
535 pt.x = width_orig; pt.y = 0;
536 LPtoDP(hdc, &pt, 1);
537 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
538 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
539 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
540 /* with a custom matrix */
541 memset(&gm, 0, sizeof(gm));
542 SetLastError(0xdeadbeef);
543 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
544 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
545 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
546 pt.x = width_orig; pt.y = 0;
547 LPtoDP(hdc, &pt, 1);
548 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
549 ok(near_match(gm.gmCellIncX, 10 * width_orig), "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
550 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
552 SetLastError(0xdeadbeef);
553 ret = SetMapMode(hdc, MM_LOMETRIC);
554 ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
556 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
558 /* with an identity matrix */
559 memset(&gm, 0, sizeof(gm));
560 SetLastError(0xdeadbeef);
561 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
562 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
563 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
564 pt.x = width_orig; pt.y = 0;
565 LPtoDP(hdc, &pt, 1);
566 ok(near_match(gm.gmCellIncX, pt.x), "incX %d != %d\n", gm.gmCellIncX, pt.x);
567 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
568 /* with a custom matrix */
569 memset(&gm, 0, sizeof(gm));
570 SetLastError(0xdeadbeef);
571 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
572 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
573 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
574 pt.x = width_orig; pt.y = 0;
575 LPtoDP(hdc, &pt, 1);
576 ok(near_match(gm.gmCellIncX, (pt.x + 1)/2), "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
577 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
579 SetLastError(0xdeadbeef);
580 ret = SetMapMode(hdc, MM_TEXT);
581 ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
583 test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
585 /* with an identity matrix */
586 memset(&gm, 0, sizeof(gm));
587 SetLastError(0xdeadbeef);
588 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
589 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
590 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
591 pt.x = width_orig; pt.y = 0;
592 LPtoDP(hdc, &pt, 1);
593 ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
594 ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
595 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
596 /* with a custom matrix */
597 memset(&gm, 0, sizeof(gm));
598 SetLastError(0xdeadbeef);
599 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
600 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
601 trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
602 pt.x = width_orig; pt.y = 0;
603 LPtoDP(hdc, &pt, 1);
604 ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
605 ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
606 ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
608 SelectObject(hdc, old_hfont);
609 DeleteObject(hfont);
610 DeleteDC(hdc);
613 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
615 LOGFONT *lf = (LOGFONT *)lParam;
617 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
619 *lf = *elf;
620 return 0; /* stop enumeration */
622 return 1; /* continue enumeration */
625 static void test_bitmap_font_metrics(void)
627 static const struct font_data
629 const char face_name[LF_FACESIZE];
630 int weight, height, ascent, descent, int_leading, ext_leading;
631 int ave_char_width, max_char_width;
632 DWORD ansi_bitfield;
633 } fd[] =
635 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
636 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
637 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1 | FS_CYRILLIC },
638 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2 },
639 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1 },
640 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2 },
641 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC },
642 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1 },
643 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2 },
644 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC },
645 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
646 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
647 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
648 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
649 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1 },
650 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2 | FS_CYRILLIC },
651 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1 | FS_LATIN2 },
652 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC },
653 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1 | FS_LATIN2 },
654 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC },
655 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1 },
656 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2 },
657 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC },
658 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1 },
659 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2 },
660 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC },
661 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1 | FS_LATIN2 },
662 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC },
663 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
664 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
665 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
666 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1 },
667 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2 | FS_CYRILLIC },
669 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
670 * require a new system.sfd for that font
672 { "System", FW_BOLD, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN },
673 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1 },
674 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2 | FS_CYRILLIC },
675 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN },
676 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1 },
677 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2 | FS_CYRILLIC },
678 { "Small Fonts", FW_NORMAL, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN },
679 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1 },
680 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2 | FS_CYRILLIC },
681 { "Small Fonts", FW_NORMAL, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN },
682 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1 },
683 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2 | FS_CYRILLIC },
684 { "Small Fonts", FW_NORMAL, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN },
685 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1 | FS_LATIN2 },
686 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC },
687 { "Small Fonts", FW_NORMAL, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN },
688 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1 | FS_LATIN2 | FS_CYRILLIC },
689 { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN },
690 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1 | FS_LATIN2 },
691 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC },
692 { "FixedSys", FW_NORMAL, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN }
694 /* FIXME: add "Terminal" */
696 HDC hdc;
697 LOGFONT lf;
698 HFONT hfont, old_hfont;
699 TEXTMETRIC tm;
700 INT ret, i;
702 hdc = CreateCompatibleDC(0);
703 assert(hdc);
705 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
707 int bit;
709 memset(&lf, 0, sizeof(lf));
711 lf.lfHeight = fd[i].height;
712 strcpy(lf.lfFaceName, fd[i].face_name);
714 for(bit = 0; bit < 32; bit++)
716 DWORD fs[2];
717 CHARSETINFO csi;
719 fs[0] = 1L << bit;
720 fs[1] = 0;
721 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
722 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
724 lf.lfCharSet = csi.ciCharset;
725 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
726 if (ret) continue;
728 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
730 hfont = create_font(lf.lfFaceName, &lf);
731 old_hfont = SelectObject(hdc, hfont);
732 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
734 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);
735 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);
736 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);
737 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);
738 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);
739 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);
740 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);
742 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
743 that make the max width bigger */
744 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
745 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);
747 SelectObject(hdc, old_hfont);
748 DeleteObject(hfont);
752 DeleteDC(hdc);
755 static void test_GdiGetCharDimensions(void)
757 HDC hdc;
758 TEXTMETRICW tm;
759 LONG ret;
760 SIZE size;
761 LONG avgwidth, height;
762 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
764 if (!pGdiGetCharDimensions)
766 skip("GdiGetCharDimensions not available on this platform\n");
767 return;
770 hdc = CreateCompatibleDC(NULL);
772 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
773 avgwidth = ((size.cx / 26) + 1) / 2;
775 ret = pGdiGetCharDimensions(hdc, &tm, &height);
776 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
777 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
779 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
780 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
782 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
783 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
785 height = 0;
786 ret = pGdiGetCharDimensions(hdc, NULL, &height);
787 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
788 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
790 DeleteDC(hdc);
793 static void test_GetCharABCWidths(void)
795 static const WCHAR str[] = {'a',0};
796 BOOL ret;
797 HDC hdc;
798 LOGFONTA lf;
799 HFONT hfont;
800 ABC abc[1];
801 WORD glyphs[1];
802 DWORD nb;
804 if (!pGetCharABCWidthsW || !pGetCharABCWidthsI)
806 skip("GetCharABCWidthsW/I not available on this platform\n");
807 return;
810 memset(&lf, 0, sizeof(lf));
811 strcpy(lf.lfFaceName, "System");
812 lf.lfHeight = 20;
814 hfont = CreateFontIndirectA(&lf);
815 hdc = GetDC(0);
816 hfont = SelectObject(hdc, hfont);
818 nb = pGetGlyphIndicesW(hdc, str, 1, glyphs, 0);
819 ok(nb == 1, "GetGlyphIndicesW should have returned 1\n");
821 ret = pGetCharABCWidthsI(NULL, 0, 1, glyphs, abc);
822 ok(!ret, "GetCharABCWidthsI should have failed\n");
824 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, NULL);
825 ok(!ret, "GetCharABCWidthsI should have failed\n");
827 ret = pGetCharABCWidthsI(hdc, 0, 1, glyphs, abc);
828 ok(ret, "GetCharABCWidthsI should have succeeded\n");
830 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
831 ok(!ret, "GetCharABCWidthsW should have failed\n");
833 ret = pGetCharABCWidthsW(hdc, 'a', 'a', NULL);
834 ok(!ret, "GetCharABCWidthsW should have failed\n");
836 ret = pGetCharABCWidthsW(hdc, 'a', 'a', abc);
837 ok(!ret, "GetCharABCWidthsW should have failed\n");
839 hfont = SelectObject(hdc, hfont);
840 DeleteObject(hfont);
841 ReleaseDC(NULL, hdc);
844 static void test_text_extents(void)
846 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
847 LPINT extents;
848 INT i, len, fit1, fit2;
849 LOGFONTA lf;
850 TEXTMETRICA tm;
851 HDC hdc;
852 HFONT hfont;
853 SIZE sz;
854 SIZE sz1, sz2;
856 memset(&lf, 0, sizeof(lf));
857 strcpy(lf.lfFaceName, "Arial");
858 lf.lfHeight = 20;
860 hfont = CreateFontIndirectA(&lf);
861 hdc = GetDC(0);
862 hfont = SelectObject(hdc, hfont);
863 GetTextMetricsA(hdc, &tm);
864 GetTextExtentPointA(hdc, "o", 1, &sz);
865 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
867 SetLastError(0xdeadbeef);
868 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
869 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
871 skip("Skipping remainder of text extents test on a Win9x platform\n");
872 hfont = SelectObject(hdc, hfont);
873 DeleteObject(hfont);
874 ReleaseDC(0, hdc);
875 return;
878 len = lstrlenW(wt);
879 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
880 extents[0] = 1; /* So that the increasing sequence test will fail
881 if the extents array is untouched. */
882 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
883 GetTextExtentPointW(hdc, wt, len, &sz2);
884 ok(sz1.cy == sz2.cy,
885 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
886 /* Because of the '\n' in the string GetTextExtentExPoint and
887 GetTextExtentPoint return different widths under Win2k, but
888 under WinXP they return the same width. So we don't test that
889 here. */
891 for (i = 1; i < len; ++i)
892 ok(extents[i-1] <= extents[i],
893 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
895 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
896 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
897 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
898 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
899 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
900 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
901 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
902 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
903 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
904 ok(extents[0] == extents[2] && extents[1] == extents[3],
905 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
906 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
907 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
908 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
909 HeapFree(GetProcessHeap(), 0, extents);
911 hfont = SelectObject(hdc, hfont);
912 DeleteObject(hfont);
913 ReleaseDC(NULL, hdc);
916 static void test_GetGlyphIndices(void)
918 HDC hdc;
919 HFONT hfont;
920 DWORD charcount;
921 LOGFONTA lf;
922 DWORD flags = 0;
923 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
924 WORD glyphs[(sizeof(testtext)/2)-1];
925 TEXTMETRIC textm;
926 HFONT hOldFont;
928 if (!pGetGlyphIndicesW) {
929 skip("GetGlyphIndicesW not available on platform\n");
930 return;
933 hdc = GetDC(0);
935 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
936 flags |= GGI_MARK_NONEXISTING_GLYPHS;
937 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
938 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
939 ok((glyphs[4] == 0x001f || glyphs[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs[4]);
940 flags = 0;
941 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
942 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
943 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndicesW should have returned a %04x not %04x\n",
944 textm.tmDefaultChar, glyphs[4]);
946 if(!is_font_installed("Tahoma"))
948 skip("Tahoma is not installed so skipping this test\n");
949 return;
951 memset(&lf, 0, sizeof(lf));
952 strcpy(lf.lfFaceName, "Tahoma");
953 lf.lfHeight = 20;
955 hfont = CreateFontIndirectA(&lf);
956 hOldFont = SelectObject(hdc, hfont);
957 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
958 flags |= GGI_MARK_NONEXISTING_GLYPHS;
959 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
960 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
961 ok(glyphs[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs[4]);
962 flags = 0;
963 testtext[0] = textm.tmDefaultChar;
964 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
965 ok(charcount == 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount);
966 ok(glyphs[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs[0]);
967 ok(glyphs[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs[4]);
968 DeleteObject(SelectObject(hdc, hOldFont));
971 static void test_GetKerningPairs(void)
973 static const struct kerning_data
975 const char face_name[LF_FACESIZE];
976 LONG height;
977 /* some interesting fields from OUTLINETEXTMETRIC */
978 LONG tmHeight, tmAscent, tmDescent;
979 UINT otmEMSquare;
980 INT otmAscent;
981 INT otmDescent;
982 UINT otmLineGap;
983 UINT otmsCapEmHeight;
984 UINT otmsXHeight;
985 INT otmMacAscent;
986 INT otmMacDescent;
987 UINT otmMacLineGap;
988 UINT otmusMinimumPPEM;
989 /* small subset of kerning pairs to test */
990 DWORD total_kern_pairs;
991 const KERNINGPAIR kern_pair[26];
992 } kd[] =
994 {"Arial", 12, 12, 9, 3,
995 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
998 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
999 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1000 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1001 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1002 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1003 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1004 {933,970,+1},{933,972,-1}
1007 {"Arial", -34, 39, 32, 7,
1008 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1011 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1012 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1013 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1014 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1015 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1016 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1017 {933,970,+2},{933,972,-3}
1020 { "Arial", 120, 120, 97, 23,
1021 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1024 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1025 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1026 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1027 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1028 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1029 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1030 {933,970,+6},{933,972,-10}
1033 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1034 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1035 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1038 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1039 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1040 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1041 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1042 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1043 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1044 {933,970,+54},{933,972,-83}
1047 #endif
1049 LOGFONT lf;
1050 HFONT hfont, hfont_old;
1051 KERNINGPAIR *kern_pair;
1052 HDC hdc;
1053 DWORD total_kern_pairs, ret, i, n, matches;
1055 hdc = GetDC(0);
1057 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1058 * which may render this test unusable, so we're trying to avoid that.
1060 SetLastError(0xdeadbeef);
1061 GetKerningPairsW(hdc, 0, NULL);
1062 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1064 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1065 ReleaseDC(0, hdc);
1066 return;
1069 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
1071 OUTLINETEXTMETRICW otm;
1073 if (!is_font_installed(kd[i].face_name))
1075 trace("%s is not installed so skipping this test\n", kd[i].face_name);
1076 continue;
1079 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
1081 memset(&lf, 0, sizeof(lf));
1082 strcpy(lf.lfFaceName, kd[i].face_name);
1083 lf.lfHeight = kd[i].height;
1084 hfont = CreateFontIndirect(&lf);
1085 assert(hfont != 0);
1087 hfont_old = SelectObject(hdc, hfont);
1089 SetLastError(0xdeadbeef);
1090 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
1091 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
1093 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
1094 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
1095 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
1096 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
1097 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
1098 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
1100 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
1101 kd[i].otmEMSquare, otm.otmEMSquare);
1102 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
1103 kd[i].otmAscent, otm.otmAscent);
1104 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
1105 kd[i].otmDescent, otm.otmDescent);
1106 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
1107 kd[i].otmLineGap, otm.otmLineGap);
1108 ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
1109 kd[i].otmMacDescent, otm.otmMacDescent);
1110 todo_wine {
1111 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
1112 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
1113 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
1114 kd[i].otmsXHeight, otm.otmsXHeight);
1115 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
1116 kd[i].otmMacAscent, otm.otmMacAscent);
1117 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1118 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
1119 kd[i].otmMacLineGap, otm.otmMacLineGap);
1120 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
1121 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
1124 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
1125 trace("total_kern_pairs %u\n", total_kern_pairs);
1126 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
1128 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1129 SetLastError(0xdeadbeef);
1130 ret = GetKerningPairsW(hdc, 0, kern_pair);
1131 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1132 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1133 ok(ret == 0, "got %lu, expected 0\n", ret);
1134 #endif
1136 ret = GetKerningPairsW(hdc, 100, NULL);
1137 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1139 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
1140 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
1142 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
1143 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
1145 matches = 0;
1147 for (n = 0; n < ret; n++)
1149 DWORD j;
1150 #if 0
1151 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
1152 trace("{'%c','%c',%d},\n",
1153 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
1154 #endif
1155 for (j = 0; j < kd[i].total_kern_pairs; j++)
1157 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
1158 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
1160 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
1161 "pair %d:%d got %d, expected %d\n",
1162 kern_pair[n].wFirst, kern_pair[n].wSecond,
1163 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
1164 matches++;
1169 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
1170 matches, kd[i].total_kern_pairs);
1172 HeapFree(GetProcessHeap(), 0, kern_pair);
1174 SelectObject(hdc, hfont_old);
1175 DeleteObject(hfont);
1178 ReleaseDC(0, hdc);
1181 static void test_GetOutlineTextMetrics(void)
1183 OUTLINETEXTMETRIC *otm;
1184 LOGFONT lf;
1185 HFONT hfont, hfont_old;
1186 HDC hdc;
1187 DWORD ret, otm_size;
1188 LPSTR unset_ptr;
1190 if (!is_font_installed("Arial"))
1192 skip("Arial is not installed\n");
1193 return;
1196 hdc = GetDC(0);
1198 memset(&lf, 0, sizeof(lf));
1199 strcpy(lf.lfFaceName, "Arial");
1200 lf.lfHeight = -13;
1201 lf.lfWeight = FW_NORMAL;
1202 lf.lfPitchAndFamily = DEFAULT_PITCH;
1203 lf.lfQuality = PROOF_QUALITY;
1204 hfont = CreateFontIndirect(&lf);
1205 assert(hfont != 0);
1207 hfont_old = SelectObject(hdc, hfont);
1208 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1209 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1211 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1213 memset(otm, 0xAA, otm_size);
1214 SetLastError(0xdeadbeef);
1215 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1216 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1217 ok(ret == 1 /* Win9x */ ||
1218 ret == otm->otmSize /* XP*/,
1219 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1220 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1222 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1223 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1224 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1225 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1228 memset(otm, 0xAA, otm_size);
1229 SetLastError(0xdeadbeef);
1230 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1231 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1232 ok(ret == 1 /* Win9x */ ||
1233 ret == otm->otmSize /* XP*/,
1234 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1235 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1237 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1238 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1239 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1240 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1243 /* ask about truncated data */
1244 memset(otm, 0xAA, otm_size);
1245 memset(&unset_ptr, 0xAA, sizeof(unset_ptr));
1246 SetLastError(0xdeadbeef);
1247 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1248 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1249 ok(ret == 1 /* Win9x */ ||
1250 ret == otm->otmSize /* XP*/,
1251 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1252 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1254 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1255 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1256 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1258 ok(otm->otmpFullName == unset_ptr, "expected %p got %p\n", unset_ptr, otm->otmpFullName);
1260 HeapFree(GetProcessHeap(), 0, otm);
1262 SelectObject(hdc, hfont_old);
1263 DeleteObject(hfont);
1265 ReleaseDC(0, hdc);
1268 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1270 INT x, y,
1271 breakCount,
1272 outputWidth = 0, /* to test TabbedTextOut() */
1273 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1274 areaWidth = clientArea->right - clientArea->left,
1275 nErrors = 0, e;
1276 BOOL lastExtent = FALSE;
1277 PSTR pFirstChar, pLastChar;
1278 SIZE size;
1279 TEXTMETRICA tm;
1280 struct err
1282 char extent[100];
1283 int GetTextExtentExPointWWidth;
1284 int TabbedTextOutWidth;
1285 } error[10];
1287 GetTextMetricsA(hdc, &tm);
1288 y = clientArea->top;
1289 do {
1290 breakCount = 0;
1291 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1292 pFirstChar = str;
1294 do {
1295 pLastChar = str;
1297 /* if not at the end of the string, ... */
1298 if (*str == '\0') break;
1299 /* ... add the next word to the current extent */
1300 while (*str != '\0' && *str++ != tm.tmBreakChar);
1301 breakCount++;
1302 SetTextJustification(hdc, 0, 0);
1303 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1304 } while ((int) size.cx < areaWidth);
1306 /* ignore trailing break chars */
1307 breakCount--;
1308 while (*(pLastChar - 1) == tm.tmBreakChar)
1310 pLastChar--;
1311 breakCount--;
1314 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1316 SetTextJustification(hdc, 0, 0);
1317 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1319 /* do not justify the last extent */
1320 if (*str != '\0' && breakCount > 0)
1322 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1323 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1324 justifiedWidth = size.cx;
1326 else lastExtent = TRUE;
1328 x = clientArea->left;
1330 outputWidth = LOWORD(TabbedTextOut(
1331 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1332 0, NULL, 0));
1333 /* catch errors and report them */
1334 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1336 memset(error[nErrors].extent, 0, 100);
1337 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1338 error[nErrors].TabbedTextOutWidth = outputWidth;
1339 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1340 nErrors++;
1343 y += size.cy;
1344 str = pLastChar;
1345 } while (*str && y < clientArea->bottom);
1347 for (e = 0; e < nErrors; e++)
1349 ok(near_match(error[e].TabbedTextOutWidth, areaWidth),
1350 "The output text (\"%s\") width should be %d, not %d.\n",
1351 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1352 /* The width returned by GetTextExtentPoint32() is exactly the same
1353 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1354 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1355 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1356 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1360 static void test_SetTextJustification(void)
1362 HDC hdc;
1363 RECT clientArea;
1364 LOGFONTA lf;
1365 HFONT hfont;
1366 HWND hwnd;
1367 static char testText[] =
1368 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1369 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1370 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1371 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1372 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1373 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1374 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1376 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1377 GetClientRect( hwnd, &clientArea );
1378 hdc = GetDC( hwnd );
1380 memset(&lf, 0, sizeof lf);
1381 lf.lfCharSet = ANSI_CHARSET;
1382 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1383 lf.lfWeight = FW_DONTCARE;
1384 lf.lfHeight = 20;
1385 lf.lfQuality = DEFAULT_QUALITY;
1386 lstrcpyA(lf.lfFaceName, "Times New Roman");
1387 hfont = create_font("Times New Roman", &lf);
1388 SelectObject(hdc, hfont);
1390 testJustification(hdc, testText, &clientArea);
1392 DeleteObject(hfont);
1393 ReleaseDC(hwnd, hdc);
1394 DestroyWindow(hwnd);
1397 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1399 HDC hdc;
1400 LOGFONTA lf;
1401 HFONT hfont, hfont_old;
1402 CHARSETINFO csi;
1403 FONTSIGNATURE fs;
1404 INT cs;
1405 DWORD i, ret;
1406 char name[64];
1408 assert(count <= 128);
1410 memset(&lf, 0, sizeof(lf));
1412 lf.lfCharSet = charset;
1413 lf.lfHeight = 10;
1414 lstrcpyA(lf.lfFaceName, "Arial");
1415 SetLastError(0xdeadbeef);
1416 hfont = CreateFontIndirectA(&lf);
1417 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1419 hdc = GetDC(0);
1420 hfont_old = SelectObject(hdc, hfont);
1422 cs = GetTextCharsetInfo(hdc, &fs, 0);
1423 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1425 SetLastError(0xdeadbeef);
1426 ret = GetTextFaceA(hdc, sizeof(name), name);
1427 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1429 if (charset == SYMBOL_CHARSET)
1431 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1432 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1434 else
1436 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1437 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1440 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1442 trace("Can't find codepage for charset %d\n", cs);
1443 ReleaseDC(0, hdc);
1444 return FALSE;
1446 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1448 if (unicode)
1450 char ansi_buf[128];
1451 WCHAR unicode_buf[128];
1453 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1455 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1457 SetLastError(0xdeadbeef);
1458 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1459 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1461 else
1463 char ansi_buf[128];
1465 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1467 SetLastError(0xdeadbeef);
1468 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1469 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1472 SelectObject(hdc, hfont_old);
1473 DeleteObject(hfont);
1475 ReleaseDC(0, hdc);
1477 return TRUE;
1480 static void test_font_charset(void)
1482 static struct charset_data
1484 INT charset;
1485 UINT code_page;
1486 WORD font_idxA[128], font_idxW[128];
1487 } cd[] =
1489 { ANSI_CHARSET, 1252 },
1490 { RUSSIAN_CHARSET, 1251 },
1491 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1493 int i;
1495 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1497 skip("Skipping the font charset test on a Win9x platform\n");
1498 return;
1501 if (!is_font_installed("Arial"))
1503 skip("Arial is not installed\n");
1504 return;
1507 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1509 if (cd[i].charset == SYMBOL_CHARSET)
1511 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1513 skip("Symbol or Wingdings is not installed\n");
1514 break;
1517 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1518 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1519 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1522 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1523 if (i > 2)
1525 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1526 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1528 else
1529 skip("Symbol or Wingdings is not installed\n");
1532 static void test_GetFontUnicodeRanges(void)
1534 LOGFONTA lf;
1535 HDC hdc;
1536 HFONT hfont, hfont_old;
1537 DWORD size;
1538 GLYPHSET *gs;
1540 if (!pGetFontUnicodeRanges)
1542 skip("GetFontUnicodeRanges not available before W2K\n");
1543 return;
1546 memset(&lf, 0, sizeof(lf));
1547 lstrcpyA(lf.lfFaceName, "Arial");
1548 hfont = create_font("Arial", &lf);
1550 hdc = GetDC(0);
1551 hfont_old = SelectObject(hdc, hfont);
1553 size = pGetFontUnicodeRanges(NULL, NULL);
1554 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1556 size = pGetFontUnicodeRanges(hdc, NULL);
1557 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1559 gs = HeapAlloc(GetProcessHeap(), 0, size);
1561 size = pGetFontUnicodeRanges(hdc, gs);
1562 ok(size, "GetFontUnicodeRanges failed\n");
1563 #if 0
1564 for (i = 0; i < gs->cRanges; i++)
1565 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1566 #endif
1567 trace("found %u ranges\n", gs->cRanges);
1569 HeapFree(GetProcessHeap(), 0, gs);
1571 SelectObject(hdc, hfont_old);
1572 DeleteObject(hfont);
1573 ReleaseDC(NULL, hdc);
1576 #define MAX_ENUM_FONTS 4096
1578 struct enum_font_data
1580 int total;
1581 LOGFONT lf[MAX_ENUM_FONTS];
1584 struct enum_font_dataW
1586 int total;
1587 LOGFONTW lf[MAX_ENUM_FONTS];
1590 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1592 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1594 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1596 if (type != TRUETYPE_FONTTYPE) return 1;
1597 #if 0
1598 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1599 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1600 #endif
1601 if (efd->total < MAX_ENUM_FONTS)
1602 efd->lf[efd->total++] = *lf;
1603 else
1604 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1606 return 1;
1609 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1611 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1613 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1615 if (type != TRUETYPE_FONTTYPE) return 1;
1616 #if 0
1617 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1618 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1619 #endif
1620 if (efd->total < MAX_ENUM_FONTS)
1621 efd->lf[efd->total++] = *lf;
1622 else
1623 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1625 return 1;
1628 static void get_charset_stats(struct enum_font_data *efd,
1629 int *ansi_charset, int *symbol_charset,
1630 int *russian_charset)
1632 int i;
1634 *ansi_charset = 0;
1635 *symbol_charset = 0;
1636 *russian_charset = 0;
1638 for (i = 0; i < efd->total; i++)
1640 switch (efd->lf[i].lfCharSet)
1642 case ANSI_CHARSET:
1643 (*ansi_charset)++;
1644 break;
1645 case SYMBOL_CHARSET:
1646 (*symbol_charset)++;
1647 break;
1648 case RUSSIAN_CHARSET:
1649 (*russian_charset)++;
1650 break;
1655 static void get_charset_statsW(struct enum_font_dataW *efd,
1656 int *ansi_charset, int *symbol_charset,
1657 int *russian_charset)
1659 int i;
1661 *ansi_charset = 0;
1662 *symbol_charset = 0;
1663 *russian_charset = 0;
1665 for (i = 0; i < efd->total; i++)
1667 switch (efd->lf[i].lfCharSet)
1669 case ANSI_CHARSET:
1670 (*ansi_charset)++;
1671 break;
1672 case SYMBOL_CHARSET:
1673 (*symbol_charset)++;
1674 break;
1675 case RUSSIAN_CHARSET:
1676 (*russian_charset)++;
1677 break;
1682 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1684 struct enum_font_data efd;
1685 struct enum_font_dataW efdw;
1686 LOGFONT lf;
1687 HDC hdc;
1688 int i, ret, ansi_charset, symbol_charset, russian_charset;
1690 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1692 if (*font_name && !is_truetype_font_installed(font_name))
1694 skip("%s is not installed\n", font_name);
1695 return;
1698 hdc = GetDC(0);
1700 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1701 * while EnumFontFamiliesEx doesn't.
1703 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1706 * Use EnumFontFamiliesW since win98 crashes when the
1707 * second parameter is NULL using EnumFontFamilies
1709 efdw.total = 0;
1710 SetLastError(0xdeadbeef);
1711 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1712 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1713 if(ret)
1715 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1716 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1717 ansi_charset, symbol_charset, russian_charset);
1718 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1719 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1720 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1721 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1724 efdw.total = 0;
1725 SetLastError(0xdeadbeef);
1726 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1727 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1728 if(ret)
1730 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1731 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1732 ansi_charset, symbol_charset, russian_charset);
1733 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1734 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1735 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1736 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1740 efd.total = 0;
1741 SetLastError(0xdeadbeef);
1742 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1743 ok(ret, "EnumFontFamilies 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\n",
1746 ansi_charset, symbol_charset, russian_charset,
1747 *font_name ? font_name : "<empty>");
1748 if (*font_name)
1749 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1750 else
1751 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1752 for (i = 0; i < efd.total; i++)
1754 /* FIXME: remove completely once Wine is fixed */
1755 if (efd.lf[i].lfCharSet != font_charset)
1757 todo_wine
1758 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1760 else
1761 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1762 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1763 font_name, efd.lf[i].lfFaceName);
1766 memset(&lf, 0, sizeof(lf));
1767 lf.lfCharSet = ANSI_CHARSET;
1768 lstrcpy(lf.lfFaceName, font_name);
1769 efd.total = 0;
1770 SetLastError(0xdeadbeef);
1771 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1772 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1773 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1774 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1775 ansi_charset, symbol_charset, russian_charset,
1776 *font_name ? font_name : "<empty>");
1777 if (font_charset == SYMBOL_CHARSET)
1779 if (*font_name)
1780 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1781 else
1782 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1784 else
1786 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1787 for (i = 0; i < efd.total; i++)
1789 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1790 if (*font_name)
1791 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1792 font_name, efd.lf[i].lfFaceName);
1796 /* DEFAULT_CHARSET should enumerate all available charsets */
1797 memset(&lf, 0, sizeof(lf));
1798 lf.lfCharSet = DEFAULT_CHARSET;
1799 lstrcpy(lf.lfFaceName, font_name);
1800 efd.total = 0;
1801 SetLastError(0xdeadbeef);
1802 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1803 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1804 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1805 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1806 ansi_charset, symbol_charset, russian_charset,
1807 *font_name ? font_name : "<empty>");
1808 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1809 for (i = 0; i < efd.total; i++)
1811 if (*font_name)
1812 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1813 font_name, efd.lf[i].lfFaceName);
1815 if (*font_name)
1817 switch (font_charset)
1819 case ANSI_CHARSET:
1820 ok(ansi_charset > 0,
1821 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1822 ok(!symbol_charset,
1823 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1824 ok(russian_charset > 0,
1825 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1826 break;
1827 case SYMBOL_CHARSET:
1828 ok(!ansi_charset,
1829 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1830 ok(symbol_charset,
1831 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1832 ok(!russian_charset,
1833 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1834 break;
1835 case DEFAULT_CHARSET:
1836 ok(ansi_charset > 0,
1837 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1838 ok(symbol_charset > 0,
1839 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1840 ok(russian_charset > 0,
1841 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1842 break;
1845 else
1847 ok(ansi_charset > 0,
1848 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1849 ok(symbol_charset > 0,
1850 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1851 ok(russian_charset > 0,
1852 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1855 memset(&lf, 0, sizeof(lf));
1856 lf.lfCharSet = SYMBOL_CHARSET;
1857 lstrcpy(lf.lfFaceName, font_name);
1858 efd.total = 0;
1859 SetLastError(0xdeadbeef);
1860 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1861 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1862 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1863 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1864 ansi_charset, symbol_charset, russian_charset,
1865 *font_name ? font_name : "<empty>");
1866 if (*font_name && font_charset == ANSI_CHARSET)
1867 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1868 else
1870 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1871 for (i = 0; i < efd.total; i++)
1873 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1874 if (*font_name)
1875 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1876 font_name, efd.lf[i].lfFaceName);
1879 ok(!ansi_charset,
1880 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1881 ok(symbol_charset > 0,
1882 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1883 ok(!russian_charset,
1884 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1887 ReleaseDC(0, hdc);
1890 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1892 HFONT hfont, hfont_prev;
1893 DWORD ret;
1894 GLYPHMETRICS gm1, gm2;
1895 LOGFONTA lf2 = *lf;
1896 WORD idx;
1897 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1899 if(!pGetGlyphIndicesA)
1901 skip("GetGlyphIndicesA is unavailable\n");
1902 return;
1905 /* negative widths are handled just as positive ones */
1906 lf2.lfWidth = -lf->lfWidth;
1908 SetLastError(0xdeadbeef);
1909 hfont = CreateFontIndirectA(lf);
1910 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1911 check_font("original", lf, hfont);
1913 hfont_prev = SelectObject(hdc, hfont);
1915 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1916 if (ret == GDI_ERROR || idx == 0xffff)
1918 SelectObject(hdc, hfont_prev);
1919 DeleteObject(hfont);
1920 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1921 return;
1924 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1925 memset(&gm1, 0xab, sizeof(gm1));
1926 SetLastError(0xdeadbeef);
1927 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1928 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1930 SelectObject(hdc, hfont_prev);
1931 DeleteObject(hfont);
1933 SetLastError(0xdeadbeef);
1934 hfont = CreateFontIndirectA(&lf2);
1935 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1936 check_font("negative width", &lf2, hfont);
1938 hfont_prev = SelectObject(hdc, hfont);
1940 memset(&gm2, 0xbb, sizeof(gm2));
1941 SetLastError(0xdeadbeef);
1942 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1943 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1945 SelectObject(hdc, hfont_prev);
1946 DeleteObject(hfont);
1948 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1949 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1950 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1951 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1952 gm1.gmCellIncX == gm2.gmCellIncX &&
1953 gm1.gmCellIncY == gm2.gmCellIncY,
1954 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1955 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1956 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1957 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1958 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1961 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1962 #include "pshpack2.h"
1963 typedef struct
1965 USHORT version;
1966 SHORT xAvgCharWidth;
1967 USHORT usWeightClass;
1968 USHORT usWidthClass;
1969 SHORT fsType;
1970 SHORT ySubscriptXSize;
1971 SHORT ySubscriptYSize;
1972 SHORT ySubscriptXOffset;
1973 SHORT ySubscriptYOffset;
1974 SHORT ySuperscriptXSize;
1975 SHORT ySuperscriptYSize;
1976 SHORT ySuperscriptXOffset;
1977 SHORT ySuperscriptYOffset;
1978 SHORT yStrikeoutSize;
1979 SHORT yStrikeoutPosition;
1980 SHORT sFamilyClass;
1981 PANOSE panose;
1982 ULONG ulUnicodeRange1;
1983 ULONG ulUnicodeRange2;
1984 ULONG ulUnicodeRange3;
1985 ULONG ulUnicodeRange4;
1986 CHAR achVendID[4];
1987 USHORT fsSelection;
1988 USHORT usFirstCharIndex;
1989 USHORT usLastCharIndex;
1990 /* According to the Apple spec, original version didn't have the below fields,
1991 * version numbers were taked from the OpenType spec.
1993 /* version 0 (TrueType 1.5) */
1994 USHORT sTypoAscender;
1995 USHORT sTypoDescender;
1996 USHORT sTypoLineGap;
1997 USHORT usWinAscent;
1998 USHORT usWinDescent;
1999 /* version 1 (TrueType 1.66) */
2000 ULONG ulCodePageRange1;
2001 ULONG ulCodePageRange2;
2002 /* version 2 (OpenType 1.2) */
2003 SHORT sxHeight;
2004 SHORT sCapHeight;
2005 USHORT usDefaultChar;
2006 USHORT usBreakChar;
2007 USHORT usMaxContext;
2008 } TT_OS2_V2;
2009 #include "poppack.h"
2011 #ifdef WORDS_BIGENDIAN
2012 #define GET_BE_WORD(x) (x)
2013 #define GET_BE_DWORD(x) (x)
2014 #else
2015 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2016 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2017 #endif
2019 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2020 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2021 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2022 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2023 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2025 typedef struct
2027 USHORT version;
2028 USHORT num_tables;
2029 } cmap_header;
2031 typedef struct
2033 USHORT plat_id;
2034 USHORT enc_id;
2035 ULONG offset;
2036 } cmap_encoding_record;
2038 typedef struct
2040 USHORT format;
2041 USHORT length;
2042 USHORT language;
2044 BYTE glyph_ids[256];
2045 } cmap_format_0;
2047 typedef struct
2049 USHORT format;
2050 USHORT length;
2051 USHORT language;
2053 USHORT seg_countx2;
2054 USHORT search_range;
2055 USHORT entry_selector;
2056 USHORT range_shift;
2058 USHORT end_count[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2059 /* Then follows:
2060 USHORT pad;
2061 USHORT start_count[seg_countx2 / 2];
2062 USHORT id_delta[seg_countx2 / 2];
2063 USHORT id_range_offset[seg_countx2 / 2];
2064 USHORT glyph_ids[];
2066 } cmap_format_4;
2068 typedef struct
2070 USHORT end_count;
2071 USHORT start_count;
2072 USHORT id_delta;
2073 USHORT id_range_offset;
2074 } cmap_format_4_seg;
2076 static void expect_ff(const TEXTMETRICA *tmA, const TT_OS2_V2 *os2, WORD family, const char *name)
2078 ok((tmA->tmPitchAndFamily & 0xf0) == family, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2079 name, family, tmA->tmPitchAndFamily, os2->panose.bFamilyType, os2->panose.bSerifStyle,
2080 os2->panose.bWeight, os2->panose.bProportion);
2083 static BOOL get_first_last_from_cmap0(void *ptr, DWORD *first, DWORD *last)
2085 int i;
2086 cmap_format_0 *cmap = (cmap_format_0*)ptr;
2088 *first = 256;
2090 for(i = 0; i < 256; i++)
2092 if(cmap->glyph_ids[i] == 0) continue;
2093 *last = i;
2094 if(*first == 256) *first = i;
2096 if(*first == 256) return FALSE;
2097 return TRUE;
2100 static void get_seg4(cmap_format_4 *cmap, USHORT seg_num, cmap_format_4_seg *seg)
2102 USHORT segs = GET_BE_WORD(cmap->seg_countx2) / 2;
2103 seg->end_count = GET_BE_WORD(cmap->end_count[seg_num]);
2104 seg->start_count = GET_BE_WORD(cmap->end_count[segs + 1 + seg_num]);
2105 seg->id_delta = GET_BE_WORD(cmap->end_count[2 * segs + 1 + seg_num]);
2106 seg->id_range_offset = GET_BE_WORD(cmap->end_count[3 * segs + 1 + seg_num]);
2109 static BOOL get_first_last_from_cmap4(void *ptr, DWORD *first, DWORD *last)
2111 int i;
2112 cmap_format_4 *cmap = (cmap_format_4*)ptr;
2113 USHORT seg_count = GET_BE_WORD(cmap->seg_countx2) / 2;
2114 USHORT const *glyph_ids = cmap->end_count + 4 * seg_count + 1;
2116 *first = 0x10000;
2118 for(i = 0; i < seg_count; i++)
2120 DWORD code, index;
2121 cmap_format_4_seg seg;
2123 get_seg4(cmap, i, &seg);
2124 for(code = seg.start_count; code <= seg.end_count; code++)
2126 if(seg.id_range_offset == 0)
2127 index = (seg.id_delta + code) & 0xffff;
2128 else
2130 index = seg.id_range_offset / 2
2131 + code - seg.start_count
2132 + i - seg_count;
2134 index = GET_BE_WORD(glyph_ids[index]);
2135 if(index) index += seg.id_delta;
2137 if(index)
2139 *last = code;
2140 if(*first == 0x10000) *first = code;
2145 if(*first == 0x10000) return FALSE;
2146 return TRUE;
2149 static void *get_cmap(cmap_header *header, USHORT plat_id, USHORT enc_id)
2151 USHORT i;
2152 cmap_encoding_record *record = (cmap_encoding_record *)(header + 1);
2154 for(i = 0; i < GET_BE_WORD(header->num_tables); i++)
2156 if(GET_BE_WORD(record->plat_id) == plat_id && GET_BE_WORD(record->enc_id) == enc_id)
2157 return (BYTE *)header + GET_BE_DWORD(record->offset);
2158 record++;
2160 return NULL;
2163 static BOOL get_first_last_from_cmap(HDC hdc, DWORD *first, DWORD *last)
2165 LONG size, ret;
2166 cmap_header *header;
2167 void *cmap;
2168 BOOL r = FALSE;
2169 WORD format;
2171 size = GetFontData(hdc, MS_CMAP_TAG, 0, NULL, 0);
2172 ok(size != GDI_ERROR, "no cmap table found\n");
2173 if(size == GDI_ERROR) return FALSE;
2175 header = HeapAlloc(GetProcessHeap(), 0, size);
2176 ret = GetFontData(hdc, MS_CMAP_TAG, 0, header, size);
2177 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2178 ok(GET_BE_WORD(header->version) == 0, "got cmap version %d\n", GET_BE_WORD(header->version));
2180 cmap = get_cmap(header, 3, 1);
2181 if(!cmap) cmap = get_cmap(header, 3, 0);
2182 if(!cmap) goto end;
2184 format = GET_BE_WORD(*(WORD *)cmap);
2185 switch(format)
2187 case 0:
2188 r = get_first_last_from_cmap0(cmap, first, last);
2189 break;
2190 case 4:
2191 r = get_first_last_from_cmap4(cmap, first, last);
2192 break;
2193 default:
2194 trace("unhandled cmap format %d\n", format);
2195 break;
2198 end:
2199 HeapFree(GetProcessHeap(), 0, header);
2200 return r;
2203 static void test_text_metrics(const LOGFONTA *lf)
2205 HDC hdc;
2206 HFONT hfont, hfont_old;
2207 TEXTMETRICA tmA;
2208 TT_OS2_V2 tt_os2;
2209 LONG size, ret;
2210 const char *font_name = lf->lfFaceName;
2211 DWORD cmap_first = 0, cmap_last = 0;
2213 hdc = GetDC(0);
2215 SetLastError(0xdeadbeef);
2216 hfont = CreateFontIndirectA(lf);
2217 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2219 hfont_old = SelectObject(hdc, hfont);
2221 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2222 if (size == GDI_ERROR)
2224 trace("OS/2 chunk was not found\n");
2225 goto end_of_test;
2227 if (size > sizeof(tt_os2))
2229 trace("got too large OS/2 chunk of size %u\n", size);
2230 size = sizeof(tt_os2);
2233 memset(&tt_os2, 0, sizeof(tt_os2));
2234 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2235 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2237 SetLastError(0xdeadbeef);
2238 ret = GetTextMetricsA(hdc, &tmA);
2239 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2241 if(!get_first_last_from_cmap(hdc, &cmap_first, &cmap_last))
2243 skip("Unable to retrieve first and last glyphs from cmap\n");
2245 else
2247 USHORT expect_first_A, expect_last_A, expect_break_A, expect_default_A;
2248 USHORT expect_first_W, expect_last_W, expect_break_W, expect_default_W;
2249 UINT os2_first_char, os2_last_char, default_char, break_char;
2250 USHORT version;
2251 TEXTMETRICW tmW;
2253 version = GET_BE_WORD(tt_os2.version);
2255 os2_first_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2256 os2_last_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2257 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2258 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2260 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2261 font_name, lf->lfCharSet, os2_first_char, os2_last_char, cmap_first, cmap_last,
2262 default_char, break_char, version, (LPCSTR)&tt_os2.achVendID);
2264 if (lf->lfCharSet == SYMBOL_CHARSET || (cmap_first >= 0xf000 && cmap_first < 0xf100))
2266 expect_first_W = 0;
2267 expect_last_W = 0xf0ff;
2268 expect_break_W = 0x20;
2269 expect_default_W = expect_break_W - 1;
2270 expect_first_A = 0x1e;
2271 expect_last_A = min(os2_last_char - os2_first_char + 0x20, 0xff);
2273 else
2275 expect_first_W = cmap_first;
2276 expect_last_W = min(cmap_last, os2_last_char);
2277 if(os2_first_char <= 1)
2278 expect_break_W = os2_first_char + 2;
2279 else if(os2_first_char > 0xff)
2280 expect_break_W = 0x20;
2281 else
2282 expect_break_W = os2_first_char;
2283 expect_default_W = expect_break_W - 1;
2284 expect_first_A = expect_default_W - 1;
2285 expect_last_A = min(expect_last_W, 0xff);
2287 expect_break_A = expect_break_W;
2288 expect_default_A = expect_default_W;
2290 ok(tmA.tmFirstChar == expect_first_A ||
2291 tmA.tmFirstChar == expect_first_A + 1 /* win9x */,
2292 "A: tmFirstChar for %s got %02x expected %02x\n", font_name, tmA.tmFirstChar, expect_first_A);
2293 ok(tmA.tmLastChar == expect_last_A ||
2294 tmA.tmLastChar == 0xff /* win9x */,
2295 "A: tmLastChar for %s got %02x expected %02x\n", font_name, tmA.tmLastChar, expect_last_A);
2296 ok(tmA.tmBreakChar == expect_break_A, "A: tmBreakChar for %s got %02x expected %02x\n",
2297 font_name, tmA.tmBreakChar, expect_break_A);
2298 ok(tmA.tmDefaultChar == expect_default_A, "A: tmDefaultChar for %s got %02x expected %02x\n",
2299 font_name, tmA.tmDefaultChar, expect_default_A);
2302 SetLastError(0xdeadbeef);
2303 ret = GetTextMetricsW(hdc, &tmW);
2304 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2305 "GetTextMetricsW error %u\n", GetLastError());
2306 if (ret)
2308 if(cmap_first != os2_first_char && tmW.tmCharSet != SYMBOL_CHARSET)
2309 todo_wine ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2310 font_name, tmW.tmFirstChar, expect_first_W);
2311 else
2312 ok(tmW.tmFirstChar == expect_first_W, "W: tmFirstChar for %s got %02x expected %02x\n",
2313 font_name, tmW.tmFirstChar, expect_first_W);
2315 if(expect_last_W != os2_last_char && tmW.tmCharSet != SYMBOL_CHARSET)
2316 todo_wine ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2317 font_name, tmW.tmLastChar, expect_last_W);
2318 else
2319 ok(tmW.tmLastChar == expect_last_W, "W: tmLastChar for %s got %02x expected %02x\n",
2320 font_name, tmW.tmLastChar, expect_last_W);
2321 ok(tmW.tmBreakChar == expect_break_W, "W: tmBreakChar for %s got %02x expected %02x\n",
2322 font_name, tmW.tmBreakChar, expect_break_W);
2323 ok(tmW.tmDefaultChar == expect_default_W, "W: tmDefaultChar for %s got %02x expected %02x\n",
2324 font_name, tmW.tmDefaultChar, expect_default_W);
2326 /* Test the aspect ratio while we have tmW */
2327 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2328 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2329 tmW.tmDigitizedAspectX, ret);
2330 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2331 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2332 tmW.tmDigitizedAspectX, ret);
2336 /* test FF_ values */
2337 switch(tt_os2.panose.bFamilyType)
2339 case PAN_ANY:
2340 case PAN_NO_FIT:
2341 case PAN_FAMILY_TEXT_DISPLAY:
2342 case PAN_FAMILY_PICTORIAL:
2343 default:
2344 if((tmA.tmPitchAndFamily & 1) == 0) /* fixed */
2346 expect_ff(&tmA, &tt_os2, FF_MODERN, font_name);
2347 break;
2349 switch(tt_os2.panose.bSerifStyle)
2351 case PAN_ANY:
2352 case PAN_NO_FIT:
2353 default:
2354 expect_ff(&tmA, &tt_os2, FF_DONTCARE, font_name);
2355 break;
2357 case PAN_SERIF_COVE:
2358 case PAN_SERIF_OBTUSE_COVE:
2359 case PAN_SERIF_SQUARE_COVE:
2360 case PAN_SERIF_OBTUSE_SQUARE_COVE:
2361 case PAN_SERIF_SQUARE:
2362 case PAN_SERIF_THIN:
2363 case PAN_SERIF_BONE:
2364 case PAN_SERIF_EXAGGERATED:
2365 case PAN_SERIF_TRIANGLE:
2366 expect_ff(&tmA, &tt_os2, FF_ROMAN, font_name);
2367 break;
2369 case PAN_SERIF_NORMAL_SANS:
2370 case PAN_SERIF_OBTUSE_SANS:
2371 case PAN_SERIF_PERP_SANS:
2372 case PAN_SERIF_FLARED:
2373 case PAN_SERIF_ROUNDED:
2374 expect_ff(&tmA, &tt_os2, FF_SWISS, font_name);
2375 break;
2377 break;
2379 case PAN_FAMILY_SCRIPT:
2380 expect_ff(&tmA, &tt_os2, FF_SCRIPT, font_name);
2381 break;
2383 case PAN_FAMILY_DECORATIVE:
2384 expect_ff(&tmA, &tt_os2, FF_DECORATIVE, font_name);
2385 break;
2388 test_negative_width(hdc, lf);
2390 end_of_test:
2391 SelectObject(hdc, hfont_old);
2392 DeleteObject(hfont);
2394 ReleaseDC(0, hdc);
2397 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2399 INT *enumed = (INT *)lParam;
2401 if (type == TRUETYPE_FONTTYPE)
2403 (*enumed)++;
2404 test_text_metrics(lf);
2406 return 1;
2409 static void test_GetTextMetrics(void)
2411 LOGFONTA lf;
2412 HDC hdc;
2413 INT enumed;
2415 hdc = GetDC(0);
2417 memset(&lf, 0, sizeof(lf));
2418 lf.lfCharSet = DEFAULT_CHARSET;
2419 enumed = 0;
2420 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2421 trace("Tested metrics of %d truetype fonts\n", enumed);
2423 ReleaseDC(0, hdc);
2426 static void test_nonexistent_font(void)
2428 static const struct
2430 const char *name;
2431 int charset;
2432 } font_subst[] =
2434 { "Times New Roman Baltic", 186 },
2435 { "Times New Roman CE", 238 },
2436 { "Times New Roman CYR", 204 },
2437 { "Times New Roman Greek", 161 },
2438 { "Times New Roman TUR", 162 }
2440 LOGFONTA lf;
2441 HDC hdc;
2442 HFONT hfont;
2443 CHARSETINFO csi;
2444 INT cs, expected_cs, i;
2445 char buf[LF_FACESIZE];
2447 if (!is_truetype_font_installed("Arial") ||
2448 !is_truetype_font_installed("Times New Roman"))
2450 skip("Arial or Times New Roman not installed\n");
2451 return;
2454 expected_cs = GetACP();
2455 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2457 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2458 return;
2460 expected_cs = csi.ciCharset;
2461 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2463 hdc = GetDC(0);
2465 memset(&lf, 0, sizeof(lf));
2466 lf.lfHeight = 100;
2467 lf.lfWeight = FW_REGULAR;
2468 lf.lfCharSet = ANSI_CHARSET;
2469 lf.lfPitchAndFamily = FF_SWISS;
2470 strcpy(lf.lfFaceName, "Nonexistent font");
2471 hfont = CreateFontIndirectA(&lf);
2472 hfont = SelectObject(hdc, hfont);
2473 GetTextFaceA(hdc, sizeof(buf), buf);
2474 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2475 cs = GetTextCharset(hdc);
2476 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2477 DeleteObject(SelectObject(hdc, hfont));
2479 memset(&lf, 0, sizeof(lf));
2480 lf.lfHeight = -13;
2481 lf.lfWeight = FW_DONTCARE;
2482 strcpy(lf.lfFaceName, "Nonexistent font");
2483 hfont = CreateFontIndirectA(&lf);
2484 hfont = SelectObject(hdc, hfont);
2485 GetTextFaceA(hdc, sizeof(buf), buf);
2486 todo_wine /* Wine uses Arial for all substitutions */
2487 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2488 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2489 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2490 "Got %s\n", buf);
2491 cs = GetTextCharset(hdc);
2492 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2493 DeleteObject(SelectObject(hdc, hfont));
2495 memset(&lf, 0, sizeof(lf));
2496 lf.lfHeight = -13;
2497 lf.lfWeight = FW_REGULAR;
2498 strcpy(lf.lfFaceName, "Nonexistent font");
2499 hfont = CreateFontIndirectA(&lf);
2500 hfont = SelectObject(hdc, hfont);
2501 GetTextFaceA(hdc, sizeof(buf), buf);
2502 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2503 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2504 cs = GetTextCharset(hdc);
2505 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2506 DeleteObject(SelectObject(hdc, hfont));
2508 memset(&lf, 0, sizeof(lf));
2509 lf.lfHeight = -13;
2510 lf.lfWeight = FW_DONTCARE;
2511 strcpy(lf.lfFaceName, "Times New Roman");
2512 hfont = CreateFontIndirectA(&lf);
2513 hfont = SelectObject(hdc, hfont);
2514 GetTextFaceA(hdc, sizeof(buf), buf);
2515 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2516 cs = GetTextCharset(hdc);
2517 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2518 DeleteObject(SelectObject(hdc, hfont));
2520 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2522 memset(&lf, 0, sizeof(lf));
2523 lf.lfHeight = -13;
2524 lf.lfWeight = FW_REGULAR;
2525 strcpy(lf.lfFaceName, font_subst[i].name);
2526 hfont = CreateFontIndirectA(&lf);
2527 hfont = SelectObject(hdc, hfont);
2528 cs = GetTextCharset(hdc);
2529 if (font_subst[i].charset == expected_cs)
2531 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2532 GetTextFaceA(hdc, sizeof(buf), buf);
2533 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2535 else
2537 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2538 GetTextFaceA(hdc, sizeof(buf), buf);
2539 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2540 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2542 DeleteObject(SelectObject(hdc, hfont));
2544 memset(&lf, 0, sizeof(lf));
2545 lf.lfHeight = -13;
2546 lf.lfWeight = FW_DONTCARE;
2547 strcpy(lf.lfFaceName, font_subst[i].name);
2548 hfont = CreateFontIndirectA(&lf);
2549 hfont = SelectObject(hdc, hfont);
2550 GetTextFaceA(hdc, sizeof(buf), buf);
2551 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2552 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2553 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2554 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2555 "got %s\n", buf);
2556 cs = GetTextCharset(hdc);
2557 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2558 DeleteObject(SelectObject(hdc, hfont));
2561 ReleaseDC(0, hdc);
2564 static void test_GdiRealizationInfo(void)
2566 HDC hdc;
2567 DWORD info[4];
2568 BOOL r;
2569 HFONT hfont, hfont_old;
2570 LOGFONTA lf;
2572 if(!pGdiRealizationInfo)
2574 skip("GdiRealizationInfo not available\n");
2575 return;
2578 hdc = GetDC(0);
2580 memset(info, 0xcc, sizeof(info));
2581 r = pGdiRealizationInfo(hdc, info);
2582 ok(r != 0, "ret 0\n");
2583 ok((info[0] & 0xf) == 1, "info[0] = %x for the system font\n", info[0]);
2584 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2586 if (!is_truetype_font_installed("Arial"))
2588 skip("skipping GdiRealizationInfo with truetype font\n");
2589 goto end;
2592 memset(&lf, 0, sizeof(lf));
2593 strcpy(lf.lfFaceName, "Arial");
2594 lf.lfHeight = 20;
2595 lf.lfWeight = FW_NORMAL;
2596 hfont = CreateFontIndirectA(&lf);
2597 hfont_old = SelectObject(hdc, hfont);
2599 memset(info, 0xcc, sizeof(info));
2600 r = pGdiRealizationInfo(hdc, info);
2601 ok(r != 0, "ret 0\n");
2602 ok((info[0] & 0xf) == 3, "info[0] = %x for arial\n", info[0]);
2603 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2605 DeleteObject(SelectObject(hdc, hfont_old));
2607 end:
2608 ReleaseDC(0, hdc);
2611 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2612 the nul in the count of characters copied when the face name buffer is not
2613 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2614 always includes it. */
2615 static void test_GetTextFace(void)
2617 static const char faceA[] = "Tahoma";
2618 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2619 LOGFONTA fA = {0};
2620 LOGFONTW fW = {0};
2621 char bufA[LF_FACESIZE];
2622 WCHAR bufW[LF_FACESIZE];
2623 HFONT f, g;
2624 HDC dc;
2625 int n;
2627 if(!is_font_installed("Tahoma"))
2629 skip("Tahoma is not installed so skipping this test\n");
2630 return;
2633 /* 'A' case. */
2634 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2635 f = CreateFontIndirectA(&fA);
2636 ok(f != NULL, "CreateFontIndirectA failed\n");
2638 dc = GetDC(NULL);
2639 g = SelectObject(dc, f);
2640 n = GetTextFaceA(dc, sizeof bufA, bufA);
2641 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2642 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2644 /* Play with the count arg. */
2645 bufA[0] = 'x';
2646 n = GetTextFaceA(dc, 0, bufA);
2647 ok(n == 0, "GetTextFaceA returned %d\n", n);
2648 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2650 bufA[0] = 'x';
2651 n = GetTextFaceA(dc, 1, bufA);
2652 ok(n == 0, "GetTextFaceA returned %d\n", n);
2653 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2655 bufA[0] = 'x'; bufA[1] = 'y';
2656 n = GetTextFaceA(dc, 2, bufA);
2657 ok(n == 1, "GetTextFaceA returned %d\n", n);
2658 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2660 n = GetTextFaceA(dc, 0, NULL);
2661 ok(n == sizeof faceA ||
2662 broken(n == 0), /* win98, winMe */
2663 "GetTextFaceA returned %d\n", n);
2665 DeleteObject(SelectObject(dc, g));
2666 ReleaseDC(NULL, dc);
2668 /* 'W' case. */
2669 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2670 SetLastError(0xdeadbeef);
2671 f = CreateFontIndirectW(&fW);
2672 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2674 win_skip("CreateFontIndirectW is not implemented\n");
2675 return;
2677 ok(f != NULL, "CreateFontIndirectW failed\n");
2679 dc = GetDC(NULL);
2680 g = SelectObject(dc, f);
2681 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2682 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2683 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2685 /* Play with the count arg. */
2686 bufW[0] = 'x';
2687 n = GetTextFaceW(dc, 0, bufW);
2688 ok(n == 0, "GetTextFaceW returned %d\n", n);
2689 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2691 bufW[0] = 'x';
2692 n = GetTextFaceW(dc, 1, bufW);
2693 ok(n == 1, "GetTextFaceW returned %d\n", n);
2694 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2696 bufW[0] = 'x'; bufW[1] = 'y';
2697 n = GetTextFaceW(dc, 2, bufW);
2698 ok(n == 2, "GetTextFaceW returned %d\n", n);
2699 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2701 n = GetTextFaceW(dc, 0, NULL);
2702 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2704 DeleteObject(SelectObject(dc, g));
2705 ReleaseDC(NULL, dc);
2708 static void test_orientation(void)
2710 static const char test_str[11] = "Test String";
2711 HDC hdc;
2712 LOGFONTA lf;
2713 HFONT hfont, old_hfont;
2714 SIZE size;
2716 if (!is_truetype_font_installed("Arial"))
2718 skip("Arial is not installed\n");
2719 return;
2722 hdc = CreateCompatibleDC(0);
2723 memset(&lf, 0, sizeof(lf));
2724 lstrcpyA(lf.lfFaceName, "Arial");
2725 lf.lfHeight = 72;
2726 lf.lfOrientation = lf.lfEscapement = 900;
2727 hfont = create_font("orientation", &lf);
2728 old_hfont = SelectObject(hdc, hfont);
2729 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2730 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2731 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2732 SelectObject(hdc, old_hfont);
2733 DeleteObject(hfont);
2734 DeleteDC(hdc);
2737 static void test_GetGlyphOutline(void)
2739 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
2740 HDC hdc;
2741 GLYPHMETRICS gm;
2742 LOGFONTA lf;
2743 HFONT hfont, old_hfont;
2744 INT ret;
2746 if (!is_truetype_font_installed("Tahoma"))
2748 skip("Tahoma is not installed\n");
2749 return;
2752 hdc = CreateCompatibleDC(0);
2753 memset(&lf, 0, sizeof(lf));
2754 lf.lfHeight = 72;
2755 lstrcpyA(lf.lfFaceName, "Tahoma");
2756 SetLastError(0xdeadbeef);
2757 hfont = CreateFontIndirectA(&lf);
2758 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
2759 old_hfont = SelectObject(hdc, hfont);
2761 memset(&gm, 0, sizeof(gm));
2762 SetLastError(0xdeadbeef);
2763 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2764 ok(ret != GDI_ERROR, "GetGlyphOutlineA error %u\n", GetLastError());
2766 memset(&gm, 0, sizeof(gm));
2767 SetLastError(0xdeadbeef);
2768 ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2769 ok(ret == GDI_ERROR, "GetGlyphOutlineA should fail\n");
2770 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2772 memset(&gm, 0, sizeof(gm));
2773 SetLastError(0xdeadbeef);
2774 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
2775 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2776 ok(ret != GDI_ERROR, "GetGlyphOutlineW error %u\n", GetLastError());
2778 memset(&gm, 0, sizeof(gm));
2779 SetLastError(0xdeadbeef);
2780 ret = GetGlyphOutlineW(hdc, 'A', GGO_METRICS, &gm, 0, NULL, NULL);
2781 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
2783 ok(ret == GDI_ERROR, "GetGlyphOutlineW should fail\n");
2784 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2787 SelectObject(hdc, old_hfont);
2788 DeleteObject(hfont);
2789 DeleteDC(hdc);
2792 START_TEST(font)
2794 init();
2796 test_logfont();
2797 test_bitmap_font();
2798 test_outline_font();
2799 test_bitmap_font_metrics();
2800 test_GdiGetCharDimensions();
2801 test_GetCharABCWidths();
2802 test_text_extents();
2803 test_GetGlyphIndices();
2804 test_GetKerningPairs();
2805 test_GetOutlineTextMetrics();
2806 test_SetTextJustification();
2807 test_font_charset();
2808 test_GetFontUnicodeRanges();
2809 test_nonexistent_font();
2810 test_orientation();
2812 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2813 * I'd like to avoid them in this test.
2815 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2816 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2817 if (is_truetype_font_installed("Arial Black") &&
2818 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2820 test_EnumFontFamilies("", ANSI_CHARSET);
2821 test_EnumFontFamilies("", SYMBOL_CHARSET);
2822 test_EnumFontFamilies("", DEFAULT_CHARSET);
2824 else
2825 skip("Arial Black or Symbol/Wingdings is not installed\n");
2826 test_GetTextMetrics();
2827 test_GdiRealizationInfo();
2828 test_GetTextFace();
2829 test_GetGlyphOutline();