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
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
37 BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
38 DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
39 DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
40 DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
42 static HMODULE hgdi32
= 0;
44 static void init(void)
46 hgdi32
= GetModuleHandleA("gdi32.dll");
48 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
49 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
50 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
51 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
52 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
53 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
56 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
58 if (type
!= TRUETYPE_FONTTYPE
) return 1;
63 static BOOL
is_truetype_font_installed(const char *name
)
68 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
75 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
80 static BOOL
is_font_installed(const char *name
)
85 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
92 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
100 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
101 /* NT4 tries to be clever and only returns the minimum length */
102 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
104 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
105 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
106 ok(!memcmp(&lf
, &lf
, FIELD_OFFSET(LOGFONTA
, lfFaceName
)), "%s: fonts don't match\n", test
);
107 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
),
108 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
111 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
113 HFONT hfont
= CreateFontIndirectA(lf
);
114 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
116 check_font(test
, lf
, hfont
);
120 static void test_logfont(void)
125 memset(&lf
, 0, sizeof lf
);
127 lf
.lfCharSet
= ANSI_CHARSET
;
128 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
129 lf
.lfWeight
= FW_DONTCARE
;
132 lf
.lfQuality
= DEFAULT_QUALITY
;
134 lstrcpyA(lf
.lfFaceName
, "Arial");
135 hfont
= create_font("Arial", &lf
);
138 memset(&lf
, 'A', sizeof(lf
));
139 hfont
= CreateFontIndirectA(&lf
);
140 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
142 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
143 check_font("AAA...", &lf
, hfont
);
147 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
149 if (type
& RASTER_FONTTYPE
)
151 LOGFONT
*lf
= (LOGFONT
*)lParam
;
153 return 0; /* stop enumeration */
156 return 1; /* continue enumeration */
159 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
, const char *test_str
,
160 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
161 const SIZE
*size_orig
, INT width_of_A_orig
,
162 INT scale_x
, INT scale_y
)
168 INT width_of_A
, cx
, cy
;
173 GetObjectA(hfont
, sizeof(lf
), &lf
);
175 old_hfont
= SelectObject(hdc
, hfont
);
177 GetTextMetricsA(hdc
, &tm
);
179 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
180 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
181 ok(cx
== scale_x
&& cy
== scale_y
, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
182 scale_x
, scale_y
, cx
, cy
);
183 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "%d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
184 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "%d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
185 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "%d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
186 ok(tm
.tmAveCharWidth
== tm_orig
->tmAveCharWidth
* scale_x
, "%d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
187 ok(tm
.tmMaxCharWidth
== tm_orig
->tmMaxCharWidth
* scale_x
, "%d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
189 ok(lf
.lfHeight
== lfHeight
, "lf %d != %d\n", lf
.lfHeight
, lfHeight
);
191 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lf %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
193 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
195 ok(size
.cx
== size_orig
->cx
* scale_x
, "%d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
196 ok(size
.cy
== size_orig
->cy
* scale_y
, "%d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
198 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
200 ok(width_of_A
== width_of_A_orig
* scale_x
, "%d != %d\n", width_of_A
, width_of_A_orig
* scale_x
);
202 SelectObject(hdc
, old_hfont
);
205 /* Test how GDI scales bitmap font metrics */
206 static void test_bitmap_font(void)
208 static const char test_str
[11] = "Test String";
211 HFONT hfont
, old_hfont
;
214 INT ret
, i
, width_orig
, height_orig
, scale
;
218 /* "System" has only 1 pixel size defined, otherwise the test breaks */
219 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
223 trace("no bitmap fonts were found, skipping the test\n");
227 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
229 height_orig
= bitmap_lf
.lfHeight
;
230 hfont
= create_font("bitmap", &bitmap_lf
);
232 old_hfont
= SelectObject(hdc
, hfont
);
233 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
234 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
235 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
236 SelectObject(hdc
, old_hfont
);
239 /* test fractional scaling */
240 for (i
= 1; i
<= height_orig
* 3; i
++)
244 bitmap_lf
.lfHeight
= i
;
245 hfont
= create_font("fractional", &bitmap_lf
);
246 scale
= (i
+ height_orig
- 1) / height_orig
;
247 nearest_height
= scale
* height_orig
;
248 /* XP allows not more than 10% deviation */
249 if (scale
> 1 && nearest_height
- i
> nearest_height
/ 10) scale
--;
250 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
254 /* test integer scaling 3x2 */
255 bitmap_lf
.lfHeight
= height_orig
* 2;
256 bitmap_lf
.lfWidth
*= 3;
257 hfont
= create_font("3x2", &bitmap_lf
);
258 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
261 /* test integer scaling 3x3 */
262 bitmap_lf
.lfHeight
= height_orig
* 3;
263 bitmap_lf
.lfWidth
= 0;
264 hfont
= create_font("3x3", &bitmap_lf
);
265 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
271 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
273 LOGFONT
*lf
= (LOGFONT
*)lParam
;
275 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
278 return 0; /* stop enumeration */
280 return 1; /* continue enumeration */
283 static void test_bitmap_font_metrics(void)
285 static const struct font_data
287 const char face_name
[LF_FACESIZE
];
288 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
289 int ave_char_width
, max_char_width
;
293 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
294 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
295 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, FS_LATIN1
| FS_CYRILLIC
},
296 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, FS_LATIN2
},
297 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, FS_LATIN1
},
298 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, FS_LATIN2
},
299 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, FS_CYRILLIC
},
300 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, FS_LATIN1
},
301 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, FS_LATIN2
},
302 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, FS_CYRILLIC
},
303 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
304 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1
| FS_LATIN2
},
305 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC
},
306 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
307 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, FS_LATIN1
},
308 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, FS_LATIN2
| FS_CYRILLIC
},
309 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, FS_LATIN1
| FS_LATIN2
},
310 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, FS_CYRILLIC
},
311 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, FS_LATIN1
| FS_LATIN2
},
312 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, FS_CYRILLIC
},
313 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, FS_LATIN1
},
314 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, FS_LATIN2
},
315 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, FS_CYRILLIC
},
316 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, FS_LATIN1
},
317 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, FS_LATIN2
},
318 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, FS_CYRILLIC
},
319 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, FS_LATIN1
| FS_LATIN2
},
320 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, FS_CYRILLIC
},
321 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
322 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
323 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
324 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, FS_LATIN1
},
325 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, FS_LATIN2
| FS_CYRILLIC
},
327 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
328 * require a new system.sfd for that font
330 { "System", FW_BOLD
, 18, 16, 2, 0, 2, 8, 16, FS_JISJAPAN
},
331 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, FS_LATIN1
},
332 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, FS_LATIN2
| FS_CYRILLIC
},
333 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, FS_JISJAPAN
},
334 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, FS_LATIN1
},
335 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, FS_LATIN2
| FS_CYRILLIC
},
336 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, FS_JISJAPAN
},
337 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, FS_LATIN1
},
338 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, FS_LATIN2
| FS_CYRILLIC
},
339 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, FS_JISJAPAN
},
340 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, FS_LATIN1
},
341 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, FS_LATIN2
| FS_CYRILLIC
},
342 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, FS_JISJAPAN
},
343 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, FS_LATIN1
| FS_LATIN2
},
344 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, FS_CYRILLIC
},
345 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, FS_JISJAPAN
},
346 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
347 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, FS_JISJAPAN
},
348 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, FS_LATIN1
| FS_LATIN2
},
349 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, FS_CYRILLIC
},
350 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, FS_JISJAPAN
}
352 /* FIXME: add "Terminal" */
356 HFONT hfont
, old_hfont
;
360 hdc
= CreateCompatibleDC(0);
363 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
367 memset(&lf
, 0, sizeof(lf
));
369 lf
.lfHeight
= fd
[i
].height
;
370 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
372 for(bit
= 0; bit
< 32; bit
++)
379 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
380 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
382 lf
.lfCharSet
= csi
.ciCharset
;
383 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
386 trace("found font %s, height %d charset %x\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
388 hfont
= create_font(lf
.lfFaceName
, &lf
);
389 old_hfont
= SelectObject(hdc
, hfont
);
390 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %d\n", GetLastError());
392 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
);
393 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
);
394 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
);
395 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
);
396 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
);
397 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
);
398 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
);
400 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
401 that make the max width bigger */
402 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
403 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
);
405 SelectObject(hdc
, old_hfont
);
413 static void test_GdiGetCharDimensions(void)
419 LONG avgwidth
, height
;
420 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
422 if (!pGdiGetCharDimensions
)
424 skip("GdiGetCharDimensions not available on this platform\n");
428 hdc
= CreateCompatibleDC(NULL
);
430 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
431 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
433 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
434 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
435 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
437 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
438 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
440 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
441 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
444 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
445 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
446 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
451 static void test_GetCharABCWidths(void)
453 static const WCHAR str
[] = {'a',0};
462 if (!pGetCharABCWidthsW
|| !pGetCharABCWidthsI
)
464 skip("GetCharABCWidthsW/I not available on this platform\n");
468 memset(&lf
, 0, sizeof(lf
));
469 strcpy(lf
.lfFaceName
, "System");
472 hfont
= CreateFontIndirectA(&lf
);
474 hfont
= SelectObject(hdc
, hfont
);
476 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
477 ok(nb
== 1, "pGetGlyphIndicesW should have returned 1\n");
479 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
480 ok(!ret
, "GetCharABCWidthsI should have failed\n");
482 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
483 ok(!ret
, "GetCharABCWidthsI should have failed\n");
485 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
486 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
488 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
489 ok(!ret
, "GetCharABCWidthsW should have failed\n");
491 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
492 ok(!ret
, "GetCharABCWidthsW should have failed\n");
494 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
495 ok(!ret
, "GetCharABCWidthsW should have failed\n");
497 hfont
= SelectObject(hdc
, hfont
);
499 ReleaseDC(NULL
, hdc
);
502 static void test_text_extents(void)
504 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
506 INT i
, len
, fit1
, fit2
;
514 memset(&lf
, 0, sizeof(lf
));
515 strcpy(lf
.lfFaceName
, "Arial");
518 hfont
= CreateFontIndirectA(&lf
);
520 hfont
= SelectObject(hdc
, hfont
);
521 GetTextMetricsA(hdc
, &tm
);
522 GetTextExtentPointA(hdc
, "o", 1, &sz
);
523 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
525 SetLastError(0xdeadbeef);
526 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
527 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
529 skip("Skipping remainder of text extents test on a Win9x platform\n");
530 hfont
= SelectObject(hdc
, hfont
);
537 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
538 extents
[0] = 1; /* So that the increasing sequence test will fail
539 if the extents array is untouched. */
540 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
541 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
543 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
544 /* Because of the '\n' in the string GetTextExtentExPoint and
545 GetTextExtentPoint return different widths under Win2k, but
546 under WinXP they return the same width. So we don't test that
549 for (i
= 1; i
< len
; ++i
)
550 ok(extents
[i
-1] <= extents
[i
],
551 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
553 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
554 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
555 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
556 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
557 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
558 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
559 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
560 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
561 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
562 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
563 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
564 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
565 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
566 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
567 HeapFree(GetProcessHeap(), 0, extents
);
569 hfont
= SelectObject(hdc
, hfont
);
571 ReleaseDC(NULL
, hdc
);
574 static void test_GetGlyphIndices(void)
581 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
582 WORD glyphs
[(sizeof(testtext
)/2)-1];
585 if (!pGetGlyphIndicesW
) {
586 skip("GetGlyphIndices not available on platform\n");
590 if(!is_font_installed("Symbol"))
592 skip("Symbol is not installed so skipping this test\n");
596 memset(&lf
, 0, sizeof(lf
));
597 strcpy(lf
.lfFaceName
, "Symbol");
600 hfont
= CreateFontIndirectA(&lf
);
603 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
604 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
605 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
606 ok(charcount
== 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount
);
607 ok((glyphs
[4] == 0x001f || glyphs
[4] == UNICODE_NOCHAR
/* Vista */), "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs
[4]);
609 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
610 ok(charcount
== 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount
);
611 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndices should have returned a %04x not %04x\n",
612 textm
.tmDefaultChar
, glyphs
[4]);
615 static void test_GetKerningPairs(void)
617 static const struct kerning_data
619 const char face_name
[LF_FACESIZE
];
621 /* some interesting fields from OUTLINETEXTMETRIC */
622 LONG tmHeight
, tmAscent
, tmDescent
;
627 UINT otmsCapEmHeight
;
632 UINT otmusMinimumPPEM
;
633 /* small subset of kerning pairs to test */
634 DWORD total_kern_pairs
;
635 const KERNINGPAIR kern_pair
[26];
638 {"Arial", 12, 12, 9, 3,
639 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
642 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
643 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
644 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
645 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
646 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
647 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
648 {933,970,+1},{933,972,-1}
651 {"Arial", -34, 39, 32, 7,
652 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
655 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
656 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
657 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
658 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
659 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
660 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
661 {933,970,+2},{933,972,-3}
664 { "Arial", 120, 120, 97, 23,
665 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
668 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
669 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
670 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
671 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
672 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
673 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
674 {933,970,+6},{933,972,-10}
677 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
678 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
679 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
682 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
683 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
684 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
685 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
686 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
687 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
688 {933,970,+54},{933,972,-83}
694 HFONT hfont
, hfont_old
;
695 KERNINGPAIR
*kern_pair
;
697 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
701 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
702 * which may render this test unusable, so we're trying to avoid that.
704 SetLastError(0xdeadbeef);
705 GetKerningPairsW(hdc
, 0, NULL
);
706 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
708 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
713 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
715 OUTLINETEXTMETRICW otm
;
717 if (!is_font_installed(kd
[i
].face_name
))
719 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
723 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
725 memset(&lf
, 0, sizeof(lf
));
726 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
727 lf
.lfHeight
= kd
[i
].height
;
728 hfont
= CreateFontIndirect(&lf
);
731 hfont_old
= SelectObject(hdc
, hfont
);
733 SetLastError(0xdeadbeef);
734 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
735 ok(GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
) == sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
737 ok(kd
[i
].tmHeight
== otm
.otmTextMetrics
.tmHeight
, "expected %d, got %d\n",
738 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
739 ok(kd
[i
].tmAscent
== otm
.otmTextMetrics
.tmAscent
, "expected %d, got %d\n",
740 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
741 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
742 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
744 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
745 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
746 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
747 kd
[i
].otmAscent
, otm
.otmAscent
);
748 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
749 kd
[i
].otmDescent
, otm
.otmDescent
);
750 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
751 kd
[i
].otmLineGap
, otm
.otmLineGap
);
753 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
754 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
755 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
756 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
757 ok(kd
[i
].otmMacAscent
== otm
.otmMacAscent
, "expected %d, got %d\n",
758 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
759 ok(kd
[i
].otmMacDescent
== otm
.otmMacDescent
, "expected %d, got %d\n",
760 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
761 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
762 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
763 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
764 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
765 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
768 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
769 trace("total_kern_pairs %u\n", total_kern_pairs
);
770 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
772 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
773 SetLastError(0xdeadbeef);
774 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
775 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
776 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
777 ok(ret
== 0, "got %lu, expected 0\n", ret
);
780 ret
= GetKerningPairsW(hdc
, 100, NULL
);
781 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
783 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
784 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
786 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
787 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
791 for (n
= 0; n
< ret
; n
++)
795 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
796 trace("{'%c','%c',%d},\n",
797 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
799 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
801 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
802 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
804 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
805 "pair %d:%d got %d, expected %d\n",
806 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
807 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
813 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
814 matches
, kd
[i
].total_kern_pairs
);
816 HeapFree(GetProcessHeap(), 0, kern_pair
);
818 SelectObject(hdc
, hfont_old
);
825 static void test_GetOutlineTextMetrics(void)
827 OUTLINETEXTMETRIC
*otm
;
829 HFONT hfont
, hfont_old
;
833 if (!is_font_installed("Arial"))
835 skip("Arial is not installed\n");
841 memset(&lf
, 0, sizeof(lf
));
842 strcpy(lf
.lfFaceName
, "Arial");
844 lf
.lfWeight
= FW_NORMAL
;
845 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
846 lf
.lfQuality
= PROOF_QUALITY
;
847 hfont
= CreateFontIndirect(&lf
);
850 hfont_old
= SelectObject(hdc
, hfont
);
851 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
852 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
854 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
856 memset(otm
, 0xAA, otm_size
);
857 SetLastError(0xdeadbeef);
858 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
859 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
860 ok(ret
== 1 /* Win9x */ ||
861 ret
== otm
->otmSize
/* XP*/,
862 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
863 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
865 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
866 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
867 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
868 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
871 memset(otm
, 0xAA, otm_size
);
872 SetLastError(0xdeadbeef);
873 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
874 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
875 ok(ret
== 1 /* Win9x */ ||
876 ret
== otm
->otmSize
/* XP*/,
877 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
878 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
880 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
881 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
882 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
883 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
886 /* ask about truncated data */
887 memset(otm
, 0xAA, otm_size
);
888 SetLastError(0xdeadbeef);
889 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
890 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
891 ok(ret
== 1 /* Win9x */ ||
892 ret
== otm
->otmSize
/* XP*/,
893 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
894 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
896 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
897 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
898 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
900 ok(otm
->otmpFullName
== (LPSTR
)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm
->otmpFullName
);
902 HeapFree(GetProcessHeap(), 0, otm
);
904 SelectObject(hdc
, hfont_old
);
910 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
914 outputWidth
= 0, /* to test TabbedTextOut() */
915 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
916 areaWidth
= clientArea
->right
- clientArea
->left
,
918 BOOL lastExtent
= FALSE
;
919 PSTR pFirstChar
, pLastChar
;
925 int GetTextExtentExPointWWidth
;
926 int TabbedTextOutWidth
;
929 GetTextMetricsA(hdc
, &tm
);
933 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
939 /* if not at the end of the string, ... */
940 if (*str
== '\0') break;
941 /* ... add the next word to the current extent */
942 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
944 SetTextJustification(hdc
, 0, 0);
945 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
946 } while ((int) size
.cx
< areaWidth
);
948 /* ignore trailing break chars */
950 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
956 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
958 SetTextJustification(hdc
, 0, 0);
959 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
961 /* do not justify the last extent */
962 if (*str
!= '\0' && breakCount
> 0)
964 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
965 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
966 justifiedWidth
= size
.cx
;
968 else lastExtent
= TRUE
;
970 x
= clientArea
->left
;
972 outputWidth
= LOWORD(TabbedTextOut(
973 hdc
, x
, y
, pFirstChar
, pLastChar
- pFirstChar
,
975 /* catch errors and report them */
976 if (!lastExtent
&& ((outputWidth
!= areaWidth
) || (justifiedWidth
!= areaWidth
)))
978 memset(error
[nErrors
].extent
, 0, 100);
979 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
980 error
[nErrors
].TabbedTextOutWidth
= outputWidth
;
981 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
987 } while (*str
&& y
< clientArea
->bottom
);
989 for (e
= 0; e
< nErrors
; e
++)
991 ok(error
[e
].TabbedTextOutWidth
== areaWidth
,
992 "The output text (\"%s\") width should be %d, not %d.\n",
993 error
[e
].extent
, areaWidth
, error
[e
].TabbedTextOutWidth
);
994 /* The width returned by GetTextExtentPoint32() is exactly the same
995 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
996 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
997 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
998 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1002 static void test_SetTextJustification(void)
1009 static char testText
[] =
1010 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1011 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1012 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1013 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1014 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1015 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1016 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1018 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1019 GetClientRect( hwnd
, &clientArea
);
1020 hdc
= GetDC( hwnd
);
1022 memset(&lf
, 0, sizeof lf
);
1023 lf
.lfCharSet
= ANSI_CHARSET
;
1024 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1025 lf
.lfWeight
= FW_DONTCARE
;
1027 lf
.lfQuality
= DEFAULT_QUALITY
;
1028 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1029 hfont
= create_font("Times New Roman", &lf
);
1030 SelectObject(hdc
, hfont
);
1032 testJustification(hdc
, testText
, &clientArea
);
1034 DeleteObject(hfont
);
1035 ReleaseDC(hwnd
, hdc
);
1036 DestroyWindow(hwnd
);
1039 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1043 HFONT hfont
, hfont_old
;
1050 assert(count
<= 128);
1052 memset(&lf
, 0, sizeof(lf
));
1054 lf
.lfCharSet
= charset
;
1056 lstrcpyA(lf
.lfFaceName
, "Arial");
1057 SetLastError(0xdeadbeef);
1058 hfont
= CreateFontIndirectA(&lf
);
1059 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1062 hfont_old
= SelectObject(hdc
, hfont
);
1064 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1065 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1067 SetLastError(0xdeadbeef);
1068 ret
= GetTextFace(hdc
, sizeof(name
), name
);
1069 ok(ret
, "GetTextFace error %u\n", GetLastError());
1071 if (charset
== SYMBOL_CHARSET
)
1073 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1074 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1078 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1079 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1082 if (!TranslateCharsetInfo((DWORD
*)cs
, &csi
, TCI_SRCCHARSET
))
1084 trace("Can't find codepage for charset %d\n", cs
);
1088 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1093 WCHAR unicode_buf
[128];
1095 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1097 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1099 SetLastError(0xdeadbeef);
1100 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1101 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1107 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1109 SetLastError(0xdeadbeef);
1110 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1111 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1114 SelectObject(hdc
, hfont_old
);
1115 DeleteObject(hfont
);
1122 static void test_font_charset(void)
1124 static struct charset_data
1128 WORD font_idxA
[128], font_idxW
[128];
1131 { ANSI_CHARSET
, 1252 },
1132 { RUSSIAN_CHARSET
, 1251 },
1133 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1137 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1139 skip("Skipping the font charset test on a Win9x platform\n");
1143 if (!is_font_installed("Arial"))
1145 skip("Arial is not installed\n");
1149 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1151 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1153 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1155 skip("Symbol or Wingdings is not installed\n");
1159 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
);
1160 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
);
1161 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1164 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1167 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1168 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1171 skip("Symbol or Wingdings is not installed\n");
1174 static void test_GetFontUnicodeRanges(void)
1178 HFONT hfont
, hfont_old
;
1182 if (!pGetFontUnicodeRanges
)
1184 skip("GetFontUnicodeRanges not available before W2K\n");
1188 memset(&lf
, 0, sizeof(lf
));
1189 lstrcpyA(lf
.lfFaceName
, "Arial");
1190 hfont
= create_font("Arial", &lf
);
1193 hfont_old
= SelectObject(hdc
, hfont
);
1195 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1196 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1198 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1199 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1201 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1203 size
= pGetFontUnicodeRanges(hdc
, gs
);
1204 ok(size
, "GetFontUnicodeRanges failed\n");
1206 for (i
= 0; i
< gs
->cRanges
; i
++)
1207 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1209 trace("found %u ranges\n", gs
->cRanges
);
1211 HeapFree(GetProcessHeap(), 0, gs
);
1213 SelectObject(hdc
, hfont_old
);
1214 DeleteObject(hfont
);
1215 ReleaseDC(NULL
, hdc
);
1218 #define MAX_ENUM_FONTS 256
1220 struct enum_font_data
1223 LOGFONT lf
[MAX_ENUM_FONTS
];
1226 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1228 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1230 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1232 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1233 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfWeight
, lf
->lfItalic
);
1235 if (efd
->total
< MAX_ENUM_FONTS
)
1236 efd
->lf
[efd
->total
++] = *lf
;
1241 static void get_charset_stats(struct enum_font_data
*efd
,
1242 int *ansi_charset
, int *symbol_charset
,
1243 int *russian_charset
)
1248 *symbol_charset
= 0;
1249 *russian_charset
= 0;
1251 for (i
= 0; i
< efd
->total
; i
++)
1253 switch (efd
->lf
[i
].lfCharSet
)
1258 case SYMBOL_CHARSET
:
1259 (*symbol_charset
)++;
1261 case RUSSIAN_CHARSET
:
1262 (*russian_charset
)++;
1268 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1270 struct enum_font_data efd
;
1273 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1275 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1277 if (*font_name
&& !is_truetype_font_installed(font_name
))
1279 skip("%s is not installed\n", font_name
);
1285 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1286 * while EnumFontFamiliesEx doesn't.
1288 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1291 SetLastError(0xdeadbeef);
1292 ret
= EnumFontFamilies(hdc
, NULL
, arial_enum_proc
, (LPARAM
)&efd
);
1293 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1294 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1295 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1296 ansi_charset
, symbol_charset
, russian_charset
);
1297 ok(efd
.total
> 0, "no fonts enumerated: NULL\n");
1298 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1299 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1300 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1303 SetLastError(0xdeadbeef);
1304 ret
= EnumFontFamiliesEx(hdc
, NULL
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1305 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1306 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1307 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1308 ansi_charset
, symbol_charset
, russian_charset
);
1309 ok(efd
.total
> 0, "no fonts enumerated: NULL\n");
1310 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1311 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1312 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1316 SetLastError(0xdeadbeef);
1317 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
1318 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1319 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1320 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1321 ansi_charset
, symbol_charset
, russian_charset
,
1322 *font_name
? font_name
: "<empty>");
1324 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1326 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
1327 for (i
= 0; i
< efd
.total
; i
++)
1329 /* FIXME: remove completely once Wine is fixed */
1330 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
1333 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1336 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1337 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1338 font_name
, efd
.lf
[i
].lfFaceName
);
1341 memset(&lf
, 0, sizeof(lf
));
1342 lf
.lfCharSet
= ANSI_CHARSET
;
1343 lstrcpy(lf
.lfFaceName
, font_name
);
1345 SetLastError(0xdeadbeef);
1346 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1347 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1348 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1349 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1350 ansi_charset
, symbol_charset
, russian_charset
,
1351 *font_name
? font_name
: "<empty>");
1352 if (font_charset
== SYMBOL_CHARSET
)
1355 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
1357 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1361 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
1362 for (i
= 0; i
< efd
.total
; i
++)
1364 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1366 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1367 font_name
, efd
.lf
[i
].lfFaceName
);
1371 /* DEFAULT_CHARSET should enumerate all available charsets */
1372 memset(&lf
, 0, sizeof(lf
));
1373 lf
.lfCharSet
= DEFAULT_CHARSET
;
1374 lstrcpy(lf
.lfFaceName
, font_name
);
1376 SetLastError(0xdeadbeef);
1377 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1378 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1379 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1380 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1381 ansi_charset
, symbol_charset
, russian_charset
,
1382 *font_name
? font_name
: "<empty>");
1383 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
1384 for (i
= 0; i
< efd
.total
; i
++)
1387 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1388 font_name
, efd
.lf
[i
].lfFaceName
);
1392 switch (font_charset
)
1395 ok(ansi_charset
> 0,
1396 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1398 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
1399 ok(russian_charset
> 0,
1400 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1402 case SYMBOL_CHARSET
:
1404 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
1406 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1407 ok(!russian_charset
,
1408 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1410 case DEFAULT_CHARSET
:
1411 ok(ansi_charset
> 0,
1412 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1413 ok(symbol_charset
> 0,
1414 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1415 ok(russian_charset
> 0,
1416 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1422 ok(ansi_charset
> 0,
1423 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1424 ok(symbol_charset
> 0,
1425 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1426 ok(russian_charset
> 0,
1427 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1430 memset(&lf
, 0, sizeof(lf
));
1431 lf
.lfCharSet
= SYMBOL_CHARSET
;
1432 lstrcpy(lf
.lfFaceName
, font_name
);
1434 SetLastError(0xdeadbeef);
1435 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1436 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1437 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1438 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1439 ansi_charset
, symbol_charset
, russian_charset
,
1440 *font_name
? font_name
: "<empty>");
1441 if (*font_name
&& font_charset
== ANSI_CHARSET
)
1442 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
1445 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
1446 for (i
= 0; i
< efd
.total
; i
++)
1448 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1450 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1451 font_name
, efd
.lf
[i
].lfFaceName
);
1455 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1456 ok(symbol_charset
> 0,
1457 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1458 ok(!russian_charset
,
1459 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1465 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1466 #include "pshpack2.h"
1470 SHORT xAvgCharWidth
;
1471 USHORT usWeightClass
;
1472 USHORT usWidthClass
;
1474 SHORT ySubscriptXSize
;
1475 SHORT ySubscriptYSize
;
1476 SHORT ySubscriptXOffset
;
1477 SHORT ySubscriptYOffset
;
1478 SHORT ySuperscriptXSize
;
1479 SHORT ySuperscriptYSize
;
1480 SHORT ySuperscriptXOffset
;
1481 SHORT ySuperscriptYOffset
;
1482 SHORT yStrikeoutSize
;
1483 SHORT yStrikeoutPosition
;
1486 ULONG ulUnicodeRange1
;
1487 ULONG ulUnicodeRange2
;
1488 ULONG ulUnicodeRange3
;
1489 ULONG ulUnicodeRange4
;
1492 USHORT usFirstCharIndex
;
1493 USHORT usLastCharIndex
;
1494 /* According to the Apple spec, original version didn't have the below fields,
1495 * version numbers were taked from the OpenType spec.
1497 /* version 0 (TrueType 1.5) */
1498 USHORT sTypoAscender
;
1499 USHORT sTypoDescender
;
1500 USHORT sTypoLineGap
;
1502 USHORT usWinDescent
;
1503 /* version 1 (TrueType 1.66) */
1504 ULONG ulCodePageRange1
;
1505 ULONG ulCodePageRange2
;
1506 /* version 2 (OpenType 1.2) */
1509 USHORT usDefaultChar
;
1511 USHORT usMaxContext
;
1513 #include "poppack.h"
1515 #ifdef WORDS_BIGENDIAN
1516 #define GET_BE_WORD(x) (x)
1518 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1521 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1522 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1523 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1524 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1526 static void test_text_metrics(const LOGFONTA
*lf
)
1529 HFONT hfont
, hfont_old
;
1532 UINT first_unicode_char
, last_unicode_char
, default_char
, break_char
;
1537 const char *font_name
= lf
->lfFaceName
;
1539 trace("Testing font metrics for %s, charset %d\n", font_name
, lf
->lfCharSet
);
1543 SetLastError(0xdeadbeef);
1544 hfont
= CreateFontIndirectA(lf
);
1545 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1547 hfont_old
= SelectObject(hdc
, hfont
);
1549 if(lf
->lfWidth
> 0) {
1550 HFONT hfont2
, hfont_prev
;
1551 GLYPHMETRICS gm1
, gm2
;
1553 MAT2 mat2
= { {0,1}, {0,0}, {0,0}, {0,1} };
1555 /* negative widths are handled just as positive ones */
1558 SetLastError(0xdeadbeef);
1559 hfont2
= CreateFontIndirectA(&lf2
);
1560 ok(hfont2
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1561 hfont_prev
= SelectObject(hdc
, hfont2
);
1563 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1564 memset(&gm1
, 0xab, sizeof(gm1
));
1565 SetLastError(0xdeadbeef);
1566 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat2
);
1567 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1569 SelectObject(hdc
, hfont_prev
);
1570 DeleteObject(hfont2
);
1572 memset(&gm2
, 0xbb, sizeof(gm2
));
1573 SetLastError(0xdeadbeef);
1574 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat2
);
1575 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1577 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
1578 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
1579 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
1580 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
1581 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
1582 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
1583 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1584 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
1585 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
1586 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
1587 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
1590 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
1591 if (size
== GDI_ERROR
)
1593 trace("OS/2 chunk was not found\n");
1596 if (size
> sizeof(tt_os2
))
1598 trace("got too large OS/2 chunk of size %u\n", size
);
1599 size
= sizeof(tt_os2
);
1602 memset(&tt_os2
, 0, sizeof(tt_os2
));
1603 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
1604 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
1606 version
= GET_BE_WORD(tt_os2
.version
);
1607 trace("OS/2 chunk version %u, vendor %4.4s\n", version
, (LPCSTR
)&tt_os2
.achVendID
);
1609 first_unicode_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
1610 last_unicode_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
1611 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
1612 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
1614 trace("for %s first %x, last %x, default %x, break %x\n", font_name
,
1615 first_unicode_char
, last_unicode_char
, default_char
, break_char
);
1617 SetLastError(0xdeadbeef);
1618 ret
= GetTextMetricsA(hdc
, &tmA
);
1619 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
1620 trace("A: first %x, last %x, default %x, break %x\n",
1621 tmA
.tmFirstChar
, tmA
.tmLastChar
, tmA
.tmDefaultChar
, tmA
.tmBreakChar
);
1623 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1624 test_char
= min(first_unicode_char
- 1, 255);
1625 ok(tmA
.tmFirstChar
== test_char
, "A: tmFirstChar for %s %02x != %02x\n",
1626 font_name
, tmA
.tmFirstChar
, test_char
);
1628 if (lf
->lfCharSet
== SYMBOL_CHARSET
)
1630 test_char
= min(last_unicode_char
- 0xf000, 255);
1631 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
1632 font_name
, tmA
.tmLastChar
, test_char
);
1636 test_char
= min(last_unicode_char
, 255);
1637 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
1638 font_name
, tmA
.tmLastChar
, test_char
);
1641 SetLastError(0xdeadbeef);
1642 ret
= GetTextMetricsW(hdc
, &tmW
);
1643 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
1644 "GetTextMetricsW error %u\n", GetLastError());
1647 trace("W: first %x, last %x, default %x, break %x\n",
1648 tmW
.tmFirstChar
, tmW
.tmLastChar
, tmW
.tmDefaultChar
,
1651 if (lf
->lfCharSet
== SYMBOL_CHARSET
)
1653 /* It appears that for fonts with SYMBOL_CHARSET Windows always
1654 * sets symbol range to 0 - f0ff
1656 ok(tmW
.tmFirstChar
== 0, "W: tmFirstChar for %s %02x != 0\n",
1657 font_name
, tmW
.tmFirstChar
);
1658 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1659 ok(tmW
.tmLastChar
>= 0xf000, "W: tmLastChar for %s %02x < 0xf000\n",
1660 font_name
, tmW
.tmLastChar
);
1662 ok(tmW
.tmDefaultChar
== 0x1f, "W: tmDefaultChar for %s %02x != 0x1f\n",
1663 font_name
, tmW
.tmDefaultChar
);
1664 ok(tmW
.tmBreakChar
== 0x20, "W: tmBreakChar for %s %02x != 0x20\n",
1665 font_name
, tmW
.tmBreakChar
);
1669 ok(tmW
.tmFirstChar
== first_unicode_char
, "W: tmFirstChar for %s %02x != %02x\n",
1670 font_name
, tmW
.tmFirstChar
, first_unicode_char
);
1671 ok(tmW
.tmLastChar
== last_unicode_char
, "W: tmLastChar for %s %02x != %02x\n",
1672 font_name
, tmW
.tmLastChar
, last_unicode_char
);
1674 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
1675 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
1676 tmW
.tmDigitizedAspectX
, ret
);
1677 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
1678 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
1679 tmW
.tmDigitizedAspectX
, ret
);
1683 SelectObject(hdc
, hfont_old
);
1684 DeleteObject(hfont
);
1689 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
1691 INT
*enumed
= (INT
*)lParam
;
1693 if (type
== TRUETYPE_FONTTYPE
)
1696 test_text_metrics(lf
);
1701 static void test_GetTextMetrics(void)
1709 memset(&lf
, 0, sizeof(lf
));
1710 lf
.lfCharSet
= DEFAULT_CHARSET
;
1712 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
1713 trace("Tested metrics of %d truetype fonts\n", enumed
);
1718 static void test_nonexistent_font(void)
1723 char buf
[LF_FACESIZE
];
1725 if (!is_truetype_font_installed("Arial Black"))
1727 skip("Arial not installed\n");
1733 memset(&lf
, 0, sizeof(lf
));
1735 lf
.lfWeight
= FW_REGULAR
;
1736 lf
.lfCharSet
= ANSI_CHARSET
;
1737 lf
.lfPitchAndFamily
= FF_SWISS
;
1738 strcpy(lf
.lfFaceName
, "Nonexistent font");
1740 hfont
= CreateFontIndirectA(&lf
);
1741 hfont
= SelectObject(hdc
, hfont
);
1742 GetTextFaceA(hdc
, sizeof(buf
), buf
);
1743 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
1744 DeleteObject(SelectObject(hdc
, hfont
));
1754 test_bitmap_font_metrics();
1755 test_GdiGetCharDimensions();
1756 test_GetCharABCWidths();
1757 test_text_extents();
1758 test_GetGlyphIndices();
1759 test_GetKerningPairs();
1760 test_GetOutlineTextMetrics();
1761 test_SetTextJustification();
1762 test_font_charset();
1763 test_GetFontUnicodeRanges();
1764 test_nonexistent_font();
1766 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1767 * I'd like to avoid them in this test.
1769 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
1770 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
1771 if (is_truetype_font_installed("Arial Black") &&
1772 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1774 test_EnumFontFamilies("", ANSI_CHARSET
);
1775 test_EnumFontFamilies("", SYMBOL_CHARSET
);
1776 test_EnumFontFamilies("", DEFAULT_CHARSET
);
1779 skip("Arial Black or Symbol/Wingdings is not installed\n");
1780 test_GetTextMetrics();