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
},
327 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, CP1252_BIT
},
328 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, CP1250_BIT
| CP1251_BIT
},
329 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, CP1252_BIT
},
330 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, CP1250_BIT
| CP1251_BIT
},
331 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, CP1252_BIT
},
332 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, CP1250_BIT
| CP1251_BIT
},
333 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, CP1252_BIT
},
334 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, CP1250_BIT
| CP1251_BIT
},
335 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, CP1252_BIT
| CP1250_BIT
},
336 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, CP1251_BIT
},
337 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, CP1252_BIT
| CP1250_BIT
| CP1251_BIT
},
338 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, CP1252_BIT
| CP1250_BIT
},
339 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, CP1251_BIT
}
341 /* FIXME: add "Terminal" */
345 HFONT hfont
, old_hfont
;
349 hdc
= CreateCompatibleDC(0);
352 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
356 memset(&lf
, 0, sizeof(lf
));
358 lf
.lfHeight
= fd
[i
].height
;
359 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
361 for(bit
= 0; bit
< 32; bit
++)
368 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
369 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
371 lf
.lfCharSet
= csi
.ciCharset
;
372 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
375 trace("found font %s, height %d charset %x\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
377 hfont
= create_font(lf
.lfFaceName
, &lf
);
378 old_hfont
= SelectObject(hdc
, hfont
);
379 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %d\n", GetLastError());
381 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmWeight
, fd
[i
].weight
);
382 ok(tm
.tmHeight
== fd
[i
].height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmHeight
, fd
[i
].height
);
383 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmAscent
, fd
[i
].ascent
);
384 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmDescent
, fd
[i
].descent
);
385 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
386 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
387 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
389 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
390 that make the max width bigger */
391 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
392 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
394 SelectObject(hdc
, old_hfont
);
402 static void test_GdiGetCharDimensions(void)
408 LONG avgwidth
, height
;
409 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
411 if (!pGdiGetCharDimensions
)
413 skip("GdiGetCharDimensions not available on this platform\n");
417 hdc
= CreateCompatibleDC(NULL
);
419 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
420 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
422 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
423 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
424 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
426 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
427 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
429 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
430 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
433 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
434 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
435 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
440 static void test_GetCharABCWidthsW(void)
444 if (!pGetCharABCWidthsW
) return;
446 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
447 ok(!ret
, "GetCharABCWidthsW should have returned FALSE\n");
450 static void test_text_extents(void)
452 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
454 INT i
, len
, fit1
, fit2
;
462 memset(&lf
, 0, sizeof(lf
));
463 strcpy(lf
.lfFaceName
, "Arial");
466 hfont
= CreateFontIndirectA(&lf
);
468 hfont
= SelectObject(hdc
, hfont
);
469 GetTextMetricsA(hdc
, &tm
);
470 GetTextExtentPointA(hdc
, "o", 1, &sz
);
471 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
473 SetLastError(0xdeadbeef);
474 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
475 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
477 skip("Skipping remainder of text extents test on a Win9x platform\n");
478 hfont
= SelectObject(hdc
, hfont
);
485 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
486 extents
[0] = 1; /* So that the increasing sequence test will fail
487 if the extents array is untouched. */
488 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
489 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
491 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
492 /* Because of the '\n' in the string GetTextExtentExPoint and
493 GetTextExtentPoint return different widths under Win2k, but
494 under WinXP they return the same width. So we don't test that
497 for (i
= 1; i
< len
; ++i
)
498 ok(extents
[i
-1] <= extents
[i
],
499 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
501 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
502 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
503 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
504 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
505 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
506 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
507 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
508 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
509 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
510 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
511 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
512 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
513 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
514 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
515 HeapFree(GetProcessHeap(), 0, extents
);
517 hfont
= SelectObject(hdc
, hfont
);
519 ReleaseDC(NULL
, hdc
);
522 static void test_GetGlyphIndices(void)
529 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
530 WORD glyphs
[(sizeof(testtext
)/2)-1];
533 if (!pGetGlyphIndicesW
) {
534 skip("GetGlyphIndices not available on platform\n");
538 if(!is_font_installed("Symbol"))
540 skip("Symbol is not installed so skipping this test\n");
544 memset(&lf
, 0, sizeof(lf
));
545 strcpy(lf
.lfFaceName
, "Symbol");
548 hfont
= CreateFontIndirectA(&lf
);
551 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
552 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
553 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
554 ok(charcount
== 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount
);
555 ok(glyphs
[4] == 0x001f, "GetGlyphIndices should have returned a nonexistent char not %04x\n", glyphs
[4]);
557 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
558 ok(charcount
== 5, "GetGlyphIndices count of glyphs should = 5 not %d\n", charcount
);
559 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndices should have returned a %04x not %04x\n",
560 textm
.tmDefaultChar
, glyphs
[4]);
563 static void test_GetKerningPairs(void)
565 static const struct kerning_data
567 const char face_name
[LF_FACESIZE
];
569 /* some interesting fields from OUTLINETEXTMETRIC */
570 LONG tmHeight
, tmAscent
, tmDescent
;
575 UINT otmsCapEmHeight
;
580 UINT otmusMinimumPPEM
;
581 /* small subset of kerning pairs to test */
582 DWORD total_kern_pairs
;
583 const KERNINGPAIR kern_pair
[26];
586 {"Arial", 12, 12, 9, 3,
587 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
590 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
591 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
592 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
593 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
594 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
595 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
596 {933,970,+1},{933,972,-1}
599 {"Arial", -34, 39, 32, 7,
600 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
603 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
604 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
605 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
606 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
607 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
608 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
609 {933,970,+2},{933,972,-3}
612 { "Arial", 120, 120, 97, 23,
613 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
616 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
617 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
618 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
619 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
620 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
621 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
622 {933,970,+6},{933,972,-10}
625 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
626 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
627 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
630 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
631 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
632 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
633 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
634 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
635 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
636 {933,970,+54},{933,972,-83}
642 HFONT hfont
, hfont_old
;
643 KERNINGPAIR
*kern_pair
;
645 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
649 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
650 * which may render this test unusable, so we're trying to avoid that.
652 SetLastError(0xdeadbeef);
653 GetKerningPairsW(hdc
, 0, NULL
);
654 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
656 skip("Skipping the GetKerningPairs test on a Win9x platform\n");
661 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
663 OUTLINETEXTMETRICW otm
;
665 if (!is_font_installed(kd
[i
].face_name
))
667 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
671 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
673 memset(&lf
, 0, sizeof(lf
));
674 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
675 lf
.lfHeight
= kd
[i
].height
;
676 hfont
= CreateFontIndirect(&lf
);
679 hfont_old
= SelectObject(hdc
, hfont
);
681 SetLastError(0xdeadbeef);
682 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
683 ok(GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
) == sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
685 ok(kd
[i
].tmHeight
== otm
.otmTextMetrics
.tmHeight
, "expected %d, got %d\n",
686 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
687 ok(kd
[i
].tmAscent
== otm
.otmTextMetrics
.tmAscent
, "expected %d, got %d\n",
688 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
689 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
690 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
692 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
693 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
694 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
695 kd
[i
].otmAscent
, otm
.otmAscent
);
696 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
697 kd
[i
].otmDescent
, otm
.otmDescent
);
698 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
699 kd
[i
].otmLineGap
, otm
.otmLineGap
);
701 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
702 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
703 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
704 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
705 ok(kd
[i
].otmMacAscent
== otm
.otmMacAscent
, "expected %d, got %d\n",
706 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
707 ok(kd
[i
].otmMacDescent
== otm
.otmMacDescent
, "expected %d, got %d\n",
708 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
709 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
710 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
711 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
712 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
713 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
716 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
717 trace("total_kern_pairs %u\n", total_kern_pairs
);
718 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
720 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
721 SetLastError(0xdeadbeef);
722 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
723 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
724 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
725 ok(ret
== 0, "got %lu, expected 0\n", ret
);
728 ret
= GetKerningPairsW(hdc
, 100, NULL
);
729 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
731 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
732 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
734 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
735 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
739 for (n
= 0; n
< ret
; n
++)
743 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
744 trace("{'%c','%c',%d},\n",
745 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
747 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
749 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
750 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
752 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
753 "pair %d:%d got %d, expected %d\n",
754 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
755 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
761 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
762 matches
, kd
[i
].total_kern_pairs
);
764 HeapFree(GetProcessHeap(), 0, kern_pair
);
766 SelectObject(hdc
, hfont_old
);
773 static void test_GetOutlineTextMetrics(void)
775 OUTLINETEXTMETRIC
*otm
;
777 HFONT hfont
, hfont_old
;
781 if (!is_font_installed("Arial"))
783 skip("Arial is not installed\n");
789 memset(&lf
, 0, sizeof(lf
));
790 strcpy(lf
.lfFaceName
, "Arial");
792 lf
.lfWeight
= FW_NORMAL
;
793 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
794 lf
.lfQuality
= PROOF_QUALITY
;
795 hfont
= CreateFontIndirect(&lf
);
798 hfont_old
= SelectObject(hdc
, hfont
);
799 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
800 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
802 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
804 memset(otm
, 0xAA, otm_size
);
805 SetLastError(0xdeadbeef);
806 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
807 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
808 ok(ret
== 1 /* Win9x */ ||
809 ret
== otm
->otmSize
/* XP*/,
810 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
811 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
813 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
814 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
815 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
816 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
819 memset(otm
, 0xAA, otm_size
);
820 SetLastError(0xdeadbeef);
821 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
822 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
823 ok(ret
== 1 /* Win9x */ ||
824 ret
== otm
->otmSize
/* XP*/,
825 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
826 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
828 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
829 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
830 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
831 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
834 /* ask about truncated data */
835 memset(otm
, 0xAA, otm_size
);
836 SetLastError(0xdeadbeef);
837 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
838 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
839 ok(ret
== 1 /* Win9x */ ||
840 ret
== otm
->otmSize
/* XP*/,
841 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
842 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
844 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
845 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
846 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
848 ok(otm
->otmpFullName
== (LPSTR
)0xAAAAAAAA, "expected 0xAAAAAAAA got %p\n", otm
->otmpFullName
);
850 HeapFree(GetProcessHeap(), 0, otm
);
852 SelectObject(hdc
, hfont_old
);
858 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
862 outputWidth
= 0, /* to test TabbedTextOut() */
863 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
864 areaWidth
= clientArea
->right
- clientArea
->left
,
866 BOOL lastExtent
= FALSE
;
867 PSTR pFirstChar
, pLastChar
;
873 int GetTextExtentExPointWWidth
;
874 int TabbedTextOutWidth
;
877 GetTextMetricsA(hdc
, &tm
);
881 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
887 /* if not at the end of the string, ... */
888 if (*str
== '\0') break;
889 /* ... add the next word to the current extent */
890 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
892 SetTextJustification(hdc
, 0, 0);
893 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
894 } while ((int) size
.cx
< areaWidth
);
896 /* ignore trailing break chars */
898 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
904 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
906 SetTextJustification(hdc
, 0, 0);
907 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
909 /* do not justify the last extent */
910 if (*str
!= '\0' && breakCount
> 0)
912 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
913 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
914 justifiedWidth
= size
.cx
;
916 else lastExtent
= TRUE
;
918 x
= clientArea
->left
;
920 outputWidth
= LOWORD(TabbedTextOut(
921 hdc
, x
, y
, pFirstChar
, pLastChar
- pFirstChar
,
923 /* catch errors and report them */
924 if (!lastExtent
&& ((outputWidth
!= areaWidth
) || (justifiedWidth
!= areaWidth
)))
926 memset(error
[nErrors
].extent
, 0, 100);
927 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
928 error
[nErrors
].TabbedTextOutWidth
= outputWidth
;
929 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
935 } while (*str
&& y
< clientArea
->bottom
);
937 for (e
= 0; e
< nErrors
; e
++)
939 ok(error
[e
].TabbedTextOutWidth
== areaWidth
,
940 "The output text (\"%s\") width should be %d, not %d.\n",
941 error
[e
].extent
, areaWidth
, error
[e
].TabbedTextOutWidth
);
942 /* The width returned by GetTextExtentPoint32() is exactly the same
943 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
944 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
945 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
946 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
950 static void test_SetTextJustification(void)
957 static char testText
[] =
958 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
959 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
960 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
961 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
962 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
963 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
964 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
966 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
967 GetClientRect( hwnd
, &clientArea
);
970 memset(&lf
, 0, sizeof lf
);
971 lf
.lfCharSet
= ANSI_CHARSET
;
972 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
973 lf
.lfWeight
= FW_DONTCARE
;
975 lf
.lfQuality
= DEFAULT_QUALITY
;
976 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
977 hfont
= create_font("Times New Roman", &lf
);
978 SelectObject(hdc
, hfont
);
980 testJustification(hdc
, testText
, &clientArea
);
983 ReleaseDC(hwnd
, hdc
);
987 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
991 HFONT hfont
, hfont_old
;
998 assert(count
<= 128);
1000 memset(&lf
, 0, sizeof(lf
));
1002 lf
.lfCharSet
= charset
;
1004 lstrcpyA(lf
.lfFaceName
, "Arial");
1005 SetLastError(0xdeadbeef);
1006 hfont
= CreateFontIndirectA(&lf
);
1007 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1010 hfont_old
= SelectObject(hdc
, hfont
);
1012 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1013 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1015 SetLastError(0xdeadbeef);
1016 ret
= GetTextFace(hdc
, sizeof(name
), name
);
1017 ok(ret
, "GetTextFace error %u\n", GetLastError());
1019 if (charset
== SYMBOL_CHARSET
)
1021 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1022 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1026 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1027 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1030 if (!TranslateCharsetInfo((DWORD
*)cs
, &csi
, TCI_SRCCHARSET
))
1032 trace("Can't find codepage for charset %d\n", cs
);
1036 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1041 WCHAR unicode_buf
[128];
1043 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1045 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1047 SetLastError(0xdeadbeef);
1048 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1049 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1055 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1057 SetLastError(0xdeadbeef);
1058 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1059 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1062 SelectObject(hdc
, hfont_old
);
1063 DeleteObject(hfont
);
1070 static void test_font_charset(void)
1072 static struct charset_data
1076 WORD font_idxA
[128], font_idxW
[128];
1079 { ANSI_CHARSET
, 1252 },
1080 { RUSSIAN_CHARSET
, 1251 },
1081 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1085 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1087 skip("Skipping the font charset test on a Win9x platform\n");
1091 if (!is_font_installed("Arial"))
1093 skip("Arial is not installed\n");
1097 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1099 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1101 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1103 skip("Symbol or Wingdings is not installed\n");
1107 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
);
1108 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
);
1109 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1112 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1115 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1116 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1119 skip("Symbol or Wingdings is not installed\n");
1122 static void test_GetFontUnicodeRanges(void)
1126 HFONT hfont
, hfont_old
;
1130 if (!pGetFontUnicodeRanges
)
1132 skip("GetFontUnicodeRanges not available before W2K\n");
1136 memset(&lf
, 0, sizeof(lf
));
1137 lstrcpyA(lf
.lfFaceName
, "Arial");
1138 hfont
= create_font("Arial", &lf
);
1141 hfont_old
= SelectObject(hdc
, hfont
);
1143 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1144 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1146 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1147 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1149 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1151 size
= pGetFontUnicodeRanges(hdc
, gs
);
1152 ok(size
, "GetFontUnicodeRanges failed\n");
1154 for (i
= 0; i
< gs
->cRanges
; i
++)
1155 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1157 trace("found %u ranges\n", gs
->cRanges
);
1159 HeapFree(GetProcessHeap(), 0, gs
);
1161 SelectObject(hdc
, hfont_old
);
1162 DeleteObject(hfont
);
1163 ReleaseDC(NULL
, hdc
);
1166 #define MAX_ENUM_FONTS 256
1168 struct enum_font_data
1171 LOGFONT lf
[MAX_ENUM_FONTS
];
1174 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1176 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1178 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1180 trace("enumed font \"%s\", charset %d, weight %d, italic %d\n",
1181 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfWeight
, lf
->lfItalic
);
1183 if (efd
->total
< MAX_ENUM_FONTS
)
1184 efd
->lf
[efd
->total
++] = *lf
;
1189 static void get_charset_stats(struct enum_font_data
*efd
,
1190 int *ansi_charset
, int *symbol_charset
,
1191 int *russian_charset
)
1196 *symbol_charset
= 0;
1197 *russian_charset
= 0;
1199 for (i
= 0; i
< efd
->total
; i
++)
1201 switch (efd
->lf
[i
].lfCharSet
)
1206 case SYMBOL_CHARSET
:
1207 (*symbol_charset
)++;
1209 case RUSSIAN_CHARSET
:
1210 (*russian_charset
)++;
1216 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1218 struct enum_font_data efd
;
1221 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1223 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1225 if (*font_name
&& !is_truetype_font_installed(font_name
))
1227 skip("%s is not installed\n", font_name
);
1233 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1234 * while EnumFontFamiliesEx doesn't.
1236 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1239 SetLastError(0xdeadbeef);
1240 ret
= EnumFontFamilies(hdc
, NULL
, arial_enum_proc
, (LPARAM
)&efd
);
1241 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1242 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1243 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1244 ansi_charset
, symbol_charset
, russian_charset
);
1245 ok(efd
.total
> 0, "no fonts enumerated: NULL\n");
1246 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1247 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1248 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1252 SetLastError(0xdeadbeef);
1253 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
1254 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1255 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1256 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1257 ansi_charset
, symbol_charset
, russian_charset
,
1258 *font_name
? font_name
: "<empty>");
1260 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1262 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
1263 for (i
= 0; i
< efd
.total
; i
++)
1265 /* FIXME: remove completely once Wine is fixed */
1266 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
1269 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1272 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1273 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1274 font_name
, efd
.lf
[i
].lfFaceName
);
1277 memset(&lf
, 0, sizeof(lf
));
1278 lf
.lfCharSet
= ANSI_CHARSET
;
1279 lstrcpy(lf
.lfFaceName
, font_name
);
1281 SetLastError(0xdeadbeef);
1282 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1283 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1284 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1285 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1286 ansi_charset
, symbol_charset
, russian_charset
,
1287 *font_name
? font_name
: "<empty>");
1288 if (font_charset
== SYMBOL_CHARSET
)
1291 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
1293 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1297 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
1298 for (i
= 0; i
< efd
.total
; i
++)
1300 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1302 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1303 font_name
, efd
.lf
[i
].lfFaceName
);
1307 /* DEFAULT_CHARSET should enumerate all available charsets */
1308 memset(&lf
, 0, sizeof(lf
));
1309 lf
.lfCharSet
= DEFAULT_CHARSET
;
1310 lstrcpy(lf
.lfFaceName
, font_name
);
1312 SetLastError(0xdeadbeef);
1313 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1314 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1315 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1316 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1317 ansi_charset
, symbol_charset
, russian_charset
,
1318 *font_name
? font_name
: "<empty>");
1319 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
1320 for (i
= 0; i
< efd
.total
; i
++)
1323 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1324 font_name
, efd
.lf
[i
].lfFaceName
);
1328 switch (font_charset
)
1331 ok(ansi_charset
> 0,
1332 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1334 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
1335 ok(russian_charset
> 0,
1336 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1338 case SYMBOL_CHARSET
:
1340 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
1342 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1343 ok(!russian_charset
,
1344 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1346 case DEFAULT_CHARSET
:
1347 ok(ansi_charset
> 0,
1348 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1349 ok(symbol_charset
> 0,
1350 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1351 ok(russian_charset
> 0,
1352 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1358 ok(ansi_charset
> 0,
1359 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1360 ok(symbol_charset
> 0,
1361 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1362 ok(russian_charset
> 0,
1363 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1366 memset(&lf
, 0, sizeof(lf
));
1367 lf
.lfCharSet
= SYMBOL_CHARSET
;
1368 lstrcpy(lf
.lfFaceName
, font_name
);
1370 SetLastError(0xdeadbeef);
1371 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1372 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1373 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1374 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1375 ansi_charset
, symbol_charset
, russian_charset
,
1376 *font_name
? font_name
: "<empty>");
1377 if (*font_name
&& font_charset
== ANSI_CHARSET
)
1378 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
1381 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
1382 for (i
= 0; i
< efd
.total
; i
++)
1384 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1386 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1387 font_name
, efd
.lf
[i
].lfFaceName
);
1391 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1392 ok(symbol_charset
> 0,
1393 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1394 ok(!russian_charset
,
1395 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1401 /* PANOSE is 10 bytes in size, need to pack the structure properly */
1402 #include "pshpack2.h"
1406 SHORT xAvgCharWidth
;
1407 USHORT usWeightClass
;
1408 USHORT usWidthClass
;
1410 SHORT ySubscriptXSize
;
1411 SHORT ySubscriptYSize
;
1412 SHORT ySubscriptXOffset
;
1413 SHORT ySubscriptYOffset
;
1414 SHORT ySuperscriptXSize
;
1415 SHORT ySuperscriptYSize
;
1416 SHORT ySuperscriptXOffset
;
1417 SHORT ySuperscriptYOffset
;
1418 SHORT yStrikeoutSize
;
1419 SHORT yStrikeoutPosition
;
1422 ULONG ulUnicodeRange1
;
1423 ULONG ulUnicodeRange2
;
1424 ULONG ulUnicodeRange3
;
1425 ULONG ulUnicodeRange4
;
1428 USHORT usFirstCharIndex
;
1429 USHORT usLastCharIndex
;
1430 /* According to the Apple spec, original version didn't have the below fields,
1431 * version numbers were taked from the OpenType spec.
1433 /* version 0 (TrueType 1.5) */
1434 USHORT sTypoAscender
;
1435 USHORT sTypoDescender
;
1436 USHORT sTypoLineGap
;
1438 USHORT usWinDescent
;
1439 /* version 1 (TrueType 1.66) */
1440 ULONG ulCodePageRange1
;
1441 ULONG ulCodePageRange2
;
1442 /* version 2 (OpenType 1.2) */
1445 USHORT usDefaultChar
;
1447 USHORT usMaxContext
;
1449 #include "poppack.h"
1451 #ifdef WORDS_BIGENDIAN
1452 #define GET_BE_WORD(x) (x)
1454 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
1457 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
1458 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
1459 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
1460 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
1462 static void test_text_metrics(const LOGFONTA
*lf
)
1465 HFONT hfont
, hfont_old
;
1468 UINT first_unicode_char
, last_unicode_char
, default_char
, break_char
;
1473 const char *font_name
= lf
->lfFaceName
;
1475 trace("Testing font metrics for %s, charset %d\n", font_name
, lf
->lfCharSet
);
1479 SetLastError(0xdeadbeef);
1480 hfont
= CreateFontIndirectA(lf
);
1481 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1483 hfont_old
= SelectObject(hdc
, hfont
);
1485 if(lf
->lfWidth
> 0) {
1486 HFONT hfont2
, hfont_prev
;
1487 GLYPHMETRICS gm1
, gm2
;
1489 MAT2 mat2
= { {0,1}, {0,0}, {0,0}, {0,1} };
1491 /* negative widths are handled just as positive ones */
1494 SetLastError(0xdeadbeef);
1495 hfont2
= CreateFontIndirectA(&lf2
);
1496 ok(hfont2
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1497 hfont_prev
= SelectObject(hdc
, hfont2
);
1499 memset(&gm1
, 0xaa, sizeof(gm1
));
1500 SetLastError(0xdeadbeef);
1501 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat2
);
1502 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1504 SelectObject(hdc
, hfont_prev
);
1505 DeleteObject(hfont2
);
1507 memset(&gm2
, 0xbb, sizeof(gm2
));
1508 SetLastError(0xdeadbeef);
1509 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat2
);
1510 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1512 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
1513 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
1514 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
1515 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
1516 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
1517 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
1518 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
1519 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
1520 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
1521 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
1522 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
1525 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
1526 if (size
== GDI_ERROR
)
1528 trace("OS/2 chunk was not found\n");
1531 if (size
> sizeof(tt_os2
))
1533 trace("got too large OS/2 chunk of size %u\n", size
);
1534 size
= sizeof(tt_os2
);
1537 memset(&tt_os2
, 0, sizeof(tt_os2
));
1538 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
1539 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
1541 version
= GET_BE_WORD(tt_os2
.version
);
1542 trace("OS/2 chunk version %u, vendor %4.4s\n", version
, (LPCSTR
)&tt_os2
.achVendID
);
1544 first_unicode_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
1545 last_unicode_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
1546 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
1547 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
1549 trace("for %s first %x, last %x, default %x, break %x\n", font_name
,
1550 first_unicode_char
, last_unicode_char
, default_char
, break_char
);
1552 SetLastError(0xdeadbeef);
1553 ret
= GetTextMetricsA(hdc
, &tmA
);
1554 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
1556 trace("A: first %x, last %x, default %x, break %x\n",
1557 tmA
.tmFirstChar
, tmA
.tmLastChar
, tmA
.tmDefaultChar
, tmA
.tmBreakChar
);
1559 SetLastError(0xdeadbeef);
1560 ret
= GetTextMetricsW(hdc
, &tmW
);
1561 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
1563 trace("W: first %x, last %x, default %x, break %x\n",
1564 tmW
.tmFirstChar
, tmW
.tmLastChar
, tmW
.tmDefaultChar
, tmW
.tmBreakChar
);
1566 if (lf
->lfCharSet
== SYMBOL_CHARSET
)
1568 test_char
= min(last_unicode_char
- 0xf000, 255);
1569 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
1570 font_name
, tmA
.tmLastChar
, test_char
);
1572 /* It appears that for fonts with SYMBOL_CHARSET Windows always sets
1573 * symbol range to 0 - f0ff
1575 ok(tmW
.tmFirstChar
== 0, "W: tmFirstChar for %s %02x != 0\n",
1576 font_name
, tmW
.tmFirstChar
);
1577 /* FIXME: Windows returns f0ff here, while Wine f0xx */
1578 ok(tmW
.tmLastChar
>= 0xf000, "W: tmLastChar for %s %02x != 0xf0ff\n",
1579 font_name
, tmW
.tmLastChar
);
1581 ok(tmA
.tmDefaultChar
== 0x1f, "A: tmDefaultChar for %s %02x != 0\n",
1582 font_name
, tmW
.tmDefaultChar
);
1583 ok(tmA
.tmBreakChar
== 0x20, "A: tmBreakChar for %s %02x != 0xf0ff\n",
1584 font_name
, tmW
.tmBreakChar
);
1585 ok(tmW
.tmDefaultChar
== 0x1f, "W: tmDefaultChar for %s %02x != 0\n",
1586 font_name
, tmW
.tmDefaultChar
);
1587 ok(tmW
.tmBreakChar
== 0x20, "W: tmBreakChar for %s %02x != 0xf0ff\n",
1588 font_name
, tmW
.tmBreakChar
);
1592 test_char
= min(tmW
.tmLastChar
, 255);
1593 ok(tmA
.tmLastChar
== test_char
, "A: tmLastChar for %s %02x != %02x\n",
1594 font_name
, tmA
.tmLastChar
, test_char
);
1596 ok(tmW
.tmFirstChar
== first_unicode_char
, "W: tmFirstChar for %s %02x != %02x\n",
1597 font_name
, tmW
.tmFirstChar
, first_unicode_char
);
1598 ok(tmW
.tmLastChar
== last_unicode_char
, "W: tmLastChar for %s %02x != %02x\n",
1599 font_name
, tmW
.tmLastChar
, last_unicode_char
);
1601 #if 0 /* FIXME: This doesn't appear to be what Windows does */
1602 test_char
= min(tmW
.tmFirstChar
- 1, 255);
1603 ok(tmA
.tmFirstChar
== test_char
, "A: tmFirstChar for %s %02x != %02x\n",
1604 font_name
, tmA
.tmFirstChar
, test_char
);
1606 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
1607 ok(tmW
.tmDigitizedAspectX
== ret
, "tmDigitizedAspectX %u != %u\n",
1608 tmW
.tmDigitizedAspectX
, ret
);
1609 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
1610 ok(tmW
.tmDigitizedAspectX
== ret
, "tmDigitizedAspectY %u != %u\n",
1611 tmW
.tmDigitizedAspectX
, ret
);
1614 SelectObject(hdc
, hfont_old
);
1615 DeleteObject(hfont
);
1620 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
1622 INT
*enumed
= (INT
*)lParam
;
1624 if (type
== TRUETYPE_FONTTYPE
)
1627 test_text_metrics(lf
);
1632 static void test_GetTextMetrics(void)
1638 SetLastError(0xdeadbeef);
1639 GetTextMetricsW(0, NULL
);
1640 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1642 skip("Skipping GetTextMetrics test on a Win9x platform\n");
1648 memset(&lf
, 0, sizeof(lf
));
1649 lf
.lfCharSet
= DEFAULT_CHARSET
;
1651 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
1652 trace("Tested metrics of %d truetype fonts\n", enumed
);
1663 test_bitmap_font_metrics();
1664 test_GdiGetCharDimensions();
1665 test_GetCharABCWidthsW();
1666 test_text_extents();
1667 test_GetGlyphIndices();
1668 test_GetKerningPairs();
1669 test_GetOutlineTextMetrics();
1670 test_SetTextJustification();
1671 test_font_charset();
1672 test_GetFontUnicodeRanges();
1673 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
1674 * I'd like to avoid them in this test.
1676 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
1677 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
1678 if (is_truetype_font_installed("Arial Black") &&
1679 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
1681 test_EnumFontFamilies("", ANSI_CHARSET
);
1682 test_EnumFontFamilies("", SYMBOL_CHARSET
);
1683 test_EnumFontFamilies("", DEFAULT_CHARSET
);
1686 skip("Arial Black or Symbol/Wingdings is not installed\n");
1687 test_GetTextMetrics();