push c22b4aa826b27f0c6bc5101b378e6e68716a85d9
[wine/hacks.git] / dlls / gdi32 / tests / font.c
blob0624de01180ffb6cfaa5dea9fc2e2d4fd058b1aa
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 todo_wine 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;
1189 if (!is_font_installed("Arial"))
1191 skip("Arial is not installed\n");
1192 return;
1195 hdc = GetDC(0);
1197 memset(&lf, 0, sizeof(lf));
1198 strcpy(lf.lfFaceName, "Arial");
1199 lf.lfHeight = -13;
1200 lf.lfWeight = FW_NORMAL;
1201 lf.lfPitchAndFamily = DEFAULT_PITCH;
1202 lf.lfQuality = PROOF_QUALITY;
1203 hfont = CreateFontIndirect(&lf);
1204 assert(hfont != 0);
1206 hfont_old = SelectObject(hdc, hfont);
1207 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
1208 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
1210 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
1212 memset(otm, 0xAA, otm_size);
1213 SetLastError(0xdeadbeef);
1214 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
1215 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1216 ok(ret == 1 /* Win9x */ ||
1217 ret == otm->otmSize /* XP*/,
1218 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1219 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1221 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1222 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1223 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1224 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
1227 memset(otm, 0xAA, otm_size);
1228 SetLastError(0xdeadbeef);
1229 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
1230 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1231 ok(ret == 1 /* Win9x */ ||
1232 ret == otm->otmSize /* XP*/,
1233 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1234 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1236 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
1237 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
1238 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
1239 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
1242 /* ask about truncated data */
1243 memset(otm, 0xAA, otm_size);
1244 SetLastError(0xdeadbeef);
1245 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
1246 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
1247 ok(ret == 1 /* Win9x */ ||
1248 ret == otm->otmSize /* XP*/,
1249 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
1250 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
1252 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
1253 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
1254 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
1256 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
1258 HeapFree(GetProcessHeap(), 0, otm);
1260 SelectObject(hdc, hfont_old);
1261 DeleteObject(hfont);
1263 ReleaseDC(0, hdc);
1266 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
1268 INT x, y,
1269 breakCount,
1270 outputWidth = 0, /* to test TabbedTextOut() */
1271 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
1272 areaWidth = clientArea->right - clientArea->left,
1273 nErrors = 0, e;
1274 BOOL lastExtent = FALSE;
1275 PSTR pFirstChar, pLastChar;
1276 SIZE size;
1277 TEXTMETRICA tm;
1278 struct err
1280 char extent[100];
1281 int GetTextExtentExPointWWidth;
1282 int TabbedTextOutWidth;
1283 } error[10];
1285 GetTextMetricsA(hdc, &tm);
1286 y = clientArea->top;
1287 do {
1288 breakCount = 0;
1289 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
1290 pFirstChar = str;
1292 do {
1293 pLastChar = str;
1295 /* if not at the end of the string, ... */
1296 if (*str == '\0') break;
1297 /* ... add the next word to the current extent */
1298 while (*str != '\0' && *str++ != tm.tmBreakChar);
1299 breakCount++;
1300 SetTextJustification(hdc, 0, 0);
1301 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
1302 } while ((int) size.cx < areaWidth);
1304 /* ignore trailing break chars */
1305 breakCount--;
1306 while (*(pLastChar - 1) == tm.tmBreakChar)
1308 pLastChar--;
1309 breakCount--;
1312 if (*str == '\0' || breakCount <= 0) pLastChar = str;
1314 SetTextJustification(hdc, 0, 0);
1315 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1317 /* do not justify the last extent */
1318 if (*str != '\0' && breakCount > 0)
1320 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
1321 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
1322 justifiedWidth = size.cx;
1324 else lastExtent = TRUE;
1326 x = clientArea->left;
1328 outputWidth = LOWORD(TabbedTextOut(
1329 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
1330 0, NULL, 0));
1331 /* catch errors and report them */
1332 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
1334 memset(error[nErrors].extent, 0, 100);
1335 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
1336 error[nErrors].TabbedTextOutWidth = outputWidth;
1337 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
1338 nErrors++;
1341 y += size.cy;
1342 str = pLastChar;
1343 } while (*str && y < clientArea->bottom);
1345 for (e = 0; e < nErrors; e++)
1347 ok(near_match(error[e].TabbedTextOutWidth, areaWidth),
1348 "The output text (\"%s\") width should be %d, not %d.\n",
1349 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
1350 /* The width returned by GetTextExtentPoint32() is exactly the same
1351 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1352 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
1353 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1354 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
1358 static void test_SetTextJustification(void)
1360 HDC hdc;
1361 RECT clientArea;
1362 LOGFONTA lf;
1363 HFONT hfont;
1364 HWND hwnd;
1365 static char testText[] =
1366 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1367 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1368 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1369 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1370 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1371 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1372 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1374 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
1375 GetClientRect( hwnd, &clientArea );
1376 hdc = GetDC( hwnd );
1378 memset(&lf, 0, sizeof lf);
1379 lf.lfCharSet = ANSI_CHARSET;
1380 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1381 lf.lfWeight = FW_DONTCARE;
1382 lf.lfHeight = 20;
1383 lf.lfQuality = DEFAULT_QUALITY;
1384 lstrcpyA(lf.lfFaceName, "Times New Roman");
1385 hfont = create_font("Times New Roman", &lf);
1386 SelectObject(hdc, hfont);
1388 testJustification(hdc, testText, &clientArea);
1390 DeleteObject(hfont);
1391 ReleaseDC(hwnd, hdc);
1392 DestroyWindow(hwnd);
1395 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
1397 HDC hdc;
1398 LOGFONTA lf;
1399 HFONT hfont, hfont_old;
1400 CHARSETINFO csi;
1401 FONTSIGNATURE fs;
1402 INT cs;
1403 DWORD i, ret;
1404 char name[64];
1406 assert(count <= 128);
1408 memset(&lf, 0, sizeof(lf));
1410 lf.lfCharSet = charset;
1411 lf.lfHeight = 10;
1412 lstrcpyA(lf.lfFaceName, "Arial");
1413 SetLastError(0xdeadbeef);
1414 hfont = CreateFontIndirectA(&lf);
1415 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1417 hdc = GetDC(0);
1418 hfont_old = SelectObject(hdc, hfont);
1420 cs = GetTextCharsetInfo(hdc, &fs, 0);
1421 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1423 SetLastError(0xdeadbeef);
1424 ret = GetTextFaceA(hdc, sizeof(name), name);
1425 ok(ret, "GetTextFaceA error %u\n", GetLastError());
1427 if (charset == SYMBOL_CHARSET)
1429 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1430 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1432 else
1434 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1435 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1438 if (!TranslateCharsetInfo((DWORD *)(INT_PTR)cs, &csi, TCI_SRCCHARSET))
1440 trace("Can't find codepage for charset %d\n", cs);
1441 ReleaseDC(0, hdc);
1442 return FALSE;
1444 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1446 if (unicode)
1448 char ansi_buf[128];
1449 WCHAR unicode_buf[128];
1451 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1453 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1455 SetLastError(0xdeadbeef);
1456 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1457 ok(ret == count, "GetGlyphIndicesW error %u\n", GetLastError());
1459 else
1461 char ansi_buf[128];
1463 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1465 SetLastError(0xdeadbeef);
1466 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1467 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1470 SelectObject(hdc, hfont_old);
1471 DeleteObject(hfont);
1473 ReleaseDC(0, hdc);
1475 return TRUE;
1478 static void test_font_charset(void)
1480 static struct charset_data
1482 INT charset;
1483 UINT code_page;
1484 WORD font_idxA[128], font_idxW[128];
1485 } cd[] =
1487 { ANSI_CHARSET, 1252 },
1488 { RUSSIAN_CHARSET, 1251 },
1489 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1491 int i;
1493 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1495 skip("Skipping the font charset test on a Win9x platform\n");
1496 return;
1499 if (!is_font_installed("Arial"))
1501 skip("Arial is not installed\n");
1502 return;
1505 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1507 if (cd[i].charset == SYMBOL_CHARSET)
1509 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1511 skip("Symbol or Wingdings is not installed\n");
1512 break;
1515 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1516 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1517 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1520 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1521 if (i > 2)
1523 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1524 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1526 else
1527 skip("Symbol or Wingdings is not installed\n");
1530 static void test_GetFontUnicodeRanges(void)
1532 LOGFONTA lf;
1533 HDC hdc;
1534 HFONT hfont, hfont_old;
1535 DWORD size;
1536 GLYPHSET *gs;
1538 if (!pGetFontUnicodeRanges)
1540 skip("GetFontUnicodeRanges not available before W2K\n");
1541 return;
1544 memset(&lf, 0, sizeof(lf));
1545 lstrcpyA(lf.lfFaceName, "Arial");
1546 hfont = create_font("Arial", &lf);
1548 hdc = GetDC(0);
1549 hfont_old = SelectObject(hdc, hfont);
1551 size = pGetFontUnicodeRanges(NULL, NULL);
1552 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1554 size = pGetFontUnicodeRanges(hdc, NULL);
1555 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1557 gs = HeapAlloc(GetProcessHeap(), 0, size);
1559 size = pGetFontUnicodeRanges(hdc, gs);
1560 ok(size, "GetFontUnicodeRanges failed\n");
1561 #if 0
1562 for (i = 0; i < gs->cRanges; i++)
1563 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1564 #endif
1565 trace("found %u ranges\n", gs->cRanges);
1567 HeapFree(GetProcessHeap(), 0, gs);
1569 SelectObject(hdc, hfont_old);
1570 DeleteObject(hfont);
1571 ReleaseDC(NULL, hdc);
1574 #define MAX_ENUM_FONTS 4096
1576 struct enum_font_data
1578 int total;
1579 LOGFONT lf[MAX_ENUM_FONTS];
1582 struct enum_font_dataW
1584 int total;
1585 LOGFONTW lf[MAX_ENUM_FONTS];
1588 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1590 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1592 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1594 if (type != TRUETYPE_FONTTYPE) return 1;
1595 #if 0
1596 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1597 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1598 #endif
1599 if (efd->total < MAX_ENUM_FONTS)
1600 efd->lf[efd->total++] = *lf;
1601 else
1602 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1604 return 1;
1607 static INT CALLBACK arial_enum_procw(const LOGFONTW *lf, const TEXTMETRICW *tm, DWORD type, LPARAM lParam)
1609 struct enum_font_dataW *efd = (struct enum_font_dataW *)lParam;
1611 ok(lf->lfHeight == tm->tmHeight, "lfHeight %d != tmHeight %d\n", lf->lfHeight, tm->tmHeight);
1613 if (type != TRUETYPE_FONTTYPE) return 1;
1614 #if 0
1615 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1616 lf->lfFaceName, lf->lfCharSet, lf->lfHeight, lf->lfWeight, lf->lfItalic);
1617 #endif
1618 if (efd->total < MAX_ENUM_FONTS)
1619 efd->lf[efd->total++] = *lf;
1620 else
1621 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS);
1623 return 1;
1626 static void get_charset_stats(struct enum_font_data *efd,
1627 int *ansi_charset, int *symbol_charset,
1628 int *russian_charset)
1630 int i;
1632 *ansi_charset = 0;
1633 *symbol_charset = 0;
1634 *russian_charset = 0;
1636 for (i = 0; i < efd->total; i++)
1638 switch (efd->lf[i].lfCharSet)
1640 case ANSI_CHARSET:
1641 (*ansi_charset)++;
1642 break;
1643 case SYMBOL_CHARSET:
1644 (*symbol_charset)++;
1645 break;
1646 case RUSSIAN_CHARSET:
1647 (*russian_charset)++;
1648 break;
1653 static void get_charset_statsW(struct enum_font_dataW *efd,
1654 int *ansi_charset, int *symbol_charset,
1655 int *russian_charset)
1657 int i;
1659 *ansi_charset = 0;
1660 *symbol_charset = 0;
1661 *russian_charset = 0;
1663 for (i = 0; i < efd->total; i++)
1665 switch (efd->lf[i].lfCharSet)
1667 case ANSI_CHARSET:
1668 (*ansi_charset)++;
1669 break;
1670 case SYMBOL_CHARSET:
1671 (*symbol_charset)++;
1672 break;
1673 case RUSSIAN_CHARSET:
1674 (*russian_charset)++;
1675 break;
1680 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1682 struct enum_font_data efd;
1683 struct enum_font_dataW efdw;
1684 LOGFONT lf;
1685 HDC hdc;
1686 int i, ret, ansi_charset, symbol_charset, russian_charset;
1688 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1690 if (*font_name && !is_truetype_font_installed(font_name))
1692 skip("%s is not installed\n", font_name);
1693 return;
1696 hdc = GetDC(0);
1698 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1699 * while EnumFontFamiliesEx doesn't.
1701 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1704 * Use EnumFontFamiliesW since win98 crashes when the
1705 * second parameter is NULL using EnumFontFamilies
1707 efdw.total = 0;
1708 SetLastError(0xdeadbeef);
1709 ret = EnumFontFamiliesW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw);
1710 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesW error %u\n", GetLastError());
1711 if(ret)
1713 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1714 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1715 ansi_charset, symbol_charset, russian_charset);
1716 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1717 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1718 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1719 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1722 efdw.total = 0;
1723 SetLastError(0xdeadbeef);
1724 ret = EnumFontFamiliesExW(hdc, NULL, arial_enum_procw, (LPARAM)&efdw, 0);
1725 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, "EnumFontFamiliesExW error %u\n", GetLastError());
1726 if(ret)
1728 get_charset_statsW(&efdw, &ansi_charset, &symbol_charset, &russian_charset);
1729 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1730 ansi_charset, symbol_charset, russian_charset);
1731 ok(efdw.total > 0, "fonts enumerated: NULL\n");
1732 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1733 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1734 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1738 efd.total = 0;
1739 SetLastError(0xdeadbeef);
1740 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1741 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1742 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1743 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1744 ansi_charset, symbol_charset, russian_charset,
1745 *font_name ? font_name : "<empty>");
1746 if (*font_name)
1747 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1748 else
1749 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1750 for (i = 0; i < efd.total; i++)
1752 /* FIXME: remove completely once Wine is fixed */
1753 if (efd.lf[i].lfCharSet != font_charset)
1755 todo_wine
1756 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1758 else
1759 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1760 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1761 font_name, efd.lf[i].lfFaceName);
1764 memset(&lf, 0, sizeof(lf));
1765 lf.lfCharSet = ANSI_CHARSET;
1766 lstrcpy(lf.lfFaceName, font_name);
1767 efd.total = 0;
1768 SetLastError(0xdeadbeef);
1769 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1770 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1771 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1772 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1773 ansi_charset, symbol_charset, russian_charset,
1774 *font_name ? font_name : "<empty>");
1775 if (font_charset == SYMBOL_CHARSET)
1777 if (*font_name)
1778 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1779 else
1780 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1782 else
1784 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1785 for (i = 0; i < efd.total; i++)
1787 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1788 if (*font_name)
1789 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1790 font_name, efd.lf[i].lfFaceName);
1794 /* DEFAULT_CHARSET should enumerate all available charsets */
1795 memset(&lf, 0, sizeof(lf));
1796 lf.lfCharSet = DEFAULT_CHARSET;
1797 lstrcpy(lf.lfFaceName, font_name);
1798 efd.total = 0;
1799 SetLastError(0xdeadbeef);
1800 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1801 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1802 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1803 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1804 ansi_charset, symbol_charset, russian_charset,
1805 *font_name ? font_name : "<empty>");
1806 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1807 for (i = 0; i < efd.total; i++)
1809 if (*font_name)
1810 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1811 font_name, efd.lf[i].lfFaceName);
1813 if (*font_name)
1815 switch (font_charset)
1817 case ANSI_CHARSET:
1818 ok(ansi_charset > 0,
1819 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1820 ok(!symbol_charset,
1821 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1822 ok(russian_charset > 0,
1823 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1824 break;
1825 case SYMBOL_CHARSET:
1826 ok(!ansi_charset,
1827 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1828 ok(symbol_charset,
1829 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1830 ok(!russian_charset,
1831 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1832 break;
1833 case DEFAULT_CHARSET:
1834 ok(ansi_charset > 0,
1835 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1836 ok(symbol_charset > 0,
1837 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1838 ok(russian_charset > 0,
1839 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1840 break;
1843 else
1845 ok(ansi_charset > 0,
1846 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1847 ok(symbol_charset > 0,
1848 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1849 ok(russian_charset > 0,
1850 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1853 memset(&lf, 0, sizeof(lf));
1854 lf.lfCharSet = SYMBOL_CHARSET;
1855 lstrcpy(lf.lfFaceName, font_name);
1856 efd.total = 0;
1857 SetLastError(0xdeadbeef);
1858 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1859 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1860 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1861 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1862 ansi_charset, symbol_charset, russian_charset,
1863 *font_name ? font_name : "<empty>");
1864 if (*font_name && font_charset == ANSI_CHARSET)
1865 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1866 else
1868 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1869 for (i = 0; i < efd.total; i++)
1871 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1872 if (*font_name)
1873 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1874 font_name, efd.lf[i].lfFaceName);
1877 ok(!ansi_charset,
1878 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1879 ok(symbol_charset > 0,
1880 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1881 ok(!russian_charset,
1882 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1885 ReleaseDC(0, hdc);
1888 static void test_negative_width(HDC hdc, const LOGFONTA *lf)
1890 HFONT hfont, hfont_prev;
1891 DWORD ret;
1892 GLYPHMETRICS gm1, gm2;
1893 LOGFONTA lf2 = *lf;
1894 WORD idx;
1895 MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
1897 if(!pGetGlyphIndicesA)
1899 skip("GetGlyphIndicesA is unavailable\n");
1900 return;
1903 /* negative widths are handled just as positive ones */
1904 lf2.lfWidth = -lf->lfWidth;
1906 SetLastError(0xdeadbeef);
1907 hfont = CreateFontIndirectA(lf);
1908 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1909 check_font("original", lf, hfont);
1911 hfont_prev = SelectObject(hdc, hfont);
1913 ret = pGetGlyphIndicesA(hdc, "x", 1, &idx, GGI_MARK_NONEXISTING_GLYPHS);
1914 if (ret == GDI_ERROR || idx == 0xffff)
1916 SelectObject(hdc, hfont_prev);
1917 DeleteObject(hfont);
1918 skip("Font %s doesn't contain 'x', skipping the test\n", lf->lfFaceName);
1919 return;
1922 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1923 memset(&gm1, 0xab, sizeof(gm1));
1924 SetLastError(0xdeadbeef);
1925 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat);
1926 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1928 SelectObject(hdc, hfont_prev);
1929 DeleteObject(hfont);
1931 SetLastError(0xdeadbeef);
1932 hfont = CreateFontIndirectA(&lf2);
1933 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1934 check_font("negative width", &lf2, hfont);
1936 hfont_prev = SelectObject(hdc, hfont);
1938 memset(&gm2, 0xbb, sizeof(gm2));
1939 SetLastError(0xdeadbeef);
1940 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat);
1941 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1943 SelectObject(hdc, hfont_prev);
1944 DeleteObject(hfont);
1946 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1947 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1948 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1949 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1950 gm1.gmCellIncX == gm2.gmCellIncX &&
1951 gm1.gmCellIncY == gm2.gmCellIncY,
1952 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1953 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1954 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1955 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1956 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1959 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1960 #include "pshpack2.h"
1961 typedef struct
1963 USHORT version;
1964 SHORT xAvgCharWidth;
1965 USHORT usWeightClass;
1966 USHORT usWidthClass;
1967 SHORT fsType;
1968 SHORT ySubscriptXSize;
1969 SHORT ySubscriptYSize;
1970 SHORT ySubscriptXOffset;
1971 SHORT ySubscriptYOffset;
1972 SHORT ySuperscriptXSize;
1973 SHORT ySuperscriptYSize;
1974 SHORT ySuperscriptXOffset;
1975 SHORT ySuperscriptYOffset;
1976 SHORT yStrikeoutSize;
1977 SHORT yStrikeoutPosition;
1978 SHORT sFamilyClass;
1979 PANOSE panose;
1980 ULONG ulUnicodeRange1;
1981 ULONG ulUnicodeRange2;
1982 ULONG ulUnicodeRange3;
1983 ULONG ulUnicodeRange4;
1984 CHAR achVendID[4];
1985 USHORT fsSelection;
1986 USHORT usFirstCharIndex;
1987 USHORT usLastCharIndex;
1988 /* According to the Apple spec, original version didn't have the below fields,
1989 * version numbers were taked from the OpenType spec.
1991 /* version 0 (TrueType 1.5) */
1992 USHORT sTypoAscender;
1993 USHORT sTypoDescender;
1994 USHORT sTypoLineGap;
1995 USHORT usWinAscent;
1996 USHORT usWinDescent;
1997 /* version 1 (TrueType 1.66) */
1998 ULONG ulCodePageRange1;
1999 ULONG ulCodePageRange2;
2000 /* version 2 (OpenType 1.2) */
2001 SHORT sxHeight;
2002 SHORT sCapHeight;
2003 USHORT usDefaultChar;
2004 USHORT usBreakChar;
2005 USHORT usMaxContext;
2006 } TT_OS2_V2;
2007 #include "poppack.h"
2009 #ifdef WORDS_BIGENDIAN
2010 #define GET_BE_WORD(x) (x)
2011 #else
2012 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2013 #endif
2015 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2016 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2017 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2018 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2020 static void test_text_metrics(const LOGFONTA *lf)
2022 HDC hdc;
2023 HFONT hfont, hfont_old;
2024 TEXTMETRICA tmA;
2025 TEXTMETRICW tmW;
2026 UINT first_unicode_char, last_unicode_char, default_char, break_char;
2027 INT test_char;
2028 TT_OS2_V2 tt_os2;
2029 USHORT version;
2030 LONG size, ret;
2031 const char *font_name = lf->lfFaceName;
2033 hdc = GetDC(0);
2035 SetLastError(0xdeadbeef);
2036 hfont = CreateFontIndirectA(lf);
2037 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
2039 hfont_old = SelectObject(hdc, hfont);
2041 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
2042 if (size == GDI_ERROR)
2044 trace("OS/2 chunk was not found\n");
2045 goto end_of_test;
2047 if (size > sizeof(tt_os2))
2049 trace("got too large OS/2 chunk of size %u\n", size);
2050 size = sizeof(tt_os2);
2053 memset(&tt_os2, 0, sizeof(tt_os2));
2054 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
2055 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
2057 version = GET_BE_WORD(tt_os2.version);
2059 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
2060 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
2061 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
2062 break_char = GET_BE_WORD(tt_os2.usBreakChar);
2064 trace("font %s charset %u: %x-%x default %x break %x OS/2 version %u vendor %4.4s\n",
2065 font_name, lf->lfCharSet, first_unicode_char, last_unicode_char, default_char, break_char,
2066 version, (LPCSTR)&tt_os2.achVendID);
2068 SetLastError(0xdeadbeef);
2069 ret = GetTextMetricsA(hdc, &tmA);
2070 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
2072 #if 0 /* FIXME: This doesn't appear to be what Windows does */
2073 test_char = min(first_unicode_char - 1, 255);
2074 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
2075 font_name, tmA.tmFirstChar, test_char);
2076 #endif
2077 if (lf->lfCharSet == SYMBOL_CHARSET)
2079 test_char = min(last_unicode_char - 0xf000, 255);
2080 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2081 font_name, tmA.tmLastChar, test_char);
2083 else
2085 test_char = min(last_unicode_char, 255);
2086 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
2087 font_name, tmA.tmLastChar, test_char);
2090 SetLastError(0xdeadbeef);
2091 ret = GetTextMetricsW(hdc, &tmW);
2092 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
2093 "GetTextMetricsW error %u\n", GetLastError());
2094 if (ret)
2096 trace("%04x-%04x (%02x-%02x) default %x (%x) break %x (%x)\n",
2097 tmW.tmFirstChar, tmW.tmLastChar, tmA.tmFirstChar, tmA.tmLastChar,
2098 tmW.tmDefaultChar, tmA.tmDefaultChar, tmW.tmBreakChar, tmA.tmBreakChar);
2100 if (lf->lfCharSet == SYMBOL_CHARSET)
2102 /* It appears that for fonts with SYMBOL_CHARSET Windows always
2103 * sets symbol range to 0 - f0ff
2105 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
2106 font_name, tmW.tmFirstChar);
2107 /* FIXME: Windows returns f0ff here, while Wine f0xx */
2108 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
2109 font_name, tmW.tmLastChar);
2111 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
2112 font_name, tmW.tmDefaultChar);
2113 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
2114 font_name, tmW.tmBreakChar);
2116 else
2118 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
2119 font_name, tmW.tmFirstChar, first_unicode_char);
2120 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
2121 font_name, tmW.tmLastChar, last_unicode_char);
2123 ret = GetDeviceCaps(hdc, LOGPIXELSX);
2124 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
2125 tmW.tmDigitizedAspectX, ret);
2126 ret = GetDeviceCaps(hdc, LOGPIXELSY);
2127 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
2128 tmW.tmDigitizedAspectX, ret);
2131 test_negative_width(hdc, lf);
2133 end_of_test:
2134 SelectObject(hdc, hfont_old);
2135 DeleteObject(hfont);
2137 ReleaseDC(0, hdc);
2140 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
2142 INT *enumed = (INT *)lParam;
2144 if (type == TRUETYPE_FONTTYPE)
2146 (*enumed)++;
2147 test_text_metrics(lf);
2149 return 1;
2152 static void test_GetTextMetrics(void)
2154 LOGFONTA lf;
2155 HDC hdc;
2156 INT enumed;
2158 hdc = GetDC(0);
2160 memset(&lf, 0, sizeof(lf));
2161 lf.lfCharSet = DEFAULT_CHARSET;
2162 enumed = 0;
2163 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
2164 trace("Tested metrics of %d truetype fonts\n", enumed);
2166 ReleaseDC(0, hdc);
2169 static void test_nonexistent_font(void)
2171 static const struct
2173 const char *name;
2174 int charset;
2175 } font_subst[] =
2177 { "Times New Roman Baltic", 186 },
2178 { "Times New Roman CE", 238 },
2179 { "Times New Roman CYR", 204 },
2180 { "Times New Roman Greek", 161 },
2181 { "Times New Roman TUR", 162 }
2183 LOGFONTA lf;
2184 HDC hdc;
2185 HFONT hfont;
2186 CHARSETINFO csi;
2187 INT cs, expected_cs, i;
2188 char buf[LF_FACESIZE];
2190 if (!is_truetype_font_installed("Arial") ||
2191 !is_truetype_font_installed("Times New Roman"))
2193 skip("Arial or Times New Roman not installed\n");
2194 return;
2197 expected_cs = GetACP();
2198 if (!TranslateCharsetInfo(ULongToPtr(expected_cs), &csi, TCI_SRCCODEPAGE))
2200 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs);
2201 return;
2203 expected_cs = csi.ciCharset;
2204 trace("ACP %d -> charset %d\n", GetACP(), expected_cs);
2206 hdc = GetDC(0);
2208 memset(&lf, 0, sizeof(lf));
2209 lf.lfHeight = 100;
2210 lf.lfWeight = FW_REGULAR;
2211 lf.lfCharSet = ANSI_CHARSET;
2212 lf.lfPitchAndFamily = FF_SWISS;
2213 strcpy(lf.lfFaceName, "Nonexistent font");
2214 hfont = CreateFontIndirectA(&lf);
2215 hfont = SelectObject(hdc, hfont);
2216 GetTextFaceA(hdc, sizeof(buf), buf);
2217 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
2218 cs = GetTextCharset(hdc);
2219 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2220 DeleteObject(SelectObject(hdc, hfont));
2222 memset(&lf, 0, sizeof(lf));
2223 lf.lfHeight = -13;
2224 lf.lfWeight = FW_DONTCARE;
2225 strcpy(lf.lfFaceName, "Nonexistent font");
2226 hfont = CreateFontIndirectA(&lf);
2227 hfont = SelectObject(hdc, hfont);
2228 GetTextFaceA(hdc, sizeof(buf), buf);
2229 todo_wine /* Wine uses Arial for all substitutions */
2230 ok(!lstrcmpiA(buf, "Nonexistent font") /* XP, Vista */ ||
2231 !lstrcmpiA(buf, "MS Serif") || /* Win9x */
2232 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2233 "Got %s\n", buf);
2234 cs = GetTextCharset(hdc);
2235 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2236 DeleteObject(SelectObject(hdc, hfont));
2238 memset(&lf, 0, sizeof(lf));
2239 lf.lfHeight = -13;
2240 lf.lfWeight = FW_REGULAR;
2241 strcpy(lf.lfFaceName, "Nonexistent font");
2242 hfont = CreateFontIndirectA(&lf);
2243 hfont = SelectObject(hdc, hfont);
2244 GetTextFaceA(hdc, sizeof(buf), buf);
2245 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2246 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "Got %s\n", buf);
2247 cs = GetTextCharset(hdc);
2248 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2249 DeleteObject(SelectObject(hdc, hfont));
2251 memset(&lf, 0, sizeof(lf));
2252 lf.lfHeight = -13;
2253 lf.lfWeight = FW_DONTCARE;
2254 strcpy(lf.lfFaceName, "Times New Roman");
2255 hfont = CreateFontIndirectA(&lf);
2256 hfont = SelectObject(hdc, hfont);
2257 GetTextFaceA(hdc, sizeof(buf), buf);
2258 ok(!lstrcmpiA(buf, "Times New Roman"), "Got %s\n", buf);
2259 cs = GetTextCharset(hdc);
2260 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2261 DeleteObject(SelectObject(hdc, hfont));
2263 for (i = 0; i < sizeof(font_subst)/sizeof(font_subst[0]); i++)
2265 memset(&lf, 0, sizeof(lf));
2266 lf.lfHeight = -13;
2267 lf.lfWeight = FW_REGULAR;
2268 strcpy(lf.lfFaceName, font_subst[i].name);
2269 hfont = CreateFontIndirectA(&lf);
2270 hfont = SelectObject(hdc, hfont);
2271 cs = GetTextCharset(hdc);
2272 if (font_subst[i].charset == expected_cs)
2274 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2275 GetTextFaceA(hdc, sizeof(buf), buf);
2276 ok(!lstrcmpiA(buf, font_subst[i].name), "expected %s, got %s\n", font_subst[i].name, buf);
2278 else
2280 ok(cs == ANSI_CHARSET, "expected ANSI_CHARSET, got %d\n", cs);
2281 GetTextFaceA(hdc, sizeof(buf), buf);
2282 ok(!lstrcmpiA(buf, "Arial") /* XP, Vista */ ||
2283 !lstrcmpiA(buf, "Times New Roman") /* Win9x */, "got %s\n", buf);
2285 DeleteObject(SelectObject(hdc, hfont));
2287 memset(&lf, 0, sizeof(lf));
2288 lf.lfHeight = -13;
2289 lf.lfWeight = FW_DONTCARE;
2290 strcpy(lf.lfFaceName, font_subst[i].name);
2291 hfont = CreateFontIndirectA(&lf);
2292 hfont = SelectObject(hdc, hfont);
2293 GetTextFaceA(hdc, sizeof(buf), buf);
2294 ok(!lstrcmpiA(buf, "Arial") /* Wine */ ||
2295 !lstrcmpiA(buf, font_subst[i].name) /* XP, Vista */ ||
2296 !lstrcmpiA(buf, "MS Serif") /* Win9x */ ||
2297 !lstrcmpiA(buf, "MS Sans Serif"), /* win2k3 */
2298 "got %s\n", buf);
2299 cs = GetTextCharset(hdc);
2300 ok(cs == expected_cs, "expected %d, got %d\n", expected_cs, cs);
2301 DeleteObject(SelectObject(hdc, hfont));
2304 ReleaseDC(0, hdc);
2307 static void test_GdiRealizationInfo(void)
2309 HDC hdc;
2310 DWORD info[4];
2311 BOOL r;
2312 HFONT hfont, hfont_old;
2313 LOGFONTA lf;
2315 if(!pGdiRealizationInfo)
2317 skip("GdiRealizationInfo not available\n");
2318 return;
2321 hdc = GetDC(0);
2323 memset(info, 0xcc, sizeof(info));
2324 r = pGdiRealizationInfo(hdc, info);
2325 ok(r != 0, "ret 0\n");
2326 ok(info[0] == 1, "info[0] = %x for the system font\n", info[0]);
2327 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2329 if (!is_truetype_font_installed("Arial"))
2331 skip("skipping GdiRealizationInfo with truetype font\n");
2332 goto end;
2335 memset(&lf, 0, sizeof(lf));
2336 strcpy(lf.lfFaceName, "Arial");
2337 lf.lfHeight = 20;
2338 lf.lfWeight = FW_NORMAL;
2339 hfont = CreateFontIndirectA(&lf);
2340 hfont_old = SelectObject(hdc, hfont);
2342 memset(info, 0xcc, sizeof(info));
2343 r = pGdiRealizationInfo(hdc, info);
2344 ok(r != 0, "ret 0\n");
2345 ok(info[0] == 3, "info[0] = %x for arial\n", info[0]);
2346 ok(info[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2348 DeleteObject(SelectObject(hdc, hfont_old));
2350 end:
2351 ReleaseDC(0, hdc);
2354 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2355 the nul in the count of characters copied when the face name buffer is not
2356 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2357 always includes it. */
2358 static void test_GetTextFace(void)
2360 static const char faceA[] = "Tahoma";
2361 static const WCHAR faceW[] = {'T','a','h','o','m','a', 0};
2362 LOGFONTA fA = {0};
2363 LOGFONTW fW = {0};
2364 char bufA[LF_FACESIZE];
2365 WCHAR bufW[LF_FACESIZE];
2366 HFONT f, g;
2367 HDC dc;
2368 int n;
2370 if(!is_font_installed("Tahoma"))
2372 skip("Tahoma is not installed so skipping this test\n");
2373 return;
2376 /* 'A' case. */
2377 memcpy(fA.lfFaceName, faceA, sizeof faceA);
2378 f = CreateFontIndirectA(&fA);
2379 ok(f != NULL, "CreateFontIndirectA failed\n");
2381 dc = GetDC(NULL);
2382 g = SelectObject(dc, f);
2383 n = GetTextFaceA(dc, sizeof bufA, bufA);
2384 ok(n == sizeof faceA - 1, "GetTextFaceA returned %d\n", n);
2385 ok(lstrcmpA(faceA, bufA) == 0, "GetTextFaceA\n");
2387 /* Play with the count arg. */
2388 bufA[0] = 'x';
2389 n = GetTextFaceA(dc, 0, bufA);
2390 ok(n == 0, "GetTextFaceA returned %d\n", n);
2391 ok(bufA[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2393 bufA[0] = 'x';
2394 n = GetTextFaceA(dc, 1, bufA);
2395 ok(n == 0, "GetTextFaceA returned %d\n", n);
2396 ok(bufA[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA[0]);
2398 bufA[0] = 'x'; bufA[1] = 'y';
2399 n = GetTextFaceA(dc, 2, bufA);
2400 ok(n == 1, "GetTextFaceA returned %d\n", n);
2401 ok(bufA[0] == faceA[0] && bufA[1] == '\0', "GetTextFaceA didn't copy\n");
2403 n = GetTextFaceA(dc, 0, NULL);
2404 ok(n == sizeof faceA, "GetTextFaceA returned %d\n", n);
2406 DeleteObject(SelectObject(dc, g));
2407 ReleaseDC(NULL, dc);
2409 /* 'W' case. */
2410 memcpy(fW.lfFaceName, faceW, sizeof faceW);
2411 SetLastError(0xdeadbeef);
2412 f = CreateFontIndirectW(&fW);
2413 if (!f && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2415 win_skip("CreateFontIndirectW is not implemented\n");
2416 return;
2418 ok(f != NULL, "CreateFontIndirectW failed\n");
2420 dc = GetDC(NULL);
2421 g = SelectObject(dc, f);
2422 n = GetTextFaceW(dc, sizeof bufW / sizeof bufW[0], bufW);
2423 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2424 ok(lstrcmpW(faceW, bufW) == 0, "GetTextFaceW\n");
2426 /* Play with the count arg. */
2427 bufW[0] = 'x';
2428 n = GetTextFaceW(dc, 0, bufW);
2429 ok(n == 0, "GetTextFaceW returned %d\n", n);
2430 ok(bufW[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2432 bufW[0] = 'x';
2433 n = GetTextFaceW(dc, 1, bufW);
2434 ok(n == 1, "GetTextFaceW returned %d\n", n);
2435 ok(bufW[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW[0]);
2437 bufW[0] = 'x'; bufW[1] = 'y';
2438 n = GetTextFaceW(dc, 2, bufW);
2439 ok(n == 2, "GetTextFaceW returned %d\n", n);
2440 ok(bufW[0] == faceW[0] && bufW[1] == '\0', "GetTextFaceW didn't copy\n");
2442 n = GetTextFaceW(dc, 0, NULL);
2443 ok(n == sizeof faceW / sizeof faceW[0], "GetTextFaceW returned %d\n", n);
2445 DeleteObject(SelectObject(dc, g));
2446 ReleaseDC(NULL, dc);
2449 static void test_orientation(void)
2451 static const char test_str[11] = "Test String";
2452 HDC hdc;
2453 LOGFONTA lf;
2454 HFONT hfont, old_hfont;
2455 SIZE size;
2457 if (!is_truetype_font_installed("Arial"))
2459 skip("Arial is not installed\n");
2460 return;
2463 hdc = CreateCompatibleDC(0);
2464 memset(&lf, 0, sizeof(lf));
2465 lstrcpyA(lf.lfFaceName, "Arial");
2466 lf.lfHeight = 72;
2467 lf.lfOrientation = lf.lfEscapement = 900;
2468 hfont = create_font("orientation", &lf);
2469 old_hfont = SelectObject(hdc, hfont);
2470 ok(GetTextExtentExPointA(hdc, test_str, sizeof(test_str), 32767, NULL, NULL, &size), "GetTextExtentExPointA failed\n");
2471 ok(near_match(311, size.cx), "cx should be about 311, got %d\n", size.cx);
2472 ok(near_match(75, size.cy), "cy should be about 75, got %d\n", size.cy);
2473 SelectObject(hdc, old_hfont);
2474 DeleteObject(hfont);
2475 DeleteDC(hdc);
2478 START_TEST(font)
2480 init();
2482 test_logfont();
2483 test_bitmap_font();
2484 test_outline_font();
2485 test_bitmap_font_metrics();
2486 test_GdiGetCharDimensions();
2487 test_GetCharABCWidths();
2488 test_text_extents();
2489 test_GetGlyphIndices();
2490 test_GetKerningPairs();
2491 test_GetOutlineTextMetrics();
2492 test_SetTextJustification();
2493 test_font_charset();
2494 test_GetFontUnicodeRanges();
2495 test_nonexistent_font();
2496 test_orientation();
2498 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2499 * I'd like to avoid them in this test.
2501 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
2502 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
2503 if (is_truetype_font_installed("Arial Black") &&
2504 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2506 test_EnumFontFamilies("", ANSI_CHARSET);
2507 test_EnumFontFamilies("", SYMBOL_CHARSET);
2508 test_EnumFontFamilies("", DEFAULT_CHARSET);
2510 else
2511 skip("Arial Black or Symbol/Wingdings is not installed\n");
2512 test_GetTextMetrics();
2513 test_GdiRealizationInfo();
2514 test_GetTextFace();