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
30 #include "wine/test.h"
32 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
40 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
41 /* NT4 tries to be clever and only returns the minimum length */
42 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
44 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
45 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
46 ok(!memcmp(&lf
, &lf
, FIELD_OFFSET(LOGFONTA
, lfFaceName
)), "%s: fonts don't match\n", test
);
47 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
),
48 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
51 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
53 HFONT hfont
= CreateFontIndirectA(lf
);
54 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
56 check_font(test
, lf
, hfont
);
60 static void test_logfont(void)
65 memset(&lf
, 0, sizeof lf
);
67 lf
.lfCharSet
= ANSI_CHARSET
;
68 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
69 lf
.lfWeight
= FW_DONTCARE
;
72 lf
.lfQuality
= DEFAULT_QUALITY
;
74 lstrcpyA(lf
.lfFaceName
, "Arial");
75 hfont
= create_font("Arial", &lf
);
78 memset(&lf
, 'A', sizeof(lf
));
79 hfont
= CreateFontIndirectA(&lf
);
80 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
82 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
83 check_font("AAA...", &lf
, hfont
);
87 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
89 if (type
& RASTER_FONTTYPE
)
91 LOGFONT
*lf
= (LOGFONT
*)lParam
;
93 return 0; /* stop enumeration */
96 return 1; /* continue enumeration */
99 static void test_font_metrics(HDC hdc
, HFONT hfont
, const char *test_str
,
100 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
101 const SIZE
*size_orig
, INT width_orig
,
102 INT scale_x
, INT scale_y
)
112 old_hfont
= SelectObject(hdc
, hfont
);
114 GetTextMetricsA(hdc
, &tm
);
116 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "%ld != %ld\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
117 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "%ld != %ld\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
118 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "%ld != %ld\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
119 ok(tm
.tmAveCharWidth
== tm_orig
->tmAveCharWidth
* scale_x
, "%ld != %ld\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
121 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
123 ok(size
.cx
== size_orig
->cx
* scale_x
, "%ld != %ld\n", size
.cx
, size_orig
->cx
* scale_x
);
124 ok(size
.cy
== size_orig
->cy
* scale_y
, "%ld != %ld\n", size
.cy
, size_orig
->cy
* scale_y
);
126 GetCharWidthA(hdc
, 'A', 'A', &width
);
128 ok(width
== width_orig
* scale_x
, "%d != %d\n", width
, width_orig
* scale_x
);
130 SelectObject(hdc
, old_hfont
);
133 /* see whether GDI scales bitmap font metrics */
134 static void test_bitmap_font(void)
136 static const char test_str
[11] = "Test String";
139 HFONT hfont
, old_hfont
;
142 INT ret
, i
, width_orig
, height_orig
;
146 /* "System" has only 1 pixel size defined, otherwise the test breaks */
147 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
151 trace("no bitmap fonts were found, skipping the test\n");
155 trace("found bitmap font %s, height %ld\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
157 height_orig
= bitmap_lf
.lfHeight
;
158 hfont
= create_font("bitmap", &bitmap_lf
);
160 old_hfont
= SelectObject(hdc
, hfont
);
161 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
162 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
163 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
164 SelectObject(hdc
, old_hfont
);
167 /* test fractional scaling */
168 for (i
= 1; i
< height_orig
; i
++)
170 hfont
= create_font("fractional", &bitmap_lf
);
171 test_font_metrics(hdc
, hfont
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
175 /* test integer scaling 3x2 */
176 bitmap_lf
.lfHeight
= height_orig
* 2;
177 bitmap_lf
.lfWidth
*= 3;
178 hfont
= create_font("3x2", &bitmap_lf
);
181 test_font_metrics(hdc
, hfont
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
185 /* test integer scaling 3x3 */
186 bitmap_lf
.lfHeight
= height_orig
* 3;
187 bitmap_lf
.lfWidth
= 0;
188 hfont
= create_font("3x3", &bitmap_lf
);
192 test_font_metrics(hdc
, hfont
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
199 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
201 LOGFONT
*lf
= (LOGFONT
*)lParam
;
203 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
206 return 0; /* stop enumeration */
208 return 1; /* continue enumeration */
211 static void test_bitmap_font_metrics(void)
213 static const struct font_data
215 const char face_name
[LF_FACESIZE
];
216 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
217 int ave_char_width
, max_char_width
;
220 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11 },
221 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14 },
222 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16 },
223 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20 },
224 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25 },
225 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32 },
226 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8 },
227 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9 },
228 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12 },
229 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16 },
230 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19 },
231 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23 },
232 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27 },
233 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34 },
234 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8 },
235 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9 },
236 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12 },
237 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15 },
238 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2 },
239 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4 },
240 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13 },
241 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7 },
242 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8 },
243 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9 }
244 /* FIXME: add "Fixedsys", "Terminal" */
248 HFONT hfont
, old_hfont
;
252 hdc
= CreateCompatibleDC(0);
255 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
257 memset(&lf
, 0, sizeof(lf
));
259 lf
.lfHeight
= fd
[i
].height
;
260 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
261 ret
= EnumFontFamilies(hdc
, fd
[i
].face_name
, find_font_proc
, (LPARAM
)&lf
);
264 trace("font %s height %d not found\n", fd
[i
].face_name
, fd
[i
].height
);
268 trace("found font %s, height %ld\n", lf
.lfFaceName
, lf
.lfHeight
);
270 hfont
= create_font(lf
.lfFaceName
, &lf
);
271 old_hfont
= SelectObject(hdc
, hfont
);
272 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %ld\n", GetLastError());
274 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmWeight
, fd
[i
].weight
);
275 ok(tm
.tmHeight
== fd
[i
].height
, "%s(%d): tm.tmHeight %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmHeight
, fd
[i
].height
);
276 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmAscent
, fd
[i
].ascent
);
277 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmDescent
, fd
[i
].descent
);
278 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
279 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
280 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
281 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
283 SelectObject(hdc
, old_hfont
);
290 static void test_GdiGetCharDimensions(void)
296 LONG avgwidth
, height
;
297 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
298 typedef LONG (WINAPI
*fnGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
299 fnGdiGetCharDimensions GdiGetCharDimensions
= (fnGdiGetCharDimensions
)GetProcAddress(LoadLibrary("gdi32"), "GdiGetCharDimensions");
300 if (!GdiGetCharDimensions
) return;
302 hdc
= CreateCompatibleDC(NULL
);
304 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
305 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
307 ret
= GdiGetCharDimensions(hdc
, &tm
, &height
);
308 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
309 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm
.tmHeight
, height
);
311 ret
= GdiGetCharDimensions(hdc
, &tm
, NULL
);
312 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
314 ret
= GdiGetCharDimensions(hdc
, NULL
, NULL
);
315 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
318 ret
= GdiGetCharDimensions(hdc
, NULL
, &height
);
319 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
320 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size
.cy
, height
);
325 static void test_GetCharABCWidthsW(void)
329 typedef BOOL (WINAPI
*fnGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
330 fnGetCharABCWidthsW GetCharABCWidthsW
= (fnGetCharABCWidthsW
)GetProcAddress(LoadLibrary("gdi32"), "GetCharABCWidthsW");
331 if (!GetCharABCWidthsW
) return;
333 ret
= GetCharABCWidthsW(NULL
, 'a', 'a', abc
);
334 ok(!ret
, "GetCharABCWidthsW should have returned FALSE\n");
337 static void test_text_extents(void)
345 memset(&lf
, 0, sizeof(lf
));
346 strcpy(lf
.lfFaceName
, "Arial");
349 hfont
= CreateFontIndirectA(&lf
);
351 hfont
= SelectObject(hdc
, hfont
);
352 GetTextMetricsA(hdc
, &tm
);
353 GetTextExtentPointA(hdc
, "o", 1, &sz
);
354 ok(sz
.cy
== tm
.tmHeight
, "cy %ld tmHeight %ld\n", sz
.cy
, tm
.tmHeight
);
356 SelectObject(hdc
, hfont
);
358 ReleaseDC(NULL
, hdc
);
365 test_bitmap_font_metrics();
366 test_GdiGetCharDimensions();
367 test_GetCharABCWidthsW();