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
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;
61 static BOOL
is_truetype_font_installed(const char *name
)
66 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
73 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
78 static BOOL
is_font_installed(const char *name
)
83 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
90 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
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)
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
);
114 check_font(test
, lf
, hfont
);
118 static void test_logfont(void)
123 memset(&lf
, 0, sizeof lf
);
125 lf
.lfCharSet
= ANSI_CHARSET
;
126 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
127 lf
.lfWeight
= FW_DONTCARE
;
130 lf
.lfQuality
= DEFAULT_QUALITY
;
132 lstrcpyA(lf
.lfFaceName
, "Arial");
133 hfont
= create_font("Arial", &lf
);
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
);
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
;
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
)
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";
197 HFONT hfont
, old_hfont
;
200 INT ret
, i
, width_orig
, height_orig
;
204 /* "System" has only 1 pixel size defined, otherwise the test breaks */
205 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
209 trace("no bitmap fonts were found, skipping the test\n");
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
);
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);
233 /* test integer scaling 3x2 */
234 bitmap_lf
.lfHeight
= height_orig
* 2;
235 bitmap_lf
.lfWidth
*= 3;
236 hfont
= create_font("3x2", &bitmap_lf
);
239 test_font_metrics(hdc
, hfont
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
243 /* test integer scaling 3x3 */
244 bitmap_lf
.lfHeight
= height_orig
* 3;
245 bitmap_lf
.lfWidth
= 0;
246 hfont
= create_font("3x3", &bitmap_lf
);
250 test_font_metrics(hdc
, hfont
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
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
))
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
;
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
},
328 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
329 * require a new system.sfd for that font
331 { "System", FW_BOLD
, 18, 16, 2, 0, 2, 8, 16, CP932_BIT
},
332 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT
},
333 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT
| CP1251_BIT
},
334 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, CP932_BIT
},
335 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT
},
336 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT
| CP1251_BIT
},
337 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, CP932_BIT
},
338 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT
},
339 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT
| CP1251_BIT
},
340 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, CP932_BIT
},
341 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT
},
342 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT
| CP1251_BIT
},
343 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, CP932_BIT
},
344 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT
| CP1250_BIT
},
345 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT
},
346 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, CP932_BIT
},
347 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT
| CP1250_BIT
| CP1251_BIT
},
348 /* No proper small font for Japanese yet */
349 /* { "Small Fonts", FW_NORMAL, 11, 9, 2, 0, 0, 7, 14, CP932_BIT }, */
350 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT
| CP1250_BIT
},
351 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT
},
352 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, CP932_BIT
}
354 /* FIXME: add "Terminal" */
358 HFONT hfont
, old_hfont
;
362 hdc
= CreateCompatibleDC(0);
365 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
369 memset(&lf
, 0, sizeof(lf
));
371 lf
.lfHeight
= fd
[i
].height
;
372 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
374 for(bit
= 0; bit
< 32; bit
++)
381 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
382 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
384 lf
.lfCharSet
= csi
.ciCharset
;
385 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
388 trace("found font %s, height %d charset %x\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
390 hfont
= create_font(lf
.lfFaceName
, &lf
);
391 old_hfont
= SelectObject(hdc
, hfont
);
392 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %d\n", GetLastError());
394 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
);
395 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
);
396 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
);
397 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
);
398 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
);
399 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
);
400 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
);
402 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
403 that make the max width bigger */
404 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
405 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
);
407 SelectObject(hdc
, old_hfont
);
415 static void test_GdiGetCharDimensions(void)
421 LONG avgwidth
, height
;
422 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
424 if (!pGdiGetCharDimensions
)
426 skip("GdiGetCharDimensions not available on this platform\n");
430 hdc
= CreateCompatibleDC(NULL
);
432 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
433 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
435 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
436 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
437 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
439 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
440 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
442 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
443 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
446 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
447 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
448 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
453 static void test_GetCharABCWidthsW(void)
457 if (!pGetCharABCWidthsW
) return;
459 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
460 ok(!ret
, "GetCharABCWidthsW should have returned FALSE\n");
463 static void test_text_extents(void)
465 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
467 INT i
, len
, fit1
, fit2
;
475 memset(&lf
, 0, sizeof(lf
));
476 strcpy(lf
.lfFaceName
, "Arial");
479 hfont
= CreateFontIndirectA(&lf
);
481 hfont
= SelectObject(hdc
, hfont
);
482 GetTextMetricsA(hdc
, &tm
);
483 GetTextExtentPointA(hdc
, "o", 1, &sz
);
484 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
486 SetLastError(0xdeadbeef);
487 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
488 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
490 skip("Skipping remainder of text extents test on a Win9x platform\n");
491 hfont
= SelectObject(hdc
, hfont
);
498 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
499 extents
[0] = 1; /* So that the increasing sequence test will fail
500 if the extents array is untouched. */
501 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
502 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
504 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
505 /* Because of the '\n' in the string GetTextExtentExPoint and
506 GetTextExtentPoint return different widths under Win2k, but
507 under WinXP they return the same width. So we don't test that
510 for (i
= 1; i
< len
; ++i
)
511 ok(extents
[i
-1] <= extents
[i
],
512 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
514 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
515 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
516 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
517 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
518 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
519 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
520 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
521 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
522 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
523 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
524 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
525 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
526 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
527 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
528 HeapFree(GetProcessHeap(), 0, extents
);
530 hfont
= SelectObject(hdc
, hfont
);
532 ReleaseDC(NULL
, hdc
);
535 static void test_GetGlyphIndices(void)
542 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
543 WORD glyphs
[(sizeof(testtext
)/2)-1];
546 if (!pGetGlyphIndicesW
) {
547 skip("GetGlyphIndices not available on platform\n");
551 if(!is_font_installed("Symbol"))
553 skip("Symbol is not installed so skipping this test\n");
557 memset(&lf
, 0, sizeof(lf
));
558 strcpy(lf
.lfFaceName
, "Symbol");
561 hfont
= CreateFontIndirectA(&lf
);
564 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
565 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
566 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
567 ok(charcount
== 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount
);
568 ok(glyphs
[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs
[4]);
570 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
571 ok(charcount
== 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount
);
572 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndices should have returned a %04x not %04x\n",
573 textm
.tmDefaultChar
, glyphs
[4]);
576 static void test_GetKerningPairs(void)
578 static const struct kerning_data
580 const char face_name
[LF_FACESIZE
];
582 /* some interesting fields from OUTLINETEXTMETRIC */
583 LONG tmHeight
, tmAscent
, tmDescent
;
588 UINT otmsCapEmHeight
;
593 UINT otmusMinimumPPEM
;
594 /* small subset of kerning pairs to test */
595 DWORD total_kern_pairs
;
596 const KERNINGPAIR kern_pair
[26];
599 {"Arial", 12, 12, 9, 3,
600 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
603 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
604 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
605 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
606 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
607 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
608 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
609 {933,970,+1},{933,972,-1}
612 {"Arial", -34, 39, 32, 7,
613 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
616 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
617 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
618 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
619 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
620 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
621 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
622 {933,970,+2},{933,972,-3}
625 { "Arial", 120, 120, 97, 23,
626 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
629 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
630 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
631 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
632 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
633 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
634 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
635 {933,970,+6},{933,972,-10}
638 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
639 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
640 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
643 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
644 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
645 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
646 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
647 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
648 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
649 {933,970,+54},{933,972,-83}
655 HFONT hfont
, hfont_old
;
656 KERNINGPAIR
*kern_pair
;
658 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
662 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
663 * which may render this test unusable, so we're trying to avoid that.
665 SetLastError(0xdeadbeef);
666 GetKerningPairsW(hdc
, 0, NULL
);
667 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
669 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
674 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
676 OUTLINETEXTMETRICW otm
;
678 if (!is_font_installed(kd
[i
].face_name
))
680 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
684 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
686 memset(&lf
, 0, sizeof(lf
));
687 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
688 lf
.lfHeight
= kd
[i
].height
;
689 hfont
= CreateFontIndirect(&lf
);
692 hfont_old
= SelectObject(hdc
, hfont
);
694 SetLastError(0xdeadbeef);
695 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
696 ok(GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
) == sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
698 ok(kd
[i
].tmHeight
== otm
.otmTextMetrics
.tmHeight
, "expected %d, got %d\n",
699 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
700 ok(kd
[i
].tmAscent
== otm
.otmTextMetrics
.tmAscent
, "expected %d, got %d\n",
701 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
702 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
703 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
705 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
706 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
707 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
708 kd
[i
].otmAscent
, otm
.otmAscent
);
709 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
710 kd
[i
].otmDescent
, otm
.otmDescent
);
711 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
712 kd
[i
].otmLineGap
, otm
.otmLineGap
);
714 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
715 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
716 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
717 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
718 ok(kd
[i
].otmMacAscent
== otm
.otmMacAscent
, "expected %d, got %d\n",
719 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
720 ok(kd
[i
].otmMacDescent
== otm
.otmMacDescent
, "expected %d, got %d\n",
721 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
722 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
723 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
724 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
725 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
726 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
729 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
730 trace("total_kern_pairs %u\n", total_kern_pairs
);
731 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
733 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
734 SetLastError(0xdeadbeef);
735 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
736 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
737 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
738 ok(ret
== 0, "got %lu, expected 0\n", ret
);
741 ret
= GetKerningPairsW(hdc
, 100, NULL
);
742 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
744 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
745 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
747 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
748 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
752 for (n
= 0; n
< ret
; n
++)
756 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
757 trace("{'%c','%c',%d},\n",
758 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
760 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
762 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
763 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
765 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
766 "pair %d:%d got %d, expected %d\n",
767 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
768 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
774 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
775 matches
, kd
[i
].total_kern_pairs
);
777 HeapFree(GetProcessHeap(), 0, kern_pair
);
779 SelectObject(hdc
, hfont_old
);
786 static void test_GetOutlineTextMetrics(void)
788 OUTLINETEXTMETRIC
*otm
;
790 HFONT hfont
, hfont_old
;
794 if (!is_font_installed("Arial"))
796 skip("Arial is not installed\n");
802 memset(&lf
, 0, sizeof(lf
));
803 strcpy(lf
.lfFaceName
, "Arial");
805 lf
.lfWeight
= FW_NORMAL
;
806 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
807 lf
.lfQuality
= PROOF_QUALITY
;
808 hfont
= CreateFontIndirect(&lf
);
811 hfont_old
= SelectObject(hdc
, hfont
);
812 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
813 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
815 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
817 memset(otm
, 0xAA, otm_size
);
818 SetLastError(0xdeadbeef);
819 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
820 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
821 ok(ret
== 1 /* Win9x */ ||
822 ret
== otm
->otmSize
/* XP*/,
823 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
824 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
826 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
827 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
828 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
829 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
832 memset(otm
, 0xAA, otm_size
);
833 SetLastError(0xdeadbeef);
834 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
835 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
836 ok(ret
== 1 /* Win9x */ ||
837 ret
== otm
->otmSize
/* XP*/,
838 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
839 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
841 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
842 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
843 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
844 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
847 /* ask about truncated data */
848 memset(otm
, 0xAA, otm_size
);
849 SetLastError(0xdeadbeef);
850 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
851 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
852 ok(ret
== 1 /* Win9x */ ||
853 ret
== otm
->otmSize
/* XP*/,
854 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
855 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
857 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
858 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
859 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
861 ok(otm
->otmpFullName
== (LPSTR
)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm
->otmpFullName
);
863 HeapFree(GetProcessHeap(), 0, otm
);
865 SelectObject(hdc
, hfont_old
);
871 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
875 outputWidth
= 0, /* to test TabbedTextOut() */
876 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
877 areaWidth
= clientArea
->right
- clientArea
->left
,
879 BOOL lastExtent
= FALSE
;
880 PSTR pFirstChar
, pLastChar
;
886 int GetTextExtentExPointWWidth
;
887 int TabbedTextOutWidth
;
890 GetTextMetricsA(hdc
, &tm
);
894 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
900 /* if not at the end of the string, ... */
901 if (*str
== '\0') break;
902 /* ... add the next word to the current extent */
903 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
905 SetTextJustification(hdc
, 0, 0);
906 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
907 } while ((int) size
.cx
< areaWidth
);
909 /* ignore trailing break chars */
911 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
917 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
919 SetTextJustification(hdc
, 0, 0);
920 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
922 /* do not justify the last extent */
923 if (*str
!= '\0' && breakCount
> 0)
925 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
926 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
927 justifiedWidth
= size
.cx
;
929 else lastExtent
= TRUE
;
931 x
= clientArea
->left
;
933 outputWidth
= LOWORD(TabbedTextOut(
934 hdc
, x
, y
, pFirstChar
, pLastChar
- pFirstChar
,
936 /* catch errors and report them */
937 if (!lastExtent
&& ((outputWidth
!= areaWidth
) || (justifiedWidth
!= areaWidth
)))
939 memset(error
[nErrors
].extent
, 0, 100);
940 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
941 error
[nErrors
].TabbedTextOutWidth
= outputWidth
;
942 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
948 } while (*str
&& y
< clientArea
->bottom
);
950 for (e
= 0; e
< nErrors
; e
++)
952 ok(error
[e
].TabbedTextOutWidth
== areaWidth
,
953 "The output text (\"%s\") width should be %d, not %d.\n",
954 error
[e
].extent
, areaWidth
, error
[e
].TabbedTextOutWidth
);
955 /* The width returned by GetTextExtentPoint32() is exactly the same
956 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
957 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
958 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
959 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
963 static void test_SetTextJustification(void)
970 static char testText
[] =
971 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
972 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
973 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
974 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
975 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
976 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
977 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
979 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
980 GetClientRect( hwnd
, &clientArea
);
983 memset(&lf
, 0, sizeof lf
);
984 lf
.lfCharSet
= ANSI_CHARSET
;
985 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
986 lf
.lfWeight
= FW_DONTCARE
;
988 lf
.lfQuality
= DEFAULT_QUALITY
;
989 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
990 hfont
= create_font("Times New Roman", &lf
);
991 SelectObject(hdc
, hfont
);
993 testJustification(hdc
, testText
, &clientArea
);
996 ReleaseDC(hwnd
, hdc
);
1000 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1004 HFONT hfont
, hfont_old
;
1011 assert(count
<= 128);
1013 memset(&lf
, 0, sizeof(lf
));
1015 lf
.lfCharSet
= charset
;
1017 lstrcpyA(lf
.lfFaceName
, "Arial");
1018 SetLastError(0xdeadbeef);
1019 hfont
= CreateFontIndirectA(&lf
);
1020 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1023 hfont_old
= SelectObject(hdc
, hfont
);
1025 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1026 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1028 SetLastError(0xdeadbeef);
1029 ret
= GetTextFace(hdc
, sizeof(name
), name
);
1030 ok(ret
, "GetTextFace error %u\n", GetLastError());
1032 if (charset
== SYMBOL_CHARSET
)
1034 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1035 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1039 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1040 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1043 if (!TranslateCharsetInfo((DWORD
*)cs
, &csi
, TCI_SRCCHARSET
))
1045 trace("Can't find codepage for charset %d\n", cs
);
1049 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1054 WCHAR unicode_buf
[128];
1056 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1058 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1060 SetLastError(0xdeadbeef);
1061 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1062 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1068 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1070 SetLastError(0xdeadbeef);
1071 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1072 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1075 SelectObject(hdc
, hfont_old
);
1076 DeleteObject(hfont
);
1083 static void test_font_charset(void)
1085 static struct charset_data
1089 WORD font_idxA
[128], font_idxW
[128];
1092 { ANSI_CHARSET
, 1252 },
1093 { RUSSIAN_CHARSET
, 1251 },
1094 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1098 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1100 skip("Skipping the font charset test on a Win9x platform\n");
1104 if (!is_font_installed("Arial"))
1106 skip("Arial is not installed\n");
1110 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1112 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1114 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1116 skip("Symbol or Wingdings is not installed\n");
1120 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
);
1121 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
);
1122 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1125 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1128 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1129 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1132 skip("Symbol or Wingdings is not installed\n");
1135 static void test_GetFontUnicodeRanges(void)
1139 HFONT hfont
, hfont_old
;
1143 if (!pGetFontUnicodeRanges
)
1145 skip("GetFontUnicodeRanges not available before W2K\n");
1149 memset(&lf
, 0, sizeof(lf
));
1150 lstrcpyA(lf
.lfFaceName
, "Arial");
1151 hfont
= create_font("Arial", &lf
);
1154 hfont_old
= SelectObject(hdc
, hfont
);
1156 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1157 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1159 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1160 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1162 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1164 size
= pGetFontUnicodeRanges(hdc
, gs
);
1165 ok(size
, "GetFontUnicodeRanges failed\n");
1167 for (i
= 0; i
< gs
->cRanges
; i
++)
1168 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1170 trace("found %u ranges\n", gs
->cRanges
);
1172 HeapFree(GetProcessHeap(), 0, gs
);
1174 SelectObject(hdc
, hfont_old
);
1175 DeleteObject(hfont
);
1176 ReleaseDC(NULL
, hdc
);
1179 #define MAX_ENUM_FONTS 256
1181 struct enum_font_data
1184 LOGFONT lf
[MAX_ENUM_FONTS
];
1187 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1189 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1191 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1193 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1194 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfWeight
, lf
->lfItalic
);
1196 if (efd
->total
< MAX_ENUM_FONTS
)
1197 efd
->lf
[efd
->total
++] = *lf
;
1202 static void get_charset_stats(struct enum_font_data
*efd
,
1203 int *ansi_charset
, int *symbol_charset
,
1204 int *russian_charset
)
1209 *symbol_charset
= 0;
1210 *russian_charset
= 0;
1212 for (i
= 0; i
< efd
->total
; i
++)
1214 switch (efd
->lf
[i
].lfCharSet
)
1219 case SYMBOL_CHARSET
:
1220 (*symbol_charset
)++;
1222 case RUSSIAN_CHARSET
:
1223 (*russian_charset
)++;
1229 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1231 struct enum_font_data efd
;
1234 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1236 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1238 if (*font_name
&& !is_truetype_font_installed(font_name
))
1240 skip("%s is not installed\n", font_name
);
1246 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1247 * while EnumFontFamiliesEx doesn't.
1249 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1252 SetLastError(0xdeadbeef);
1253 ret
= EnumFontFamilies(hdc
, NULL
, 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 NULL\n",
1257 ansi_charset
, symbol_charset
, russian_charset
);
1258 ok(efd
.total
> 0, "no fonts enumerated: NULL\n");
1259 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1260 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1261 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1265 SetLastError(0xdeadbeef);
1266 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
1267 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1268 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1269 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1270 ansi_charset
, symbol_charset
, russian_charset
,
1271 *font_name
? font_name
: "<empty>");
1273 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1275 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
1276 for (i
= 0; i
< efd
.total
; i
++)
1278 /* FIXME: remove completely once Wine is fixed */
1279 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
1282 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1285 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1286 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1287 font_name
, efd
.lf
[i
].lfFaceName
);
1290 memset(&lf
, 0, sizeof(lf
));
1291 lf
.lfCharSet
= ANSI_CHARSET
;
1292 lstrcpy(lf
.lfFaceName
, font_name
);
1294 SetLastError(0xdeadbeef);
1295 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1296 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1297 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1298 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1299 ansi_charset
, symbol_charset
, russian_charset
,
1300 *font_name
? font_name
: "<empty>");
1301 if (font_charset
== SYMBOL_CHARSET
)
1304 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
1306 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1310 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
1311 for (i
= 0; i
< efd
.total
; i
++)
1313 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1315 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1316 font_name
, efd
.lf
[i
].lfFaceName
);
1320 /* DEFAULT_CHARSET should enumerate all available charsets */
1321 memset(&lf
, 0, sizeof(lf
));
1322 lf
.lfCharSet
= DEFAULT_CHARSET
;
1323 lstrcpy(lf
.lfFaceName
, font_name
);
1325 SetLastError(0xdeadbeef);
1326 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1327 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1328 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1329 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1330 ansi_charset
, symbol_charset
, russian_charset
,
1331 *font_name
? font_name
: "<empty>");
1332 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
1333 for (i
= 0; i
< efd
.total
; i
++)
1336 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1337 font_name
, efd
.lf
[i
].lfFaceName
);
1341 switch (font_charset
)
1344 ok(ansi_charset
> 0,
1345 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1347 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
1348 ok(russian_charset
> 0,
1349 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1351 case SYMBOL_CHARSET
:
1353 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
1355 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1356 ok(!russian_charset
,
1357 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1359 case DEFAULT_CHARSET
:
1360 ok(ansi_charset
> 0,
1361 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1362 ok(symbol_charset
> 0,
1363 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1364 ok(russian_charset
> 0,
1365 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1371 ok(ansi_charset
> 0,
1372 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1373 ok(symbol_charset
> 0,
1374 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1375 ok(russian_charset
> 0,
1376 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1379 memset(&lf
, 0, sizeof(lf
));
1380 lf
.lfCharSet
= SYMBOL_CHARSET
;
1381 lstrcpy(lf
.lfFaceName
, font_name
);
1383 SetLastError(0xdeadbeef);
1384 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1385 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1386 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1387 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1388 ansi_charset
, symbol_charset
, russian_charset
,
1389 *font_name
? font_name
: "<empty>");
1390 if (*font_name
&& font_charset
== ANSI_CHARSET
)
1391 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
1394 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
1395 for (i
= 0; i
< efd
.total
; i
++)
1397 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1399 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1400 font_name
, efd
.lf
[i
].lfFaceName
);
1404 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1405 ok(symbol_charset
> 0,
1406 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1407 ok(!russian_charset
,
1408 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1414 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1415 #include "pshpack2.h"
1419 SHORT xAvgCharWidth
;
1420 USHORT usWeightClass
;
1421 USHORT usWidthClass
;
1423 SHORT ySubscriptXSize
;
1424 SHORT ySubscriptYSize
;
1425 SHORT ySubscriptXOffset
;
1426 SHORT ySubscriptYOffset
;
1427 SHORT ySuperscriptXSize
;
1428 SHORT ySuperscriptYSize
;
1429 SHORT ySuperscriptXOffset
;
1430 SHORT ySuperscriptYOffset
;
1431 SHORT yStrikeoutSize
;
1432 SHORT yStrikeoutPosition
;
1435 ULONG ulUnicodeRange1
;
1436 ULONG ulUnicodeRange2
;
1437 ULONG ulUnicodeRange3
;
1438 ULONG ulUnicodeRange4
;
1441 USHORT usFirstCharIndex
;
1442 USHORT usLastCharIndex
;
1443 /* According to the Apple spec, original version didn't have the below fields,
1444 * version numbers were taked from the OpenType spec.
1446 /* version 0 (TrueType 1.5) */
1447 USHORT sTypoAscender
;
1448 USHORT sTypoDescender
;
1449 USHORT sTypoLineGap
;
1451 USHORT usWinDescent
;
1452 /* version 1 (TrueType 1.66) */
1453 ULONG ulCodePageRange1
;
1454 ULONG ulCodePageRange2
;
1455 /* version 2 (OpenType 1.2) */
1458 USHORT usDefaultChar
;
1460 USHORT usMaxContext
;
1462 #include "poppack.h"
1464 #ifdef WORDS_BIGENDIAN
1465 #define GET_BE_WORD(x) (x)
1467 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1470 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1471 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1472 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1473 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1475 static void test_text_metrics(const LOGFONTA
*lf
)
1478 HFONT hfont
, hfont_old
;
1481 UINT first_unicode_char
, last_unicode_char
, default_char
, break_char
;
1486 const char *font_name
= lf
->lfFaceName
;
1488 trace("Testing font metrics for %s, charset %d\n", font_name
, lf
->lfCharSet
);
1492 SetLastError(0xdeadbeef);
1493 hfont
= CreateFontIndirectA(lf
);
1494 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1496 hfont_old
= SelectObject(hdc
, hfont
);
1498 if(lf
->lfWidth
> 0) {
1499 HFONT hfont2
, hfont_prev
;
1500 GLYPHMETRICS gm1
, gm2
;
1502 MAT2 mat2
= { {0,1}, {0,0}, {0,0}, {0,1} };
1504 /* negative widths are handled just as positive ones */
1507 SetLastError(0xdeadbeef);
1508 hfont2
= CreateFontIndirectA(&lf2
);
1509 ok(hfont2
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1510 hfont_prev
= SelectObject(hdc
, hfont2
);
1512 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1513 memset(&gm1
, 0xab, sizeof(gm1
));
1514 SetLastError(0xdeadbeef);
1515 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat2
);
1516 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1518 SelectObject(hdc
, hfont_prev
);
1519 DeleteObject(hfont2
);
1521 memset(&gm2
, 0xbb, sizeof(gm2
));
1522 SetLastError(0xdeadbeef);
1523 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat2
);
1524 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1526 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
1527 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
1528 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
1529 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
1530 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
1531 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
1532 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1533 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
1534 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
1535 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
1536 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
1539 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
1540 if (size
== GDI_ERROR
)
1542 trace("OS/2 chunk was not found\n");
1545 if (size
> sizeof(tt_os2
))
1547 trace("got too large OS/2 chunk of size %u\n", size
);
1548 size
= sizeof(tt_os2
);
1551 memset(&tt_os2
, 0, sizeof(tt_os2
));
1552 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
1553 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
1555 version
= GET_BE_WORD(tt_os2
.version
);
1556 trace("OS/2 chunk version %u, vendor %4.4s\n", version
, (LPCSTR
)&tt_os2
.achVendID
);
1558 first_unicode_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
1559 last_unicode_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
1560 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
1561 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
1563 trace("for %s first %x, last %x, default %x, break %x\n", font_name
,
1564 first_unicode_char
, last_unicode_char
, default_char
, break_char
);
1566 SetLastError(0xdeadbeef);
1567 ret
= GetTextMetricsA(hdc
, &tmA
);
1568 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
1569 trace("A: first %x, last %x, default %x, break %x\n",
1570 tmA
.tmFirstChar
, tmA
.tmLastChar
, tmA
.tmDefaultChar
, tmA
.tmBreakChar
);
1572 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1573 test_char
= min(first_unicode_char
- 1, 255);
1574 ok(tmA
.tmFirstChar
== test_char
, "A: tmFirstChar for %s %02x != %02x\n",
1575 font_name
, tmA
.tmFirstChar
, test_char
);
1577 if (lf
->lfCharSet
== SYMBOL_CHARSET
)
1579 test_char
= min(last_unicode_char
- 0xf000, 255);
1580 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
1581 font_name
, tmA
.tmLastChar
, test_char
);
1585 test_char
= min(last_unicode_char
, 255);
1586 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
1587 font_name
, tmA
.tmLastChar
, test_char
);
1590 SetLastError(0xdeadbeef);
1591 ret
= GetTextMetricsW(hdc
, &tmW
);
1592 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
1593 "GetTextMetricsW error %u\n", GetLastError());
1596 trace("W: first %x, last %x, default %x, break %x\n",
1597 tmW
.tmFirstChar
, tmW
.tmLastChar
, tmW
.tmDefaultChar
,
1600 if (lf
->lfCharSet
== SYMBOL_CHARSET
)
1602 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1603 * sets symbol range to 0 - f0ff
1605 ok(tmW
.tmFirstChar
== 0, "W: tmFirstChar for %s %02x != 0\n",
1606 font_name
, tmW
.tmFirstChar
);
1607 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1608 ok(tmW
.tmLastChar
>= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1609 font_name
, tmW
.tmLastChar
);
1611 ok(tmW
.tmDefaultChar
== 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1612 font_name
, tmW
.tmDefaultChar
);
1613 ok(tmW
.tmBreakChar
== 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1614 font_name
, tmW
.tmBreakChar
);
1618 ok(tmW
.tmFirstChar
== first_unicode_char
, "W: tmFirstChar for %s %02x != %02x\n",
1619 font_name
, tmW
.tmFirstChar
, first_unicode_char
);
1620 ok(tmW
.tmLastChar
== last_unicode_char
, "W: tmLastChar for %s %02x != %02x\n",
1621 font_name
, tmW
.tmLastChar
, last_unicode_char
);
1623 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
1624 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
1625 tmW
.tmDigitizedAspectX
, ret
);
1626 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
1627 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
1628 tmW
.tmDigitizedAspectX
, ret
);
1632 SelectObject(hdc
, hfont_old
);
1633 DeleteObject(hfont
);
1638 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
1640 INT
*enumed
= (INT
*)lParam
;
1642 if (type
== TRUETYPE_FONTTYPE
)
1645 test_text_metrics(lf
);
1650 static void test_GetTextMetrics(void)
1658 memset(&lf
, 0, sizeof(lf
));
1659 lf
.lfCharSet
= DEFAULT_CHARSET
;
1661 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
1662 trace("Tested metrics of %d truetype fonts\n", enumed
);
1667 static void test_nonexistent_font(void)
1672 char buf
[LF_FACESIZE
];
1674 if (!is_truetype_font_installed("Arial Black"))
1676 skip("Arial not installed\n");
1682 memset(&lf
, 0, sizeof(lf
));
1684 lf
.lfWeight
= FW_REGULAR
;
1685 lf
.lfCharSet
= ANSI_CHARSET
;
1686 lf
.lfPitchAndFamily
= FF_SWISS
;
1687 strcpy(lf
.lfFaceName
, "Nonexistent font");
1689 hfont
= CreateFontIndirectA(&lf
);
1690 hfont
= SelectObject(hdc
, hfont
);
1691 GetTextFaceA(hdc
, sizeof(buf
), buf
);
1692 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
1693 DeleteObject(SelectObject(hdc
, hfont
));
1703 test_bitmap_font_metrics();
1704 test_GdiGetCharDimensions();
1705 test_GetCharABCWidthsW();
1706 test_text_extents();
1707 test_GetGlyphIndices();
1708 test_GetKerningPairs();
1709 test_GetOutlineTextMetrics();
1710 test_SetTextJustification();
1711 test_font_charset();
1712 test_GetFontUnicodeRanges();
1713 test_nonexistent_font();
1715 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1716 * I'd like to avoid them in this test.
1718 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
1719 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
1720 if (is_truetype_font_installed("Arial Black") &&
1721 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1723 test_EnumFontFamilies("", ANSI_CHARSET
);
1724 test_EnumFontFamilies("", SYMBOL_CHARSET
);
1725 test_EnumFontFamilies("", DEFAULT_CHARSET
);
1728 skip("Arial Black or Symbol/Wingdings is not installed\n");
1729 test_GetTextMetrics();