push 50b650a476c6f0df362ce67f063848f086de44d9
[wine/hacks.git] / dlls / gdi32 / tests / font.c
blob33dd3f8b6a1786fd67135eb6cbcbae42da5caebd
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 expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
35 LONG (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
36 BOOL (WINAPI *pGetCharABCWidthsW)(HDC hdc, UINT first, UINT last, LPABC abc);
37 DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs);
38 DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags);
39 DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags);
41 static HMODULE hgdi32 = 0;
43 static void init(void)
45 hgdi32 = GetModuleHandleA("gdi32.dll");
47 pGdiGetCharDimensions = (void *)GetProcAddress(hgdi32, "GdiGetCharDimensions");
48 pGetCharABCWidthsW = (void *)GetProcAddress(hgdi32, "GetCharABCWidthsW");
49 pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges");
50 pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA");
51 pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW");
54 static INT CALLBACK is_truetype_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
56 if (type != TRUETYPE_FONTTYPE) return 1;
58 return 0;
61 static BOOL is_truetype_font_installed(const char *name)
63 HDC hdc = GetDC(0);
64 BOOL ret = FALSE;
66 if (!EnumFontFamiliesA(hdc, name, is_truetype_font_installed_proc, 0))
67 ret = TRUE;
69 ReleaseDC(0, hdc);
70 return ret;
73 static INT CALLBACK is_font_installed_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
75 return 0;
78 static BOOL is_font_installed(const char *name)
80 HDC hdc = GetDC(0);
81 BOOL ret = FALSE;
83 if(!EnumFontFamiliesA(hdc, name, is_font_installed_proc, 0))
84 ret = TRUE;
86 ReleaseDC(0, hdc);
87 return ret;
90 static void check_font(const char* test, const LOGFONTA* lf, HFONT hfont)
92 LOGFONTA getobj_lf;
93 int ret, minlen = 0;
95 if (!hfont)
96 return;
98 ret = GetObject(hfont, sizeof(getobj_lf), &getobj_lf);
99 /* NT4 tries to be clever and only returns the minimum length */
100 while (lf->lfFaceName[minlen] && minlen < LF_FACESIZE-1)
101 minlen++;
102 minlen += FIELD_OFFSET(LOGFONTA, lfFaceName) + 1;
103 ok(ret == sizeof(LOGFONTA) || ret == minlen, "%s: GetObject returned %d\n", test, ret);
104 ok(!memcmp(&lf, &lf, FIELD_OFFSET(LOGFONTA, lfFaceName)), "%s: fonts don't match\n", test);
105 ok(!lstrcmpA(lf->lfFaceName, getobj_lf.lfFaceName),
106 "%s: font names don't match: %s != %s\n", test, lf->lfFaceName, getobj_lf.lfFaceName);
109 static HFONT create_font(const char* test, const LOGFONTA* lf)
111 HFONT hfont = CreateFontIndirectA(lf);
112 ok(hfont != 0, "%s: CreateFontIndirect failed\n", test);
113 if (hfont)
114 check_font(test, lf, hfont);
115 return hfont;
118 static void test_logfont(void)
120 LOGFONTA lf;
121 HFONT hfont;
123 memset(&lf, 0, sizeof lf);
125 lf.lfCharSet = ANSI_CHARSET;
126 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
127 lf.lfWeight = FW_DONTCARE;
128 lf.lfHeight = 16;
129 lf.lfWidth = 16;
130 lf.lfQuality = DEFAULT_QUALITY;
132 lstrcpyA(lf.lfFaceName, "Arial");
133 hfont = create_font("Arial", &lf);
134 DeleteObject(hfont);
136 memset(&lf, 'A', sizeof(lf));
137 hfont = CreateFontIndirectA(&lf);
138 ok(hfont != 0, "CreateFontIndirectA with strange LOGFONT failed\n");
140 lf.lfFaceName[LF_FACESIZE - 1] = 0;
141 check_font("AAA...", &lf, hfont);
142 DeleteObject(hfont);
145 static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
147 if (type & RASTER_FONTTYPE)
149 LOGFONT *lf = (LOGFONT *)lParam;
150 *lf = *elf;
151 return 0; /* stop enumeration */
154 return 1; /* continue enumeration */
157 static void test_font_metrics(HDC hdc, HFONT hfont, const char *test_str,
158 INT test_str_len, const TEXTMETRICA *tm_orig,
159 const SIZE *size_orig, INT width_orig,
160 INT scale_x, INT scale_y)
162 HFONT old_hfont;
163 TEXTMETRICA tm;
164 SIZE size;
165 INT width;
167 if (!hfont)
168 return;
170 old_hfont = SelectObject(hdc, hfont);
172 GetTextMetricsA(hdc, &tm);
174 ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
175 ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
176 ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
177 ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
179 GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
181 ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x);
182 ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y);
184 GetCharWidthA(hdc, 'A', 'A', &width);
186 ok(width == width_orig * scale_x, "%d != %d\n", width, width_orig * scale_x);
188 SelectObject(hdc, old_hfont);
191 /* see whether GDI scales bitmap font metrics */
192 static void test_bitmap_font(void)
194 static const char test_str[11] = "Test String";
195 HDC hdc;
196 LOGFONTA bitmap_lf;
197 HFONT hfont, old_hfont;
198 TEXTMETRICA tm_orig;
199 SIZE size_orig;
200 INT ret, i, width_orig, height_orig;
202 hdc = GetDC(0);
204 /* "System" has only 1 pixel size defined, otherwise the test breaks */
205 ret = EnumFontFamiliesA(hdc, "System", font_enum_proc, (LPARAM)&bitmap_lf);
206 if (ret)
208 ReleaseDC(0, hdc);
209 trace("no bitmap fonts were found, skipping the test\n");
210 return;
213 trace("found bitmap font %s, height %d\n", bitmap_lf.lfFaceName, bitmap_lf.lfHeight);
215 height_orig = bitmap_lf.lfHeight;
216 hfont = create_font("bitmap", &bitmap_lf);
218 old_hfont = SelectObject(hdc, hfont);
219 ok(GetTextMetricsA(hdc, &tm_orig), "GetTextMetricsA failed\n");
220 ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
221 ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
222 SelectObject(hdc, old_hfont);
223 DeleteObject(hfont);
225 /* test fractional scaling */
226 for (i = 1; i < height_orig; i++)
228 hfont = create_font("fractional", &bitmap_lf);
229 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 1, 1);
230 DeleteObject(hfont);
233 /* test integer scaling 3x2 */
234 bitmap_lf.lfHeight = height_orig * 2;
235 bitmap_lf.lfWidth *= 3;
236 hfont = create_font("3x2", &bitmap_lf);
237 todo_wine
239 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 2);
241 DeleteObject(hfont);
243 /* test integer scaling 3x3 */
244 bitmap_lf.lfHeight = height_orig * 3;
245 bitmap_lf.lfWidth = 0;
246 hfont = create_font("3x3", &bitmap_lf);
248 todo_wine
250 test_font_metrics(hdc, hfont, test_str, sizeof(test_str), &tm_orig, &size_orig, width_orig, 3, 3);
252 DeleteObject(hfont);
254 ReleaseDC(0, hdc);
257 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
259 LOGFONT *lf = (LOGFONT *)lParam;
261 if (elf->lfHeight == lf->lfHeight && !strcmp(elf->lfFaceName, lf->lfFaceName))
263 *lf = *elf;
264 return 0; /* stop enumeration */
266 return 1; /* continue enumeration */
269 #define CP1252_BIT 0x00000001
270 #define CP1250_BIT 0x00000002
271 #define CP1251_BIT 0x00000004
272 #define CP1253_BIT 0x00000008
273 #define CP1254_BIT 0x00000010
274 #define CP1255_BIT 0x00000020
275 #define CP1256_BIT 0x00000040
276 #define CP1257_BIT 0x00000080
277 #define CP1258_BIT 0x00000100
278 #define CP874_BIT 0x00010000
279 #define CP932_BIT 0x00020000
280 #define CP936_BIT 0x00040000
281 #define CP949_BIT 0x00080000
282 #define CP950_BIT 0x00100000
284 static void test_bitmap_font_metrics(void)
286 static const struct font_data
288 const char face_name[LF_FACESIZE];
289 int weight, height, ascent, descent, int_leading, ext_leading;
290 int ave_char_width, max_char_width;
291 DWORD ansi_bitfield;
292 } fd[] =
294 { "MS Sans Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT | CP1250_BIT | CP1251_BIT },
295 { "MS Sans Serif", FW_NORMAL, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT | CP1250_BIT | CP1251_BIT },
296 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 16, CP1252_BIT | CP1251_BIT },
297 { "MS Sans Serif", FW_NORMAL, 20, 16, 4, 4, 0, 8, 18, CP1250_BIT },
298 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 19, CP1252_BIT },
299 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 24, CP1250_BIT },
300 { "MS Sans Serif", FW_NORMAL, 24, 19, 5, 6, 0, 9, 20, CP1251_BIT },
301 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 24, CP1252_BIT },
302 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 6, 0, 12, 24, CP1250_BIT },
303 { "MS Sans Serif", FW_NORMAL, 29, 23, 6, 5, 0, 12, 25, CP1251_BIT },
304 { "MS Sans Serif", FW_NORMAL, 37, 29, 8, 5, 0, 16, 32, CP1252_BIT | CP1250_BIT | CP1251_BIT },
305 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
306 { "MS Serif", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
307 { "MS Serif", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
308 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 11, CP1252_BIT },
309 { "MS Serif", FW_NORMAL, 13, 11, 2, 2, 0, 5, 12, CP1250_BIT | CP1251_BIT },
310 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 14, CP1252_BIT | CP1250_BIT },
311 { "MS Serif", FW_NORMAL, 16, 13, 3, 3, 0, 6, 16, CP1251_BIT },
312 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 18, CP1252_BIT | CP1250_BIT },
313 { "MS Serif", FW_NORMAL, 19, 15, 4, 3, 0, 8, 19, CP1251_BIT },
314 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 17, CP1252_BIT },
315 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 22, CP1250_BIT },
316 { "MS Serif", FW_NORMAL, 21, 16, 5, 3, 0, 9, 23, CP1251_BIT },
317 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 23, CP1252_BIT },
318 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 26, CP1250_BIT },
319 { "MS Serif", FW_NORMAL, 27, 21, 6, 3, 0, 12, 27, CP1251_BIT },
320 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 33, CP1252_BIT | CP1250_BIT },
321 { "MS Serif", FW_NORMAL, 35, 27, 8, 3, 0, 16, 34, CP1251_BIT },
322 { "Courier", FW_NORMAL, 13, 11, 2, 0, 0, 8, 8, CP1252_BIT | CP1250_BIT | CP1251_BIT },
323 { "Courier", FW_NORMAL, 16, 13, 3, 0, 0, 9, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
324 { "Courier", FW_NORMAL, 20, 16, 4, 0, 0, 12, 12, CP1252_BIT | CP1250_BIT | CP1251_BIT },
325 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 14, CP1252_BIT },
326 { "System", FW_BOLD, 16, 13, 3, 3, 0, 7, 15, CP1250_BIT | CP1251_BIT },
327 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT},
328 { "Small Fonts", FW_NORMAL, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT | CP1251_BIT },
329 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT },
330 { "Small Fonts", FW_NORMAL, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT | CP1251_BIT },
331 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT },
332 { "Small Fonts", FW_NORMAL, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT | CP1251_BIT },
333 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT },
334 { "Small Fonts", FW_NORMAL, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT | CP1251_BIT },
335 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT | CP1250_BIT },
336 { "Small Fonts", FW_NORMAL, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT },
337 { "Small Fonts", FW_NORMAL, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT | CP1250_BIT | CP1251_BIT },
338 { "Fixedsys", FW_NORMAL, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT | CP1250_BIT },
339 { "Fixedsys", FW_NORMAL, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT }
341 /* FIXME: add "Terminal" */
343 HDC hdc;
344 LOGFONT lf;
345 HFONT hfont, old_hfont;
346 TEXTMETRIC tm;
347 INT ret, i;
349 hdc = CreateCompatibleDC(0);
350 assert(hdc);
352 for (i = 0; i < sizeof(fd)/sizeof(fd[0]); i++)
354 int bit;
356 memset(&lf, 0, sizeof(lf));
358 lf.lfHeight = fd[i].height;
359 strcpy(lf.lfFaceName, fd[i].face_name);
361 for(bit = 0; bit < 32; bit++)
363 DWORD fs[2];
364 CHARSETINFO csi;
366 fs[0] = 1L << bit;
367 fs[1] = 0;
368 if((fd[i].ansi_bitfield & fs[0]) == 0) continue;
369 if(!TranslateCharsetInfo( fs, &csi, TCI_SRCFONTSIG )) continue;
371 lf.lfCharSet = csi.ciCharset;
372 ret = EnumFontFamiliesEx(hdc, &lf, find_font_proc, (LPARAM)&lf, 0);
373 if (ret) continue;
375 trace("found font %s, height %d charset %x\n", lf.lfFaceName, lf.lfHeight, lf.lfCharSet);
377 hfont = create_font(lf.lfFaceName, &lf);
378 old_hfont = SelectObject(hdc, hfont);
379 ok(GetTextMetrics(hdc, &tm), "GetTextMetrics error %d\n", GetLastError());
381 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);
382 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);
383 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);
384 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);
385 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);
386 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);
387 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);
389 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
390 that make the max width bigger */
391 if(strcmp(lf.lfFaceName, "System") || lf.lfCharSet != ANSI_CHARSET)
392 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);
394 SelectObject(hdc, old_hfont);
395 DeleteObject(hfont);
399 DeleteDC(hdc);
402 static void test_GdiGetCharDimensions(void)
404 HDC hdc;
405 TEXTMETRICW tm;
406 LONG ret;
407 SIZE size;
408 LONG avgwidth, height;
409 static const char szAlphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
411 if (!pGdiGetCharDimensions)
413 skip("GdiGetCharDimensions not available on this platform\n");
414 return;
417 hdc = CreateCompatibleDC(NULL);
419 GetTextExtentPoint(hdc, szAlphabet, strlen(szAlphabet), &size);
420 avgwidth = ((size.cx / 26) + 1) / 2;
422 ret = pGdiGetCharDimensions(hdc, &tm, &height);
423 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
424 ok(height == tm.tmHeight, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm.tmHeight, height);
426 ret = pGdiGetCharDimensions(hdc, &tm, NULL);
427 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
429 ret = pGdiGetCharDimensions(hdc, NULL, NULL);
430 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
432 height = 0;
433 ret = pGdiGetCharDimensions(hdc, NULL, &height);
434 ok(ret == avgwidth, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth, ret);
435 ok(height == size.cy, "GdiGetCharDimensions should have set height to %d instead of %d\n", size.cy, height);
437 DeleteDC(hdc);
440 static void test_GetCharABCWidthsW(void)
442 BOOL ret;
443 ABC abc[1];
444 if (!pGetCharABCWidthsW) return;
446 ret = pGetCharABCWidthsW(NULL, 'a', 'a', abc);
447 ok(!ret, "GetCharABCWidthsW should have returned FALSE\n");
450 static void test_text_extents(void)
452 static const WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
453 LPINT extents;
454 INT i, len, fit1, fit2;
455 LOGFONTA lf;
456 TEXTMETRICA tm;
457 HDC hdc;
458 HFONT hfont;
459 SIZE sz;
460 SIZE sz1, sz2;
462 memset(&lf, 0, sizeof(lf));
463 strcpy(lf.lfFaceName, "Arial");
464 lf.lfHeight = 20;
466 hfont = CreateFontIndirectA(&lf);
467 hdc = GetDC(0);
468 hfont = SelectObject(hdc, hfont);
469 GetTextMetricsA(hdc, &tm);
470 GetTextExtentPointA(hdc, "o", 1, &sz);
471 ok(sz.cy == tm.tmHeight, "cy %d tmHeight %d\n", sz.cy, tm.tmHeight);
473 SetLastError(0xdeadbeef);
474 GetTextExtentExPointW(hdc, wt, 1, 1, &fit1, &fit2, &sz1);
475 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
477 skip("Skipping remainder of text extents test on a Win9x platform\n");
478 hfont = SelectObject(hdc, hfont);
479 DeleteObject(hfont);
480 ReleaseDC(0, hdc);
481 return;
484 len = lstrlenW(wt);
485 extents = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof extents[0]);
486 extents[0] = 1; /* So that the increasing sequence test will fail
487 if the extents array is untouched. */
488 GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
489 GetTextExtentPointW(hdc, wt, len, &sz2);
490 ok(sz1.cy == sz2.cy,
491 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1.cy, sz2.cy);
492 /* Because of the '\n' in the string GetTextExtentExPoint and
493 GetTextExtentPoint return different widths under Win2k, but
494 under WinXP they return the same width. So we don't test that
495 here. */
497 for (i = 1; i < len; ++i)
498 ok(extents[i-1] <= extents[i],
499 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
501 ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
502 ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
503 ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
504 GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
505 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
506 ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
507 GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
508 ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
509 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, extents + 2, &sz2);
510 ok(extents[0] == extents[2] && extents[1] == extents[3],
511 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
512 GetTextExtentExPointW(hdc, wt, 2, 0, NULL, NULL, &sz1);
513 ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
514 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
515 HeapFree(GetProcessHeap(), 0, extents);
517 hfont = SelectObject(hdc, hfont);
518 DeleteObject(hfont);
519 ReleaseDC(NULL, hdc);
522 static void test_GetGlyphIndices(void)
524 HDC hdc;
525 HFONT hfont;
526 DWORD charcount;
527 LOGFONTA lf;
528 DWORD flags = 0;
529 WCHAR testtext[] = {'T','e','s','t',0xffff,0};
530 WORD glyphs[(sizeof(testtext)/2)-1];
531 TEXTMETRIC textm;
533 if (!pGetGlyphIndicesW) {
534 skip("GetGlyphIndices not available on platform\n");
535 return;
538 if(!is_font_installed("Symbol"))
540 skip("Symbol is not installed so skipping this test\n");
541 return;
544 memset(&lf, 0, sizeof(lf));
545 strcpy(lf.lfFaceName, "Symbol");
546 lf.lfHeight = 20;
548 hfont = CreateFontIndirectA(&lf);
549 hdc = GetDC(0);
551 ok(GetTextMetrics(hdc, &textm), "GetTextMetric failed\n");
552 flags |= GGI_MARK_NONEXISTING_GLYPHS;
553 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
554 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
555 ok(glyphs[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs[4]);
556 flags = 0;
557 charcount = pGetGlyphIndicesW(hdc, testtext, (sizeof(testtext)/2)-1, glyphs, flags);
558 ok(charcount == 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount);
559 ok(glyphs[4] == textm.tmDefaultChar, "GetGlyphIndices should have returned a %04x not %04x\n",
560 textm.tmDefaultChar, glyphs[4]);
563 static void test_GetKerningPairs(void)
565 static const struct kerning_data
567 const char face_name[LF_FACESIZE];
568 LONG height;
569 /* some interesting fields from OUTLINETEXTMETRIC */
570 LONG tmHeight, tmAscent, tmDescent;
571 UINT otmEMSquare;
572 INT otmAscent;
573 INT otmDescent;
574 UINT otmLineGap;
575 UINT otmsCapEmHeight;
576 UINT otmsXHeight;
577 INT otmMacAscent;
578 INT otmMacDescent;
579 UINT otmMacLineGap;
580 UINT otmusMinimumPPEM;
581 /* small subset of kerning pairs to test */
582 DWORD total_kern_pairs;
583 const KERNINGPAIR kern_pair[26];
584 } kd[] =
586 {"Arial", 12, 12, 9, 3,
587 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
590 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
591 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
592 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
593 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
594 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
595 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
596 {933,970,+1},{933,972,-1}
599 {"Arial", -34, 39, 32, 7,
600 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
603 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
604 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
605 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
606 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
607 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
608 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
609 {933,970,+2},{933,972,-3}
612 { "Arial", 120, 120, 97, 23,
613 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
616 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
617 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
618 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
619 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
620 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
621 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
622 {933,970,+6},{933,972,-10}
625 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
626 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
627 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
630 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
631 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
632 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
633 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
634 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
635 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
636 {933,970,+54},{933,972,-83}
639 #endif
641 LOGFONT lf;
642 HFONT hfont, hfont_old;
643 KERNINGPAIR *kern_pair;
644 HDC hdc;
645 DWORD total_kern_pairs, ret, i, n, matches;
647 hdc = GetDC(0);
649 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
650 * which may render this test unusable, so we're trying to avoid that.
652 SetLastError(0xdeadbeef);
653 GetKerningPairsW(hdc, 0, NULL);
654 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
656 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
657 ReleaseDC(0, hdc);
658 return;
661 for (i = 0; i < sizeof(kd)/sizeof(kd[0]); i++)
663 OUTLINETEXTMETRICW otm;
665 if (!is_font_installed(kd[i].face_name))
667 trace("%s is not installed so skipping this test\n", kd[i].face_name);
668 continue;
671 trace("testing font %s, height %d\n", kd[i].face_name, kd[i].height);
673 memset(&lf, 0, sizeof(lf));
674 strcpy(lf.lfFaceName, kd[i].face_name);
675 lf.lfHeight = kd[i].height;
676 hfont = CreateFontIndirect(&lf);
677 assert(hfont != 0);
679 hfont_old = SelectObject(hdc, hfont);
681 SetLastError(0xdeadbeef);
682 otm.otmSize = sizeof(otm); /* just in case for Win9x compatibility */
683 ok(GetOutlineTextMetricsW(hdc, sizeof(otm), &otm) == sizeof(otm), "GetOutlineTextMetricsW error %d\n", GetLastError());
685 ok(kd[i].tmHeight == otm.otmTextMetrics.tmHeight, "expected %d, got %d\n",
686 kd[i].tmHeight, otm.otmTextMetrics.tmHeight);
687 ok(kd[i].tmAscent == otm.otmTextMetrics.tmAscent, "expected %d, got %d\n",
688 kd[i].tmAscent, otm.otmTextMetrics.tmAscent);
689 ok(kd[i].tmDescent == otm.otmTextMetrics.tmDescent, "expected %d, got %d\n",
690 kd[i].tmDescent, otm.otmTextMetrics.tmDescent);
692 ok(kd[i].otmEMSquare == otm.otmEMSquare, "expected %u, got %u\n",
693 kd[i].otmEMSquare, otm.otmEMSquare);
694 ok(kd[i].otmAscent == otm.otmAscent, "expected %d, got %d\n",
695 kd[i].otmAscent, otm.otmAscent);
696 ok(kd[i].otmDescent == otm.otmDescent, "expected %d, got %d\n",
697 kd[i].otmDescent, otm.otmDescent);
698 ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
699 kd[i].otmLineGap, otm.otmLineGap);
700 todo_wine {
701 ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
702 kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
703 ok(kd[i].otmsXHeight == otm.otmsXHeight, "expected %u, got %u\n",
704 kd[i].otmsXHeight, otm.otmsXHeight);
705 ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
706 kd[i].otmMacAscent, otm.otmMacAscent);
707 ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
708 kd[i].otmMacDescent, otm.otmMacDescent);
709 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
710 if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
711 kd[i].otmMacLineGap, otm.otmMacLineGap);
712 ok(kd[i].otmusMinimumPPEM == otm.otmusMinimumPPEM, "expected %u, got %u\n",
713 kd[i].otmusMinimumPPEM, otm.otmusMinimumPPEM);
716 total_kern_pairs = GetKerningPairsW(hdc, 0, NULL);
717 trace("total_kern_pairs %u\n", total_kern_pairs);
718 kern_pair = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pair));
720 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
721 SetLastError(0xdeadbeef);
722 ret = GetKerningPairsW(hdc, 0, kern_pair);
723 ok(GetLastError() == ERROR_INVALID_PARAMETER,
724 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
725 ok(ret == 0, "got %lu, expected 0\n", ret);
726 #endif
728 ret = GetKerningPairsW(hdc, 100, NULL);
729 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
731 ret = GetKerningPairsW(hdc, total_kern_pairs/2, kern_pair);
732 ok(ret == total_kern_pairs/2, "got %u, expected %u\n", ret, total_kern_pairs/2);
734 ret = GetKerningPairsW(hdc, total_kern_pairs, kern_pair);
735 ok(ret == total_kern_pairs, "got %u, expected %u\n", ret, total_kern_pairs);
737 matches = 0;
739 for (n = 0; n < ret; n++)
741 DWORD j;
742 #if 0
743 if (kern_pair[n].wFirst < 127 && kern_pair[n].wSecond < 127)
744 trace("{'%c','%c',%d},\n",
745 kern_pair[n].wFirst, kern_pair[n].wSecond, kern_pair[n].iKernAmount);
746 #endif
747 for (j = 0; j < kd[i].total_kern_pairs; j++)
749 if (kern_pair[n].wFirst == kd[i].kern_pair[j].wFirst &&
750 kern_pair[n].wSecond == kd[i].kern_pair[j].wSecond)
752 ok(kern_pair[n].iKernAmount == kd[i].kern_pair[j].iKernAmount,
753 "pair %d:%d got %d, expected %d\n",
754 kern_pair[n].wFirst, kern_pair[n].wSecond,
755 kern_pair[n].iKernAmount, kd[i].kern_pair[j].iKernAmount);
756 matches++;
761 ok(matches == kd[i].total_kern_pairs, "got matches %u, expected %u\n",
762 matches, kd[i].total_kern_pairs);
764 HeapFree(GetProcessHeap(), 0, kern_pair);
766 SelectObject(hdc, hfont_old);
767 DeleteObject(hfont);
770 ReleaseDC(0, hdc);
773 static void test_GetOutlineTextMetrics(void)
775 OUTLINETEXTMETRIC *otm;
776 LOGFONT lf;
777 HFONT hfont, hfont_old;
778 HDC hdc;
779 DWORD ret, otm_size;
781 if (!is_font_installed("Arial"))
783 skip("Arial is not installed\n");
784 return;
787 hdc = GetDC(0);
789 memset(&lf, 0, sizeof(lf));
790 strcpy(lf.lfFaceName, "Arial");
791 lf.lfHeight = -13;
792 lf.lfWeight = FW_NORMAL;
793 lf.lfPitchAndFamily = DEFAULT_PITCH;
794 lf.lfQuality = PROOF_QUALITY;
795 hfont = CreateFontIndirect(&lf);
796 assert(hfont != 0);
798 hfont_old = SelectObject(hdc, hfont);
799 otm_size = GetOutlineTextMetrics(hdc, 0, NULL);
800 trace("otm buffer size %u (0x%x)\n", otm_size, otm_size);
802 otm = HeapAlloc(GetProcessHeap(), 0, otm_size);
804 memset(otm, 0xAA, otm_size);
805 SetLastError(0xdeadbeef);
806 otm->otmSize = sizeof(*otm); /* just in case for Win9x compatibility */
807 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
808 ok(ret == 1 /* Win9x */ ||
809 ret == otm->otmSize /* XP*/,
810 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
811 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
813 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
814 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
815 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
816 ok(otm->otmpFullName == NULL, "expected NULL got %p\n", otm->otmpFullName);
819 memset(otm, 0xAA, otm_size);
820 SetLastError(0xdeadbeef);
821 otm->otmSize = otm_size; /* just in case for Win9x compatibility */
822 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
823 ok(ret == 1 /* Win9x */ ||
824 ret == otm->otmSize /* XP*/,
825 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
826 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
828 ok(otm->otmpFamilyName != NULL, "expected not NULL got %p\n", otm->otmpFamilyName);
829 ok(otm->otmpFaceName != NULL, "expected not NULL got %p\n", otm->otmpFaceName);
830 ok(otm->otmpStyleName != NULL, "expected not NULL got %p\n", otm->otmpStyleName);
831 ok(otm->otmpFullName != NULL, "expected not NULL got %p\n", otm->otmpFullName);
834 /* ask about truncated data */
835 memset(otm, 0xAA, otm_size);
836 SetLastError(0xdeadbeef);
837 otm->otmSize = sizeof(*otm) - sizeof(LPSTR); /* just in case for Win9x compatibility */
838 ret = GetOutlineTextMetrics(hdc, otm->otmSize, otm);
839 ok(ret == 1 /* Win9x */ ||
840 ret == otm->otmSize /* XP*/,
841 "expected %u, got %u, error %d\n", otm->otmSize, ret, GetLastError());
842 if (ret != 1) /* Win9x doesn't care about pointing beyond of the buffer */
844 ok(otm->otmpFamilyName == NULL, "expected NULL got %p\n", otm->otmpFamilyName);
845 ok(otm->otmpFaceName == NULL, "expected NULL got %p\n", otm->otmpFaceName);
846 ok(otm->otmpStyleName == NULL, "expected NULL got %p\n", otm->otmpStyleName);
848 ok(otm->otmpFullName == (LPSTR)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm->otmpFullName);
850 HeapFree(GetProcessHeap(), 0, otm);
852 SelectObject(hdc, hfont_old);
853 DeleteObject(hfont);
855 ReleaseDC(0, hdc);
858 static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
860 INT x, y,
861 breakCount,
862 outputWidth = 0, /* to test TabbedTextOut() */
863 justifiedWidth = 0, /* to test GetTextExtentExPointW() */
864 areaWidth = clientArea->right - clientArea->left,
865 nErrors = 0, e;
866 BOOL lastExtent = FALSE;
867 PSTR pFirstChar, pLastChar;
868 SIZE size;
869 TEXTMETRICA tm;
870 struct err
872 char extent[100];
873 int GetTextExtentExPointWWidth;
874 int TabbedTextOutWidth;
875 } error[10];
877 GetTextMetricsA(hdc, &tm);
878 y = clientArea->top;
879 do {
880 breakCount = 0;
881 while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
882 pFirstChar = str;
884 do {
885 pLastChar = str;
887 /* if not at the end of the string, ... */
888 if (*str == '\0') break;
889 /* ... add the next word to the current extent */
890 while (*str != '\0' && *str++ != tm.tmBreakChar);
891 breakCount++;
892 SetTextJustification(hdc, 0, 0);
893 GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
894 } while ((int) size.cx < areaWidth);
896 /* ignore trailing break chars */
897 breakCount--;
898 while (*(pLastChar - 1) == tm.tmBreakChar)
900 pLastChar--;
901 breakCount--;
904 if (*str == '\0' || breakCount <= 0) pLastChar = str;
906 SetTextJustification(hdc, 0, 0);
907 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
909 /* do not justify the last extent */
910 if (*str != '\0' && breakCount > 0)
912 SetTextJustification(hdc, areaWidth - size.cx, breakCount);
913 GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
914 justifiedWidth = size.cx;
916 else lastExtent = TRUE;
918 x = clientArea->left;
920 outputWidth = LOWORD(TabbedTextOut(
921 hdc, x, y, pFirstChar, pLastChar - pFirstChar,
922 0, NULL, 0));
923 /* catch errors and report them */
924 if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
926 memset(error[nErrors].extent, 0, 100);
927 memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
928 error[nErrors].TabbedTextOutWidth = outputWidth;
929 error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
930 nErrors++;
933 y += size.cy;
934 str = pLastChar;
935 } while (*str && y < clientArea->bottom);
937 for (e = 0; e < nErrors; e++)
939 ok(error[e].TabbedTextOutWidth == areaWidth,
940 "The output text (\"%s\") width should be %d, not %d.\n",
941 error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
942 /* The width returned by GetTextExtentPoint32() is exactly the same
943 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
944 ok(error[e].GetTextExtentExPointWWidth == areaWidth,
945 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
946 error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
950 static void test_SetTextJustification(void)
952 HDC hdc;
953 RECT clientArea;
954 LOGFONTA lf;
955 HFONT hfont;
956 HWND hwnd;
957 static char testText[] =
958 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
959 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
960 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
961 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
962 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
963 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
964 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
966 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0, 400,400, 0, 0, 0, NULL);
967 GetClientRect( hwnd, &clientArea );
968 hdc = GetDC( hwnd );
970 memset(&lf, 0, sizeof lf);
971 lf.lfCharSet = ANSI_CHARSET;
972 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
973 lf.lfWeight = FW_DONTCARE;
974 lf.lfHeight = 20;
975 lf.lfQuality = DEFAULT_QUALITY;
976 lstrcpyA(lf.lfFaceName, "Times New Roman");
977 hfont = create_font("Times New Roman", &lf);
978 SelectObject(hdc, hfont);
980 testJustification(hdc, testText, &clientArea);
982 DeleteObject(hfont);
983 ReleaseDC(hwnd, hdc);
984 DestroyWindow(hwnd);
987 static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count, BOOL unicode)
989 HDC hdc;
990 LOGFONTA lf;
991 HFONT hfont, hfont_old;
992 CHARSETINFO csi;
993 FONTSIGNATURE fs;
994 INT cs;
995 DWORD i, ret;
996 char name[64];
998 assert(count <= 128);
1000 memset(&lf, 0, sizeof(lf));
1002 lf.lfCharSet = charset;
1003 lf.lfHeight = 10;
1004 lstrcpyA(lf.lfFaceName, "Arial");
1005 SetLastError(0xdeadbeef);
1006 hfont = CreateFontIndirectA(&lf);
1007 ok(hfont != 0, "CreateFontIndirectA error %u\n", GetLastError());
1009 hdc = GetDC(0);
1010 hfont_old = SelectObject(hdc, hfont);
1012 cs = GetTextCharsetInfo(hdc, &fs, 0);
1013 ok(cs == charset, "expected %d, got %d\n", charset, cs);
1015 SetLastError(0xdeadbeef);
1016 ret = GetTextFace(hdc, sizeof(name), name);
1017 ok(ret, "GetTextFace error %u\n", GetLastError());
1019 if (charset == SYMBOL_CHARSET)
1021 ok(strcmp("Arial", name), "face name should NOT be Arial\n");
1022 ok(fs.fsCsb[0] & (1 << 31), "symbol encoding should be available\n");
1024 else
1026 ok(!strcmp("Arial", name), "face name should be Arial, not %s\n", name);
1027 ok(!(fs.fsCsb[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1030 if (!TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
1032 trace("Can't find codepage for charset %d\n", cs);
1033 ReleaseDC(0, hdc);
1034 return FALSE;
1036 ok(csi.ciACP == code_page, "expected %d, got %d\n", code_page, csi.ciACP);
1038 if (unicode)
1040 char ansi_buf[128];
1041 WCHAR unicode_buf[128];
1043 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1045 MultiByteToWideChar(code_page, 0, ansi_buf, count, unicode_buf, count);
1047 SetLastError(0xdeadbeef);
1048 ret = pGetGlyphIndicesW(hdc, unicode_buf, count, idx, 0);
1049 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1051 else
1053 char ansi_buf[128];
1055 for (i = 0; i < count; i++) ansi_buf[i] = (BYTE)(i + 128);
1057 SetLastError(0xdeadbeef);
1058 ret = pGetGlyphIndicesA(hdc, ansi_buf, count, idx, 0);
1059 ok(ret == count, "GetGlyphIndicesA error %u\n", GetLastError());
1062 SelectObject(hdc, hfont_old);
1063 DeleteObject(hfont);
1065 ReleaseDC(0, hdc);
1067 return TRUE;
1070 static void test_font_charset(void)
1072 static struct charset_data
1074 INT charset;
1075 UINT code_page;
1076 WORD font_idxA[128], font_idxW[128];
1077 } cd[] =
1079 { ANSI_CHARSET, 1252 },
1080 { RUSSIAN_CHARSET, 1251 },
1081 { SYMBOL_CHARSET, CP_SYMBOL } /* keep it as the last one */
1083 int i;
1085 if (!pGetGlyphIndicesA || !pGetGlyphIndicesW)
1087 skip("Skipping the font charset test on a Win9x platform\n");
1088 return;
1091 if (!is_font_installed("Arial"))
1093 skip("Arial is not installed\n");
1094 return;
1097 for (i = 0; i < sizeof(cd)/sizeof(cd[0]); i++)
1099 if (cd[i].charset == SYMBOL_CHARSET)
1101 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1103 skip("Symbol or Wingdings is not installed\n");
1104 break;
1107 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxA, 128, FALSE);
1108 get_glyph_indices(cd[i].charset, cd[i].code_page, cd[i].font_idxW, 128, TRUE);
1109 ok(!memcmp(cd[i].font_idxA, cd[i].font_idxW, 128*sizeof(WORD)), "%d: indices don't match\n", i);
1112 ok(memcmp(cd[0].font_idxW, cd[1].font_idxW, 128*sizeof(WORD)), "0 vs 1: indices shouldn't match\n");
1113 if (i > 2)
1115 ok(memcmp(cd[0].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "0 vs 2: indices shouldn't match\n");
1116 ok(memcmp(cd[1].font_idxW, cd[2].font_idxW, 128*sizeof(WORD)), "1 vs 2: indices shouldn't match\n");
1118 else
1119 skip("Symbol or Wingdings is not installed\n");
1122 static void test_GetFontUnicodeRanges(void)
1124 LOGFONTA lf;
1125 HDC hdc;
1126 HFONT hfont, hfont_old;
1127 DWORD size;
1128 GLYPHSET *gs;
1130 if (!pGetFontUnicodeRanges)
1132 skip("GetFontUnicodeRanges not available before W2K\n");
1133 return;
1136 memset(&lf, 0, sizeof(lf));
1137 lstrcpyA(lf.lfFaceName, "Arial");
1138 hfont = create_font("Arial", &lf);
1140 hdc = GetDC(0);
1141 hfont_old = SelectObject(hdc, hfont);
1143 size = pGetFontUnicodeRanges(NULL, NULL);
1144 ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n");
1146 size = pGetFontUnicodeRanges(hdc, NULL);
1147 ok(size, "GetFontUnicodeRanges failed unexpectedly\n");
1149 gs = HeapAlloc(GetProcessHeap(), 0, size);
1151 size = pGetFontUnicodeRanges(hdc, gs);
1152 ok(size, "GetFontUnicodeRanges failed\n");
1153 #if 0
1154 for (i = 0; i < gs->cRanges; i++)
1155 trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs);
1156 #endif
1157 trace("found %u ranges\n", gs->cRanges);
1159 HeapFree(GetProcessHeap(), 0, gs);
1161 SelectObject(hdc, hfont_old);
1162 DeleteObject(hfont);
1163 ReleaseDC(NULL, hdc);
1166 #define MAX_ENUM_FONTS 256
1168 struct enum_font_data
1170 int total;
1171 LOGFONT lf[MAX_ENUM_FONTS];
1174 static INT CALLBACK arial_enum_proc(const LOGFONT *lf, const TEXTMETRIC *tm, DWORD type, LPARAM lParam)
1176 struct enum_font_data *efd = (struct enum_font_data *)lParam;
1178 if (type != TRUETYPE_FONTTYPE) return 1;
1179 #if 0
1180 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1181 lf->lfFaceName, lf->lfCharSet, lf->lfWeight, lf->lfItalic);
1182 #endif
1183 if (efd->total < MAX_ENUM_FONTS)
1184 efd->lf[efd->total++] = *lf;
1186 return 1;
1189 static void get_charset_stats(struct enum_font_data *efd,
1190 int *ansi_charset, int *symbol_charset,
1191 int *russian_charset)
1193 int i;
1195 *ansi_charset = 0;
1196 *symbol_charset = 0;
1197 *russian_charset = 0;
1199 for (i = 0; i < efd->total; i++)
1201 switch (efd->lf[i].lfCharSet)
1203 case ANSI_CHARSET:
1204 (*ansi_charset)++;
1205 break;
1206 case SYMBOL_CHARSET:
1207 (*symbol_charset)++;
1208 break;
1209 case RUSSIAN_CHARSET:
1210 (*russian_charset)++;
1211 break;
1216 static void test_EnumFontFamilies(const char *font_name, INT font_charset)
1218 struct enum_font_data efd;
1219 LOGFONT lf;
1220 HDC hdc;
1221 int i, ret, ansi_charset, symbol_charset, russian_charset;
1223 trace("Testing font %s, charset %d\n", *font_name ? font_name : "<empty>", font_charset);
1225 if (*font_name && !is_truetype_font_installed(font_name))
1227 skip("%s is not installed\n", font_name);
1228 return;
1231 hdc = GetDC(0);
1233 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1234 * while EnumFontFamiliesEx doesn't.
1236 if (!*font_name && font_charset == DEFAULT_CHARSET) /* do it only once */
1238 efd.total = 0;
1239 SetLastError(0xdeadbeef);
1240 ret = EnumFontFamilies(hdc, NULL, arial_enum_proc, (LPARAM)&efd);
1241 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1242 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1243 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1244 ansi_charset, symbol_charset, russian_charset);
1245 ok(efd.total > 0, "no fonts enumerated: NULL\n");
1246 ok(ansi_charset > 0, "NULL family should enumerate ANSI_CHARSET\n");
1247 ok(symbol_charset > 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1248 ok(russian_charset > 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1251 efd.total = 0;
1252 SetLastError(0xdeadbeef);
1253 ret = EnumFontFamilies(hdc, font_name, arial_enum_proc, (LPARAM)&efd);
1254 ok(ret, "EnumFontFamilies error %u\n", GetLastError());
1255 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1256 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1257 ansi_charset, symbol_charset, russian_charset,
1258 *font_name ? font_name : "<empty>");
1259 if (*font_name)
1260 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1261 else
1262 ok(!efd.total, "no fonts should be enumerated for empty font_name\n");
1263 for (i = 0; i < efd.total; i++)
1265 /* FIXME: remove completely once Wine is fixed */
1266 if (efd.lf[i].lfCharSet != font_charset)
1268 todo_wine
1269 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1271 else
1272 ok(efd.lf[i].lfCharSet == font_charset, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1273 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1274 font_name, efd.lf[i].lfFaceName);
1277 memset(&lf, 0, sizeof(lf));
1278 lf.lfCharSet = ANSI_CHARSET;
1279 lstrcpy(lf.lfFaceName, font_name);
1280 efd.total = 0;
1281 SetLastError(0xdeadbeef);
1282 ret = EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1283 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1284 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1285 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1286 ansi_charset, symbol_charset, russian_charset,
1287 *font_name ? font_name : "<empty>");
1288 if (font_charset == SYMBOL_CHARSET)
1290 if (*font_name)
1291 ok(efd.total == 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name);
1292 else
1293 ok(efd.total > 0, "no fonts enumerated: %s\n", font_name);
1295 else
1297 ok(efd.total > 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name);
1298 for (i = 0; i < efd.total; i++)
1300 ok(efd.lf[i].lfCharSet == ANSI_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1301 if (*font_name)
1302 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1303 font_name, efd.lf[i].lfFaceName);
1307 /* DEFAULT_CHARSET should enumerate all available charsets */
1308 memset(&lf, 0, sizeof(lf));
1309 lf.lfCharSet = DEFAULT_CHARSET;
1310 lstrcpy(lf.lfFaceName, font_name);
1311 efd.total = 0;
1312 SetLastError(0xdeadbeef);
1313 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1314 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1315 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1316 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1317 ansi_charset, symbol_charset, russian_charset,
1318 *font_name ? font_name : "<empty>");
1319 ok(efd.total > 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name);
1320 for (i = 0; i < efd.total; i++)
1322 if (*font_name)
1323 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1324 font_name, efd.lf[i].lfFaceName);
1326 if (*font_name)
1328 switch (font_charset)
1330 case ANSI_CHARSET:
1331 ok(ansi_charset > 0,
1332 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1333 ok(!symbol_charset,
1334 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name);
1335 ok(russian_charset > 0,
1336 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1337 break;
1338 case SYMBOL_CHARSET:
1339 ok(!ansi_charset,
1340 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name);
1341 ok(symbol_charset,
1342 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1343 ok(!russian_charset,
1344 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name);
1345 break;
1346 case DEFAULT_CHARSET:
1347 ok(ansi_charset > 0,
1348 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name);
1349 ok(symbol_charset > 0,
1350 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name);
1351 ok(russian_charset > 0,
1352 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name);
1353 break;
1356 else
1358 ok(ansi_charset > 0,
1359 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1360 ok(symbol_charset > 0,
1361 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1362 ok(russian_charset > 0,
1363 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1366 memset(&lf, 0, sizeof(lf));
1367 lf.lfCharSet = SYMBOL_CHARSET;
1368 lstrcpy(lf.lfFaceName, font_name);
1369 efd.total = 0;
1370 SetLastError(0xdeadbeef);
1371 EnumFontFamiliesEx(hdc, &lf, arial_enum_proc, (LPARAM)&efd, 0);
1372 ok(ret, "EnumFontFamiliesEx error %u\n", GetLastError());
1373 get_charset_stats(&efd, &ansi_charset, &symbol_charset, &russian_charset);
1374 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1375 ansi_charset, symbol_charset, russian_charset,
1376 *font_name ? font_name : "<empty>");
1377 if (*font_name && font_charset == ANSI_CHARSET)
1378 ok(efd.total == 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name);
1379 else
1381 ok(efd.total > 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name);
1382 for (i = 0; i < efd.total; i++)
1384 ok(efd.lf[i].lfCharSet == SYMBOL_CHARSET, "%d: got charset %d\n", i, efd.lf[i].lfCharSet);
1385 if (*font_name)
1386 ok(!lstrcmp(efd.lf[i].lfFaceName, font_name), "expected %s, got %s\n",
1387 font_name, efd.lf[i].lfFaceName);
1390 ok(!ansi_charset,
1391 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1392 ok(symbol_charset > 0,
1393 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1394 ok(!russian_charset,
1395 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name ? font_name : "<empty>");
1398 ReleaseDC(0, hdc);
1401 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1402 #include "pshpack2.h"
1403 typedef struct
1405 USHORT version;
1406 SHORT xAvgCharWidth;
1407 USHORT usWeightClass;
1408 USHORT usWidthClass;
1409 SHORT fsType;
1410 SHORT ySubscriptXSize;
1411 SHORT ySubscriptYSize;
1412 SHORT ySubscriptXOffset;
1413 SHORT ySubscriptYOffset;
1414 SHORT ySuperscriptXSize;
1415 SHORT ySuperscriptYSize;
1416 SHORT ySuperscriptXOffset;
1417 SHORT ySuperscriptYOffset;
1418 SHORT yStrikeoutSize;
1419 SHORT yStrikeoutPosition;
1420 SHORT sFamilyClass;
1421 PANOSE panose;
1422 ULONG ulUnicodeRange1;
1423 ULONG ulUnicodeRange2;
1424 ULONG ulUnicodeRange3;
1425 ULONG ulUnicodeRange4;
1426 CHAR achVendID[4];
1427 USHORT fsSelection;
1428 USHORT usFirstCharIndex;
1429 USHORT usLastCharIndex;
1430 /* According to the Apple spec, original version didn't have the below fields,
1431 * version numbers were taked from the OpenType spec.
1433 /* version 0 (TrueType 1.5) */
1434 USHORT sTypoAscender;
1435 USHORT sTypoDescender;
1436 USHORT sTypoLineGap;
1437 USHORT usWinAscent;
1438 USHORT usWinDescent;
1439 /* version 1 (TrueType 1.66) */
1440 ULONG ulCodePageRange1;
1441 ULONG ulCodePageRange2;
1442 /* version 2 (OpenType 1.2) */
1443 SHORT sxHeight;
1444 SHORT sCapHeight;
1445 USHORT usDefaultChar;
1446 USHORT usBreakChar;
1447 USHORT usMaxContext;
1448 } TT_OS2_V2;
1449 #include "poppack.h"
1451 #ifdef WORDS_BIGENDIAN
1452 #define GET_BE_WORD(x) (x)
1453 #else
1454 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1455 #endif
1457 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1458 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1459 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1460 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1462 static void test_text_metrics(const LOGFONTA *lf)
1464 HDC hdc;
1465 HFONT hfont, hfont_old;
1466 TEXTMETRICA tmA;
1467 TEXTMETRICW tmW;
1468 UINT first_unicode_char, last_unicode_char, default_char, break_char;
1469 INT test_char;
1470 TT_OS2_V2 tt_os2;
1471 USHORT version;
1472 LONG size, ret;
1473 const char *font_name = lf->lfFaceName;
1475 trace("Testing font metrics for %s, charset %d\n", font_name, lf->lfCharSet);
1477 hdc = GetDC(0);
1479 SetLastError(0xdeadbeef);
1480 hfont = CreateFontIndirectA(lf);
1481 ok(hfont != 0, "CreateFontIndirect error %u\n", GetLastError());
1483 hfont_old = SelectObject(hdc, hfont);
1485 if(lf->lfWidth > 0) {
1486 HFONT hfont2, hfont_prev;
1487 GLYPHMETRICS gm1, gm2;
1488 LOGFONTA lf2 = *lf;
1489 MAT2 mat2 = { {0,1}, {0,0}, {0,0}, {0,1} };
1491 /* negative widths are handled just as positive ones */
1492 lf2.lfWidth *= -1;
1494 SetLastError(0xdeadbeef);
1495 hfont2 = CreateFontIndirectA(&lf2);
1496 ok(hfont2 != 0, "CreateFontIndirect error %u\n", GetLastError());
1497 hfont_prev = SelectObject(hdc, hfont2);
1499 memset(&gm1, 0xaa, sizeof(gm1));
1500 SetLastError(0xdeadbeef);
1501 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm1, 0, NULL, &mat2);
1502 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1504 SelectObject(hdc, hfont_prev);
1505 DeleteObject(hfont2);
1507 memset(&gm2, 0xbb, sizeof(gm2));
1508 SetLastError(0xdeadbeef);
1509 ret = GetGlyphOutlineA(hdc, 'x', GGO_METRICS, &gm2, 0, NULL, &mat2);
1510 ok(ret != GDI_ERROR, "GetGlyphOutline error 0x%x\n", GetLastError());
1512 ok(gm1.gmBlackBoxX == gm2.gmBlackBoxX &&
1513 gm1.gmBlackBoxY == gm2.gmBlackBoxY &&
1514 gm1.gmptGlyphOrigin.x == gm2.gmptGlyphOrigin.x &&
1515 gm1.gmptGlyphOrigin.y == gm2.gmptGlyphOrigin.y &&
1516 gm1.gmCellIncX == gm2.gmCellIncX &&
1517 gm1.gmCellIncY == gm2.gmCellIncY,
1518 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1519 gm1.gmBlackBoxX, gm1.gmBlackBoxY, gm1.gmptGlyphOrigin.x,
1520 gm1.gmptGlyphOrigin.y, gm1.gmCellIncX, gm1.gmCellIncY,
1521 gm2.gmBlackBoxX, gm2.gmBlackBoxY, gm2.gmptGlyphOrigin.x,
1522 gm2.gmptGlyphOrigin.y, gm2.gmCellIncX, gm2.gmCellIncY);
1525 size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0);
1526 if (size == GDI_ERROR)
1528 trace("OS/2 chunk was not found\n");
1529 goto end_of_test;
1531 if (size > sizeof(tt_os2))
1533 trace("got too large OS/2 chunk of size %u\n", size);
1534 size = sizeof(tt_os2);
1537 memset(&tt_os2, 0, sizeof(tt_os2));
1538 ret = GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size);
1539 ok(ret == size, "GetFontData should return %u not %u\n", size, ret);
1541 version = GET_BE_WORD(tt_os2.version);
1542 trace("OS/2 chunk version %u, vendor %4.4s\n", version, (LPCSTR)&tt_os2.achVendID);
1544 first_unicode_char = GET_BE_WORD(tt_os2.usFirstCharIndex);
1545 last_unicode_char = GET_BE_WORD(tt_os2.usLastCharIndex);
1546 default_char = GET_BE_WORD(tt_os2.usDefaultChar);
1547 break_char = GET_BE_WORD(tt_os2.usBreakChar);
1549 trace("for %s first %x, last %x, default %x, break %x\n", font_name,
1550 first_unicode_char, last_unicode_char, default_char, break_char);
1552 SetLastError(0xdeadbeef);
1553 ret = GetTextMetricsA(hdc, &tmA);
1554 ok(ret, "GetTextMetricsA error %u\n", GetLastError());
1555 trace("A: first %x, last %x, default %x, break %x\n",
1556 tmA.tmFirstChar, tmA.tmLastChar, tmA.tmDefaultChar, tmA.tmBreakChar);
1558 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1559 test_char = min(first_unicode_char - 1, 255);
1560 ok(tmA.tmFirstChar == test_char, "A: tmFirstChar for %s %02x != %02x\n",
1561 font_name, tmA.tmFirstChar, test_char);
1562 #endif
1563 if (lf->lfCharSet == SYMBOL_CHARSET)
1565 test_char = min(last_unicode_char - 0xf000, 255);
1566 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1567 font_name, tmA.tmLastChar, test_char);
1569 else
1571 test_char = min(last_unicode_char, 255);
1572 ok(tmA.tmLastChar == test_char, "A: tmLastChar for %s %02x != %02x\n",
1573 font_name, tmA.tmLastChar, test_char);
1576 SetLastError(0xdeadbeef);
1577 ret = GetTextMetricsW(hdc, &tmW);
1578 ok(ret || GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
1579 "GetTextMetricsW error %u\n", GetLastError());
1580 if (ret)
1582 trace("W: first %x, last %x, default %x, break %x\n",
1583 tmW.tmFirstChar, tmW.tmLastChar, tmW.tmDefaultChar,
1584 tmW.tmBreakChar);
1586 if (lf->lfCharSet == SYMBOL_CHARSET)
1588 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1589 * sets symbol range to 0 - f0ff
1591 ok(tmW.tmFirstChar == 0, "W: tmFirstChar for %s %02x != 0\n",
1592 font_name, tmW.tmFirstChar);
1593 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1594 ok(tmW.tmLastChar >= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1595 font_name, tmW.tmLastChar);
1597 ok(tmW.tmDefaultChar == 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1598 font_name, tmW.tmDefaultChar);
1599 ok(tmW.tmBreakChar == 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1600 font_name, tmW.tmBreakChar);
1602 else
1604 ok(tmW.tmFirstChar == first_unicode_char, "W: tmFirstChar for %s %02x != %02x\n",
1605 font_name, tmW.tmFirstChar, first_unicode_char);
1606 ok(tmW.tmLastChar == last_unicode_char, "W: tmLastChar for %s %02x != %02x\n",
1607 font_name, tmW.tmLastChar, last_unicode_char);
1609 ret = GetDeviceCaps(hdc, LOGPIXELSX);
1610 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectX %u != %u\n",
1611 tmW.tmDigitizedAspectX, ret);
1612 ret = GetDeviceCaps(hdc, LOGPIXELSY);
1613 ok(tmW.tmDigitizedAspectX == ret, "W: tmDigitizedAspectY %u != %u\n",
1614 tmW.tmDigitizedAspectX, ret);
1617 end_of_test:
1618 SelectObject(hdc, hfont_old);
1619 DeleteObject(hfont);
1621 ReleaseDC(0, hdc);
1624 static INT CALLBACK enum_truetype_font_proc(const LOGFONT *lf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
1626 INT *enumed = (INT *)lParam;
1628 if (type == TRUETYPE_FONTTYPE)
1630 (*enumed)++;
1631 test_text_metrics(lf);
1633 return 1;
1636 static void test_GetTextMetrics(void)
1638 LOGFONTA lf;
1639 HDC hdc;
1640 INT enumed;
1642 hdc = GetDC(0);
1644 memset(&lf, 0, sizeof(lf));
1645 lf.lfCharSet = DEFAULT_CHARSET;
1646 enumed = 0;
1647 EnumFontFamiliesExA(hdc, &lf, enum_truetype_font_proc, (LPARAM)&enumed, 0);
1648 trace("Tested metrics of %d truetype fonts\n", enumed);
1650 ReleaseDC(0, hdc);
1653 static void test_nonexistent_font(void)
1655 LOGFONTA lf;
1656 HDC hdc;
1657 HFONT hfont;
1658 char buf[LF_FACESIZE];
1660 if (!is_truetype_font_installed("Arial Black"))
1662 skip("Arial not installed\n");
1663 return;
1666 hdc = GetDC(0);
1668 memset(&lf, 0, sizeof(lf));
1669 lf.lfHeight = 100;
1670 lf.lfWeight = FW_REGULAR;
1671 lf.lfCharSet = ANSI_CHARSET;
1672 lf.lfPitchAndFamily = FF_SWISS;
1673 strcpy(lf.lfFaceName, "Nonexistent font");
1675 hfont = CreateFontIndirectA(&lf);
1676 hfont = SelectObject(hdc, hfont);
1677 GetTextFaceA(hdc, sizeof(buf), buf);
1678 ok(!lstrcmpiA(buf, "Arial"), "Got %s\n", buf);
1679 DeleteObject(SelectObject(hdc, hfont));
1680 ReleaseDC(0, hdc);
1683 START_TEST(font)
1685 init();
1687 test_logfont();
1688 test_bitmap_font();
1689 test_bitmap_font_metrics();
1690 test_GdiGetCharDimensions();
1691 test_GetCharABCWidthsW();
1692 test_text_extents();
1693 test_GetGlyphIndices();
1694 test_GetKerningPairs();
1695 test_GetOutlineTextMetrics();
1696 test_SetTextJustification();
1697 test_font_charset();
1698 test_GetFontUnicodeRanges();
1699 test_nonexistent_font();
1701 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1702 * I'd like to avoid them in this test.
1704 test_EnumFontFamilies("Arial Black", ANSI_CHARSET);
1705 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET);
1706 if (is_truetype_font_installed("Arial Black") &&
1707 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1709 test_EnumFontFamilies("", ANSI_CHARSET);
1710 test_EnumFontFamilies("", SYMBOL_CHARSET);
1711 test_EnumFontFamilies("", DEFAULT_CHARSET);
1713 else
1714 skip("Arial Black or Symbol/Wingdings is not installed\n");
1715 test_GetTextMetrics();