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 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b, exact) (abs((a) - (b)) <= ((exact) ? 0 : 1))
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
40 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
41 static BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
42 static BOOL (WINAPI
*pGetCharABCWidthsA
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
43 static BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
44 static BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
45 static BOOL (WINAPI
*pGetCharWidth32A
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
46 static BOOL (WINAPI
*pGetCharWidth32W
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
47 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
48 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
49 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
50 static BOOL (WINAPI
*pGetTextExtentExPointI
)(HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
51 LPINT nfit
, LPINT dxs
, LPSIZE size
);
52 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
53 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDVA
*);
54 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
55 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
56 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
57 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
59 static HMODULE hgdi32
= 0;
60 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
61 static WORD system_lang_id
;
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
67 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
71 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
72 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
73 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
74 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
75 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
76 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
78 static void init(void)
80 hgdi32
= GetModuleHandleA("gdi32.dll");
82 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
83 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
84 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
85 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
86 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
87 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
88 pGetCharWidth32A
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32A");
89 pGetCharWidth32W
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32W");
90 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
91 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
92 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
93 pGetTextExtentExPointI
= (void *)GetProcAddress(hgdi32
, "GetTextExtentExPointI");
94 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
95 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
96 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
97 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
98 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
99 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
101 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
104 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
106 if (type
!= TRUETYPE_FONTTYPE
) return 1;
111 static BOOL
is_truetype_font_installed(const char *name
)
116 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
123 static INT CALLBACK
is_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
128 static BOOL
is_font_installed(const char *name
)
133 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
140 static void *get_res_data(const char *fontname
, DWORD
*rsrc_size
)
145 rsrc
= FindResourceA(GetModuleHandleA(NULL
), fontname
, (LPCSTR
)RT_RCDATA
);
146 if (!rsrc
) return NULL
;
148 rsrc_data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
149 if (!rsrc_data
) return NULL
;
151 *rsrc_size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
152 if (!*rsrc_size
) return NULL
;
157 static BOOL
write_tmp_file( const void *data
, DWORD
*size
, char *tmp_name
)
159 char tmp_path
[MAX_PATH
];
163 GetTempPathA(MAX_PATH
, tmp_path
);
164 GetTempFileNameA(tmp_path
, "ttf", 0, tmp_name
);
166 hfile
= CreateFileA(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
167 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
169 ret
= WriteFile(hfile
, data
, *size
, size
, NULL
);
175 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
180 rsrc_data
= get_res_data( fontname
, &rsrc_size
);
181 if (!rsrc_data
) return FALSE
;
183 return write_tmp_file( rsrc_data
, &rsrc_size
, tmp_name
);
186 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
194 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
195 /* NT4 tries to be clever and only returns the minimum length */
196 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
198 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
199 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
200 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
201 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
202 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
203 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
204 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
205 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
206 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
207 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
208 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
209 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
210 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
211 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
212 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
213 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
214 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
215 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
216 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
217 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
218 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
219 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
220 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
221 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
222 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
223 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
224 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
225 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
228 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
230 HFONT hfont
= CreateFontIndirectA(lf
);
231 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
233 check_font(test
, lf
, hfont
);
237 static void test_logfont(void)
242 memset(&lf
, 0, sizeof lf
);
244 lf
.lfCharSet
= ANSI_CHARSET
;
245 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
246 lf
.lfWeight
= FW_DONTCARE
;
249 lf
.lfQuality
= DEFAULT_QUALITY
;
251 lstrcpyA(lf
.lfFaceName
, "Arial");
252 hfont
= create_font("Arial", &lf
);
255 memset(&lf
, 'A', sizeof(lf
));
256 hfont
= CreateFontIndirectA(&lf
);
257 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
259 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
260 check_font("AAA...", &lf
, hfont
);
264 static INT CALLBACK
font_enum_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
266 if (type
& RASTER_FONTTYPE
)
268 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
270 return 0; /* stop enumeration */
273 return 1; /* continue enumeration */
276 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
278 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
279 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
280 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
281 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
282 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
283 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
284 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
285 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
286 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
287 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
288 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
289 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
290 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
291 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
292 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
293 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
294 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
295 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
296 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
297 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
300 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
301 LONG lfWidth
, const char *test_str
,
302 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
303 const SIZE
*size_orig
, INT width_of_A_orig
,
304 INT scale_x
, INT scale_y
)
307 OUTLINETEXTMETRICA otm
;
310 INT width_of_A
, cx
, cy
;
316 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
318 GetObjectA(hfont
, sizeof(lf
), &lf
);
320 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
322 otm
.otmSize
= sizeof(otm
) / 2;
323 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
324 ok(ret
== sizeof(otm
)/2 /* XP */ ||
325 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
327 memset(&otm
, 0x1, sizeof(otm
));
328 otm
.otmSize
= sizeof(otm
);
329 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
330 ok(ret
== sizeof(otm
) /* XP */ ||
331 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
333 memset(&tm
, 0x2, sizeof(tm
));
334 ret
= GetTextMetricsA(hdc
, &tm
);
335 ok(ret
, "GetTextMetricsA failed\n");
336 /* the structure size is aligned */
337 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
339 ok(0, "tm != otm\n");
340 compare_tm(&tm
, &otm
.otmTextMetrics
);
343 tm
= otm
.otmTextMetrics
;
344 if (0) /* these metrics are scaled too, but with rounding errors */
346 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
347 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
349 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
350 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
351 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
352 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
353 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
354 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
358 ret
= GetTextMetricsA(hdc
, &tm
);
359 ok(ret
, "GetTextMetricsA failed\n");
362 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
363 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
364 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
365 lfHeight
, scale_x
, scale_y
, cx
, cy
);
366 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
367 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
368 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
369 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
370 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
372 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
376 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
379 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
381 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
383 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
384 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
386 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
388 ok(near_match(width_of_A
, width_of_A_orig
* scale_x
), "width A %d != %d\n", width_of_A
, width_of_A_orig
* scale_x
);
391 /* Test how GDI scales bitmap font metrics */
392 static void test_bitmap_font(void)
394 static const char test_str
[11] = "Test String";
397 HFONT hfont
, old_hfont
;
400 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
402 hdc
= CreateCompatibleDC(0);
404 /* "System" has only 1 pixel size defined, otherwise the test breaks */
405 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
409 trace("no bitmap fonts were found, skipping the test\n");
413 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
415 height_orig
= bitmap_lf
.lfHeight
;
416 lfWidth
= bitmap_lf
.lfWidth
;
418 hfont
= create_font("bitmap", &bitmap_lf
);
419 old_hfont
= SelectObject(hdc
, hfont
);
420 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
421 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
422 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
423 SelectObject(hdc
, old_hfont
);
426 bitmap_lf
.lfHeight
= 0;
427 bitmap_lf
.lfWidth
= 4;
428 hfont
= create_font("bitmap", &bitmap_lf
);
429 old_hfont
= SelectObject(hdc
, hfont
);
430 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
431 SelectObject(hdc
, old_hfont
);
434 bitmap_lf
.lfHeight
= height_orig
;
435 bitmap_lf
.lfWidth
= lfWidth
;
437 /* test fractional scaling */
438 for (i
= 1; i
<= height_orig
* 6; i
++)
442 bitmap_lf
.lfHeight
= i
;
443 hfont
= create_font("fractional", &bitmap_lf
);
444 scale
= (i
+ height_orig
- 1) / height_orig
;
445 nearest_height
= scale
* height_orig
;
446 /* Only jump to the next height if the difference <= 25% original height */
447 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
448 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
449 so we'll not test this particular height. */
450 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
451 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
452 old_hfont
= SelectObject(hdc
, hfont
);
453 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
454 SelectObject(hdc
, old_hfont
);
458 /* test integer scaling 3x2 */
459 bitmap_lf
.lfHeight
= height_orig
* 2;
460 bitmap_lf
.lfWidth
*= 3;
461 hfont
= create_font("3x2", &bitmap_lf
);
462 old_hfont
= SelectObject(hdc
, hfont
);
463 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
464 SelectObject(hdc
, old_hfont
);
467 /* test integer scaling 3x3 */
468 bitmap_lf
.lfHeight
= height_orig
* 3;
469 bitmap_lf
.lfWidth
= 0;
470 hfont
= create_font("3x3", &bitmap_lf
);
471 old_hfont
= SelectObject(hdc
, hfont
);
472 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
473 SelectObject(hdc
, old_hfont
);
479 /* Test how GDI scales outline font metrics */
480 static void test_outline_font(void)
482 static const char test_str
[11] = "Test String";
485 HFONT hfont
, old_hfont
, old_hfont_2
;
486 OUTLINETEXTMETRICA otm
;
488 INT width_orig
, height_orig
, lfWidth
;
491 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
495 if (!is_truetype_font_installed("Arial"))
497 skip("Arial is not installed\n");
501 hdc
= CreateCompatibleDC(0);
503 memset(&lf
, 0, sizeof(lf
));
504 strcpy(lf
.lfFaceName
, "Arial");
506 hfont
= create_font("outline", &lf
);
507 old_hfont
= SelectObject(hdc
, hfont
);
508 otm
.otmSize
= sizeof(otm
);
509 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
510 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
511 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
513 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
514 SelectObject(hdc
, old_hfont
);
517 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
518 lf
.lfHeight
= otm
.otmEMSquare
;
519 lf
.lfHeight
= -lf
.lfHeight
;
520 hfont
= create_font("outline", &lf
);
521 old_hfont
= SelectObject(hdc
, hfont
);
522 otm
.otmSize
= sizeof(otm
);
523 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
524 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
525 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
526 SelectObject(hdc
, old_hfont
);
529 height_orig
= otm
.otmTextMetrics
.tmHeight
;
530 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
532 /* test integer scaling 3x2 */
533 lf
.lfHeight
= height_orig
* 2;
534 lf
.lfWidth
= lfWidth
* 3;
535 hfont
= create_font("3x2", &lf
);
536 old_hfont
= SelectObject(hdc
, hfont
);
537 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
538 SelectObject(hdc
, old_hfont
);
541 /* test integer scaling 3x3 */
542 lf
.lfHeight
= height_orig
* 3;
543 lf
.lfWidth
= lfWidth
* 3;
544 hfont
= create_font("3x3", &lf
);
545 old_hfont
= SelectObject(hdc
, hfont
);
546 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
547 SelectObject(hdc
, old_hfont
);
550 /* test integer scaling 1x1 */
551 lf
.lfHeight
= height_orig
* 1;
552 lf
.lfWidth
= lfWidth
* 1;
553 hfont
= create_font("1x1", &lf
);
554 old_hfont
= SelectObject(hdc
, hfont
);
555 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
556 SelectObject(hdc
, old_hfont
);
559 /* test integer scaling 1x1 */
560 lf
.lfHeight
= height_orig
;
562 hfont
= create_font("1x1", &lf
);
563 old_hfont
= SelectObject(hdc
, hfont
);
564 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
566 /* with an identity matrix */
567 memset(&gm
, 0, sizeof(gm
));
568 SetLastError(0xdeadbeef);
569 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
570 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
571 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
572 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
573 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
574 /* with a custom matrix */
575 memset(&gm
, 0, sizeof(gm
));
576 SetLastError(0xdeadbeef);
577 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
578 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
580 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
581 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
587 hdc_2
= CreateCompatibleDC(0);
588 old_hfont_2
= SelectObject(hdc_2
, hfont
);
589 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
591 SetMapMode(hdc
, MM_ANISOTROPIC
);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc
, 100, 100, NULL
);
601 SetViewportExtEx(hdc
, 50, 100, NULL
);
602 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc
, 100, 200, NULL
);
611 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc
, MM_TEXT
);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
621 SelectObject(hdc_2
, old_hfont_2
);
624 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
626 SelectObject(hdc
, old_hfont
);
629 skip("GM_ADVANCED is not supported on this platform\n");
640 SetLastError(0xdeadbeef);
641 ret
= SetWorldTransform(hdc
, &xform
);
642 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
646 /* with an identity matrix */
647 memset(&gm
, 0, sizeof(gm
));
648 SetLastError(0xdeadbeef);
649 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
650 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
651 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
652 pt
.x
= width_orig
; pt
.y
= 0;
654 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
655 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
656 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
657 /* with a custom matrix */
658 memset(&gm
, 0, sizeof(gm
));
659 SetLastError(0xdeadbeef);
660 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
661 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
662 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
663 pt
.x
= width_orig
; pt
.y
= 0;
665 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
666 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
667 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
669 SetLastError(0xdeadbeef);
670 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
671 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
673 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
675 /* with an identity matrix */
676 memset(&gm
, 0, sizeof(gm
));
677 SetLastError(0xdeadbeef);
678 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
679 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
680 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
681 pt
.x
= width_orig
; pt
.y
= 0;
683 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
684 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
685 /* with a custom matrix */
686 memset(&gm
, 0, sizeof(gm
));
687 SetLastError(0xdeadbeef);
688 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
689 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
690 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
691 pt
.x
= width_orig
; pt
.y
= 0;
693 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
694 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
696 SetLastError(0xdeadbeef);
697 ret
= SetMapMode(hdc
, MM_TEXT
);
698 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
700 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
702 /* with an identity matrix */
703 memset(&gm
, 0, sizeof(gm
));
704 SetLastError(0xdeadbeef);
705 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
706 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
708 pt
.x
= width_orig
; pt
.y
= 0;
710 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
711 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
712 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
713 /* with a custom matrix */
714 memset(&gm
, 0, sizeof(gm
));
715 SetLastError(0xdeadbeef);
716 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
717 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
718 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
719 pt
.x
= width_orig
; pt
.y
= 0;
721 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
722 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
723 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
725 SelectObject(hdc
, old_hfont
);
730 static INT CALLBACK
find_font_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
732 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
734 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL
is_CJK(void)
744 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const struct font_data
752 const char face_name
[LF_FACESIZE
];
753 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
754 int ave_char_width
, max_char_width
, dpi
;
755 BYTE first_char
, last_char
, def_char
, break_char
;
761 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
762 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
763 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
764 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
765 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
766 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
767 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
768 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
769 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 16 },
770 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
772 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
773 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
774 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
775 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
776 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
777 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
778 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
779 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
780 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
781 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
783 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
784 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
785 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
786 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
787 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
788 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
789 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
790 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
791 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
792 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
793 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
794 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
795 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
796 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
797 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
798 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
800 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
801 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
802 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
803 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
804 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
805 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
806 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
807 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
808 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
809 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
810 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
811 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
813 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
814 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
815 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
816 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
817 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
818 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
819 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
820 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
821 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
822 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
823 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
824 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
825 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
826 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
827 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
828 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
829 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
831 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
832 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
833 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
834 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
835 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
836 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
837 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
838 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
839 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
840 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
841 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
843 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
844 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
845 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
847 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
848 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
849 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
851 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
852 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
853 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
855 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
856 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
858 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
859 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
860 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
861 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
862 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
863 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
864 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
865 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
866 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
867 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
868 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
869 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
870 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
871 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
872 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
873 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
874 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
875 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
876 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
877 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
878 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
880 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
881 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
882 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
883 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
884 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
885 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
886 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
887 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
888 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
889 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
890 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
891 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
893 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
894 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
895 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
897 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
899 /* FIXME: add "Terminal" */
901 static const int font_log_pixels
[] = { 96, 120 };
904 HFONT hfont
, old_hfont
;
906 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
907 char face_name
[LF_FACESIZE
];
910 trace("system language id %04x\n", system_lang_id
);
912 expected_cs
= GetACP();
913 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
915 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
918 expected_cs
= csi
.ciCharset
;
919 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
921 hdc
= CreateCompatibleDC(0);
924 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
925 GetDeviceCaps(hdc
, LOGPIXELSY
));
927 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
930 for (i
= 0; i
< sizeof(font_log_pixels
)/sizeof(font_log_pixels
[0]); i
++)
932 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
936 font_res
= font_log_pixels
[i
];
939 trace("best font resolution is %d\n", font_res
);
941 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
945 memset(&lf
, 0, sizeof(lf
));
947 height
= fd
[i
].height
& ~FH_SCALE
;
948 lf
.lfHeight
= height
;
949 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
951 for(bit
= 0; bit
< 32; bit
++)
959 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
960 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
962 lf
.lfCharSet
= csi
.ciCharset
;
963 trace("looking for %s height %d charset %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
964 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
965 if (fd
[i
].height
& FH_SCALE
)
966 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
969 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
971 if (ret
) /* FIXME: Remove once Wine is fixed */
972 todo_wine
ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
974 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
977 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
980 hfont
= create_font(lf
.lfFaceName
, &lf
);
981 old_hfont
= SelectObject(hdc
, hfont
);
983 SetLastError(0xdeadbeef);
984 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
985 ok(ret
, "GetTextFace error %u\n", GetLastError());
987 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
989 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
990 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
991 trace("Skipping replacement %s height %d charset %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
);
992 SelectObject(hdc
, old_hfont
);
997 memset(&gm
, 0, sizeof(gm
));
998 SetLastError(0xdeadbeef);
999 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1001 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
1002 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1005 bRet
= GetTextMetricsA(hdc
, &tm
);
1006 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
1008 SetLastError(0xdeadbeef);
1009 ret
= GetTextCharset(hdc
);
1010 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1011 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1013 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1015 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
1016 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
1018 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1020 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1021 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
1023 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1024 if (fd
[i
].height
& FH_SCALE
)
1025 ok(tm
.tmHeight
== fd
[i
].scaled_height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmHeight
, fd
[i
].scaled_height
);
1027 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
);
1028 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1029 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1030 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1031 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1032 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
1033 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1034 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1035 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1036 make default char test fail */
1037 if (tm
.tmCharSet
== lf
.lfCharSet
)
1038 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1039 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1040 ok(tm
.tmCharSet
== expected_cs
|| tm
.tmCharSet
== ANSI_CHARSET
, "%s(%d): tm.tmCharSet %d != %d\n", fd
[i
].face_name
, height
, tm
.tmCharSet
, expected_cs
);
1042 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1043 that make the max width bigger */
1044 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1045 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
1048 skip("Skipping font metrics test for system langid 0x%x\n",
1051 SelectObject(hdc
, old_hfont
);
1052 DeleteObject(hfont
);
1059 static void test_GdiGetCharDimensions(void)
1065 LONG avgwidth
, height
;
1066 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1068 if (!pGdiGetCharDimensions
)
1070 win_skip("GdiGetCharDimensions not available on this platform\n");
1074 hdc
= CreateCompatibleDC(NULL
);
1076 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1077 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1079 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1080 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1081 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1083 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1084 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1086 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1087 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1090 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1091 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1092 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1097 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1098 const TEXTMETRICA
*lpntme
,
1099 DWORD FontType
, LPARAM lParam
)
1101 if (FontType
& TRUETYPE_FONTTYPE
)
1105 hfont
= CreateFontIndirectA(lpelfe
);
1108 *(HFONT
*)lParam
= hfont
;
1116 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, ABC
*base_abci
, ABC
*base_abcw
, ABCFLOAT
*base_abcf
, INT todo
)
1122 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1123 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1124 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1125 if (todo
) todo_wine
ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1126 else ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1127 if (todo
) todo_wine
ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1128 else ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1130 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1131 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1132 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1133 if (todo
) todo_wine
ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1134 else ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1135 if (todo
) todo_wine
ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1136 else ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's should be unchanged\n", description
);
1138 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1139 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1140 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1141 if (todo
) todo_wine
ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1142 else ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's should be unchanged\n", description
);
1143 if (todo
) todo_wine
ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1144 else ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1147 static void test_GetCharABCWidths(void)
1149 static const WCHAR str
[] = {'i',0};
1173 {0xffffff, 0xffffff},
1174 {0x1000000, 0x1000000},
1175 {0xffffff, 0x1000000},
1176 {0xffffffff, 0xffffffff},
1184 BOOL r
[sizeof range
/ sizeof range
[0]];
1187 {ANSI_CHARSET
, 0x30, 0x30,
1188 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1189 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1190 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1191 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1192 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1193 {GB2312_CHARSET
, 0x8141, 0x4e04,
1194 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1195 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1196 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1200 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1202 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1206 memset(&lf
, 0, sizeof(lf
));
1207 strcpy(lf
.lfFaceName
, "System");
1210 hfont
= CreateFontIndirectA(&lf
);
1212 hfont
= SelectObject(hdc
, hfont
);
1214 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1215 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1217 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1218 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1220 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1221 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1223 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1224 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1226 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1227 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1229 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1230 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1232 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1233 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1235 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1236 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1238 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1239 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1241 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1242 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1244 hfont
= SelectObject(hdc
, hfont
);
1245 DeleteObject(hfont
);
1247 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1251 UINT code
= 0x41, j
;
1253 lf
.lfFaceName
[0] = '\0';
1254 lf
.lfCharSet
= c
[i
].cs
;
1255 lf
.lfPitchAndFamily
= 0;
1256 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1258 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1262 memset(a
, 0, sizeof a
);
1263 memset(w
, 0, sizeof w
);
1264 hfont
= SelectObject(hdc
, hfont
);
1265 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1266 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1267 memcmp(a
, w
, sizeof a
) == 0,
1268 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1270 memset(a
, 0xbb, sizeof a
);
1271 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1272 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1273 memset(full
, 0xcc, sizeof full
);
1274 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1275 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1276 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1277 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1279 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1281 memset(full
, 0xdd, sizeof full
);
1282 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1283 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1284 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1287 UINT last
= range
[j
].last
- range
[j
].first
;
1288 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1289 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1290 "GetCharABCWidthsA %x should match. codepage = %u\n",
1291 range
[j
].last
, c
[i
].cs
);
1295 hfont
= SelectObject(hdc
, hfont
);
1296 DeleteObject(hfont
);
1299 memset(&lf
, 0, sizeof(lf
));
1300 strcpy(lf
.lfFaceName
, "Tahoma");
1302 hfont
= CreateFontIndirectA(&lf
);
1304 /* test empty glyph's metrics */
1305 hfont
= SelectObject(hdc
, hfont
);
1306 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1307 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1308 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1309 ret
= pGetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1310 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1311 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1313 /* 1) prepare unrotated font metrics */
1314 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1315 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1316 DeleteObject(SelectObject(hdc
, hfont
));
1318 /* 2) get rotated font metrics */
1319 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1320 hfont
= CreateFontIndirectA(&lf
);
1321 hfont
= SelectObject(hdc
, hfont
);
1322 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1323 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1325 /* 3) compare ABC results */
1326 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1327 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1328 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1329 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1330 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1331 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1333 DeleteObject(SelectObject(hdc
, hfont
));
1334 ReleaseDC(NULL
, hdc
);
1336 trace("ABC sign test for a variety of transforms:\n");
1337 memset(&lf
, 0, sizeof(lf
));
1338 strcpy(lf
.lfFaceName
, "Tahoma");
1340 hfont
= CreateFontIndirectA(&lf
);
1341 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1344 SetMapMode(hdc
, MM_ANISOTROPIC
);
1345 SelectObject(hdc
, hfont
);
1347 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1348 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1350 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1351 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1352 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1353 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1354 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1355 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1357 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1358 SetWindowExtEx(hdc
, -1, -1, NULL
);
1359 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1360 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1361 SetGraphicsMode(hdc
, GM_ADVANCED
);
1362 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1363 SetWindowExtEx(hdc
, 1, 1, NULL
);
1364 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1365 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1366 SetGraphicsMode(hdc
, GM_ADVANCED
);
1367 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1369 ReleaseDC(hwnd
, hdc
);
1370 DestroyWindow(hwnd
);
1372 trace("RTL layout\n");
1373 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1376 SetMapMode(hdc
, MM_ANISOTROPIC
);
1377 SelectObject(hdc
, hfont
);
1379 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1380 SetWindowExtEx(hdc
, -1, -1, NULL
);
1381 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1382 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1383 SetGraphicsMode(hdc
, GM_ADVANCED
);
1384 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1385 SetWindowExtEx(hdc
, 1, 1, NULL
);
1386 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1387 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1388 SetGraphicsMode(hdc
, GM_ADVANCED
);
1389 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1391 ReleaseDC(hwnd
, hdc
);
1392 DestroyWindow(hwnd
);
1393 DeleteObject(hfont
);
1396 static void test_text_extents(void)
1398 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1400 INT i
, len
, fit1
, fit2
, extents2
[3];
1409 memset(&lf
, 0, sizeof(lf
));
1410 strcpy(lf
.lfFaceName
, "Arial");
1413 hfont
= CreateFontIndirectA(&lf
);
1415 hfont
= SelectObject(hdc
, hfont
);
1416 GetTextMetricsA(hdc
, &tm
);
1417 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1418 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1420 SetLastError(0xdeadbeef);
1421 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1422 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1424 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1425 hfont
= SelectObject(hdc
, hfont
);
1426 DeleteObject(hfont
);
1432 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1433 extents
[0] = 1; /* So that the increasing sequence test will fail
1434 if the extents array is untouched. */
1435 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1436 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1437 ok(sz1
.cy
== sz2
.cy
,
1438 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1439 /* Because of the '\n' in the string GetTextExtentExPoint and
1440 GetTextExtentPoint return different widths under Win2k, but
1441 under WinXP they return the same width. So we don't test that
1444 for (i
= 1; i
< len
; ++i
)
1445 ok(extents
[i
-1] <= extents
[i
],
1446 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1448 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1449 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1450 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1451 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1452 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1453 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1455 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1456 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1457 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1458 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1459 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1460 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1461 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1463 /* extents functions fail with -ve counts (the interesting case being -1) */
1464 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1465 ok(ret
== FALSE
, "got %d\n", ret
);
1466 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1467 ok(ret
== FALSE
, "got %d\n", ret
);
1468 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1469 ok(ret
== FALSE
, "got %d\n", ret
);
1471 /* max_extent = 0 succeeds and returns zero */
1473 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1475 broken(ret
== FALSE
), /* NT4, 2k */
1478 broken(fit1
== -215), /* NT4, 2k */
1479 "fit = %d\n", fit1
);
1480 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1481 ok(ret
== TRUE
, "got %d\n", ret
);
1482 ok(fit2
== 0, "fit = %d\n", fit2
);
1484 /* max_extent = -1 is interpreted as a very large width that will
1485 * definitely fit our three characters */
1487 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1488 ok(ret
== TRUE
, "got %d\n", ret
);
1489 ok(fit1
== 3, "fit = %d\n", fit1
);
1490 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1491 ok(ret
== TRUE
, "got %d\n", ret
);
1492 ok(fit2
== 3, "fit = %d\n", fit2
);
1494 /* max_extent = -2 is interpreted similarly, but the Ansi version
1495 * rejects it while the Unicode one accepts it */
1497 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1498 ok(ret
== FALSE
, "got %d\n", ret
);
1499 ok(fit1
== -215, "fit = %d\n", fit1
);
1500 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1501 ok(ret
== TRUE
, "got %d\n", ret
);
1502 ok(fit2
== 3, "fit = %d\n", fit2
);
1504 hfont
= SelectObject(hdc
, hfont
);
1505 DeleteObject(hfont
);
1507 /* non-MM_TEXT mapping mode */
1509 hfont
= CreateFontIndirectA(&lf
);
1510 hfont
= SelectObject(hdc
, hfont
);
1512 SetMapMode( hdc
, MM_HIMETRIC
);
1513 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1514 ok(ret
, "got %d\n", ret
);
1515 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1517 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1518 ok(ret
, "got %d\n", ret
);
1519 ok(fit1
== 2, "got %d\n", fit1
);
1520 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1521 for(i
= 0; i
< 2; i
++)
1522 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1524 hfont
= SelectObject(hdc
, hfont
);
1525 DeleteObject(hfont
);
1526 HeapFree(GetProcessHeap(), 0, extents
);
1527 ReleaseDC(NULL
, hdc
);
1530 static void test_GetGlyphIndices(void)
1537 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1538 WORD glyphs
[(sizeof(testtext
)/2)-1];
1542 if (!pGetGlyphIndicesW
) {
1543 win_skip("GetGlyphIndicesW not available on platform\n");
1549 memset(&lf
, 0, sizeof(lf
));
1550 strcpy(lf
.lfFaceName
, "System");
1552 lf
.lfCharSet
= ANSI_CHARSET
;
1554 hfont
= CreateFontIndirectA(&lf
);
1555 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1556 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1557 if (textm
.tmCharSet
== ANSI_CHARSET
)
1559 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1560 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1561 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1562 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1564 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1565 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1566 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1567 textm
.tmDefaultChar
, glyphs
[4]);
1570 /* FIXME: Write tests for non-ANSI charsets. */
1571 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1573 if(!is_font_installed("Tahoma"))
1575 skip("Tahoma is not installed so skipping this test\n");
1578 memset(&lf
, 0, sizeof(lf
));
1579 strcpy(lf
.lfFaceName
, "Tahoma");
1582 hfont
= CreateFontIndirectA(&lf
);
1583 hOldFont
= SelectObject(hdc
, hfont
);
1584 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1585 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1586 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1587 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1588 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1590 testtext
[0] = textm
.tmDefaultChar
;
1591 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1592 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1593 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1594 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1595 DeleteObject(SelectObject(hdc
, hOldFont
));
1598 static void test_GetKerningPairs(void)
1600 static const struct kerning_data
1602 const char face_name
[LF_FACESIZE
];
1604 /* some interesting fields from OUTLINETEXTMETRIC */
1605 LONG tmHeight
, tmAscent
, tmDescent
;
1610 UINT otmsCapEmHeight
;
1615 UINT otmusMinimumPPEM
;
1616 /* small subset of kerning pairs to test */
1617 DWORD total_kern_pairs
;
1618 const KERNINGPAIR kern_pair
[26];
1621 {"Arial", 12, 12, 9, 3,
1622 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1625 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1626 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1627 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1628 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1629 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1630 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1631 {933,970,+1},{933,972,-1}
1634 {"Arial", -34, 39, 32, 7,
1635 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1638 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1639 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1640 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1641 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1642 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1643 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1644 {933,970,+2},{933,972,-3}
1647 { "Arial", 120, 120, 97, 23,
1648 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1651 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1652 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1653 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1654 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1655 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1656 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1657 {933,970,+6},{933,972,-10}
1660 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1661 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1662 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1665 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1666 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1667 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1668 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1669 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1670 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1671 {933,970,+54},{933,972,-83}
1677 HFONT hfont
, hfont_old
;
1678 KERNINGPAIR
*kern_pair
;
1680 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1684 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1685 * which may render this test unusable, so we're trying to avoid that.
1687 SetLastError(0xdeadbeef);
1688 GetKerningPairsW(hdc
, 0, NULL
);
1689 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1691 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1696 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1698 OUTLINETEXTMETRICW otm
;
1701 if (!is_font_installed(kd
[i
].face_name
))
1703 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1707 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1709 memset(&lf
, 0, sizeof(lf
));
1710 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1711 lf
.lfHeight
= kd
[i
].height
;
1712 hfont
= CreateFontIndirectA(&lf
);
1715 hfont_old
= SelectObject(hdc
, hfont
);
1717 SetLastError(0xdeadbeef);
1718 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1719 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1720 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1722 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1723 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1724 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1725 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1726 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1727 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1729 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1730 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1731 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1732 kd
[i
].otmAscent
, otm
.otmAscent
);
1733 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1734 kd
[i
].otmDescent
, otm
.otmDescent
);
1735 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1736 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1737 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1738 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1739 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1740 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1742 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1743 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1744 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1745 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1746 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1747 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1748 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1749 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1750 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1753 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1754 trace("total_kern_pairs %u\n", total_kern_pairs
);
1755 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1757 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1760 SetLastError(0xdeadbeef);
1761 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1762 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1763 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1764 ok(ret
== 0, "got %u, expected 0\n", ret
);
1766 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1767 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1769 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1770 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1772 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1773 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1777 for (n
= 0; n
< ret
; n
++)
1780 /* Disabled to limit console spam */
1781 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1782 trace("{'%c','%c',%d},\n",
1783 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1784 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1786 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1787 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1789 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1790 "pair %d:%d got %d, expected %d\n",
1791 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1792 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1798 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1799 matches
, kd
[i
].total_kern_pairs
);
1801 HeapFree(GetProcessHeap(), 0, kern_pair
);
1803 SelectObject(hdc
, hfont_old
);
1804 DeleteObject(hfont
);
1812 const char face_name
[LF_FACESIZE
];
1813 int requested_height
;
1814 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1818 static void test_height( HDC hdc
, const struct font_data
*fd
)
1821 HFONT hfont
, old_hfont
;
1825 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1827 if (!is_truetype_font_installed(fd
[i
].face_name
))
1829 skip("%s is not installed\n", fd
[i
].face_name
);
1833 memset(&lf
, 0, sizeof(lf
));
1834 lf
.lfHeight
= fd
[i
].requested_height
;
1835 lf
.lfWeight
= fd
[i
].weight
;
1836 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1838 hfont
= CreateFontIndirectA(&lf
);
1841 old_hfont
= SelectObject(hdc
, hfont
);
1842 ret
= GetTextMetricsA(hdc
, &tm
);
1843 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1844 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1846 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1847 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmWeight
, fd
[i
].weight
);
1848 ok(match_off_by_1(tm
.tmHeight
, fd
[i
].height
, fd
[i
].exact
), "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmHeight
, fd
[i
].height
);
1849 ok(match_off_by_1(tm
.tmAscent
, fd
[i
].ascent
, fd
[i
].exact
), "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmAscent
, fd
[i
].ascent
);
1850 ok(match_off_by_1(tm
.tmDescent
, fd
[i
].descent
, fd
[i
].exact
), "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmDescent
, fd
[i
].descent
);
1851 ok(match_off_by_1(tm
.tmInternalLeading
, fd
[i
].int_leading
, fd
[i
].exact
), "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1852 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1855 SelectObject(hdc
, old_hfont
);
1856 DeleteObject(hfont
);
1860 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1862 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1863 DWORD
*table
= (DWORD
*)ttf
+ 3;
1865 for (i
= 0; i
< num_tables
; i
++)
1867 if (table
[0] == tag
)
1868 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
1874 static void test_height_selection_vdmx( HDC hdc
)
1876 static const struct font_data charset_0
[] = /* doesn't use VDMX */
1878 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1879 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1880 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1881 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1882 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1883 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
1884 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1885 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1886 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1887 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1888 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
1889 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1890 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1891 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1892 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1893 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1894 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
1895 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1896 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1897 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1898 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1899 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1900 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
1901 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
1902 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
1903 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
1904 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1905 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1906 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1907 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1908 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1909 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1910 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1911 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1912 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1913 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1914 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1915 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1916 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1917 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1918 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1919 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1920 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1921 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
1922 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
1923 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
1924 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
1925 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
1926 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
1927 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
1928 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
1929 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
1930 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1933 static const struct font_data charset_1
[] = /* Uses VDMX */
1935 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1936 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1937 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1938 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1939 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1940 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1941 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1942 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1943 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1944 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1945 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1946 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1947 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1948 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1949 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1950 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1951 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1952 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1953 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1954 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1955 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1956 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1957 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1958 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
1959 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
1960 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
1961 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1962 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1963 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1964 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1965 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1966 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1967 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1968 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1969 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1970 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1971 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1972 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1973 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1974 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1975 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1976 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
1977 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
1978 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
1979 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
1980 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
1981 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
1982 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
1983 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
1984 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
1985 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
1986 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
1987 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1990 static const struct vdmx_data
1994 const struct font_data
*fd
;
1997 { 0, 0, charset_0
},
1998 { 0, 1, charset_1
},
1999 { 1, 0, charset_0
},
2006 char ttf_name
[MAX_PATH
];
2009 if (!pAddFontResourceExA
)
2011 win_skip("AddFontResourceExA unavailable\n");
2015 for (i
= 0; i
< sizeof(data
) / sizeof(data
[0]); i
++)
2017 res
= get_res_data( "wine_vdmx.ttf", &size
);
2019 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2020 memcpy( copy
, res
, size
);
2021 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2022 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2023 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2024 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2025 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2026 ratio_rec
[0] = data
[i
].bCharSet
;
2028 write_tmp_file( copy
, &size
, ttf_name
);
2029 HeapFree( GetProcessHeap(), 0, copy
);
2031 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2032 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2033 if (!num
) win_skip("Unable to add ttf font resource\n");
2036 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2037 test_height( hdc
, data
[i
].fd
);
2038 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2040 DeleteFileA( ttf_name
);
2044 static void test_height_selection(void)
2046 static const struct font_data tahoma
[] =
2048 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2049 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2050 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2051 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2052 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2053 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2054 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2055 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2056 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2057 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2058 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2060 HDC hdc
= CreateCompatibleDC(0);
2063 test_height( hdc
, tahoma
);
2064 test_height_selection_vdmx( hdc
);
2069 static void test_GetOutlineTextMetrics(void)
2071 OUTLINETEXTMETRICA
*otm
;
2073 HFONT hfont
, hfont_old
;
2075 DWORD ret
, otm_size
;
2078 if (!is_font_installed("Arial"))
2080 skip("Arial is not installed\n");
2086 memset(&lf
, 0, sizeof(lf
));
2087 strcpy(lf
.lfFaceName
, "Arial");
2089 lf
.lfWeight
= FW_NORMAL
;
2090 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2091 lf
.lfQuality
= PROOF_QUALITY
;
2092 hfont
= CreateFontIndirectA(&lf
);
2095 hfont_old
= SelectObject(hdc
, hfont
);
2096 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2097 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
2099 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2101 memset(otm
, 0xAA, otm_size
);
2102 SetLastError(0xdeadbeef);
2103 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2104 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2105 ok(ret
== 1 /* Win9x */ ||
2106 ret
== otm
->otmSize
/* XP*/,
2107 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2108 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2110 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2111 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2112 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2113 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2116 memset(otm
, 0xAA, otm_size
);
2117 SetLastError(0xdeadbeef);
2118 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2119 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2120 ok(ret
== 1 /* Win9x */ ||
2121 ret
== otm
->otmSize
/* XP*/,
2122 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2123 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2125 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2126 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2127 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2128 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2131 /* ask about truncated data */
2132 memset(otm
, 0xAA, otm_size
);
2133 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2134 SetLastError(0xdeadbeef);
2135 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2136 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2137 ok(ret
== 1 /* Win9x */ ||
2138 ret
== otm
->otmSize
/* XP*/,
2139 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2140 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2142 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2143 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2144 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2146 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2148 HeapFree(GetProcessHeap(), 0, otm
);
2150 SelectObject(hdc
, hfont_old
);
2151 DeleteObject(hfont
);
2156 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2160 areaWidth
= clientArea
->right
- clientArea
->left
,
2162 const char *pFirstChar
, *pLastChar
;
2169 int GetTextExtentExPointWWidth
;
2172 GetTextMetricsA(hdc
, &tm
);
2173 y
= clientArea
->top
;
2176 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2182 /* if not at the end of the string, ... */
2183 if (*str
== '\0') break;
2184 /* ... add the next word to the current extent */
2185 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2187 SetTextJustification(hdc
, 0, 0);
2188 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2189 } while ((int) size
.cx
< areaWidth
);
2191 /* ignore trailing break chars */
2193 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2199 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2201 SetTextJustification(hdc
, 0, 0);
2202 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2204 /* do not justify the last extent */
2205 if (*str
!= '\0' && breakCount
> 0)
2207 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2208 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2209 if (size
.cx
!= areaWidth
&& nErrors
< sizeof(error
)/sizeof(error
[0]) - 1)
2211 error
[nErrors
].start
= pFirstChar
;
2212 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2213 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2218 trace( "%u %.*s\n", size
.cx
, (int)(pLastChar
- pFirstChar
), pFirstChar
);
2222 } while (*str
&& y
< clientArea
->bottom
);
2224 for (e
= 0; e
< nErrors
; e
++)
2226 /* The width returned by GetTextExtentPoint32() is exactly the same
2227 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2228 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2229 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2230 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2234 static void test_SetTextJustification(void)
2244 static const char testText
[] =
2245 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2246 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2247 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2248 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2249 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2250 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2251 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2253 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2254 GetClientRect( hwnd
, &clientArea
);
2255 hdc
= GetDC( hwnd
);
2257 memset(&lf
, 0, sizeof lf
);
2258 lf
.lfCharSet
= ANSI_CHARSET
;
2259 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2260 lf
.lfWeight
= FW_DONTCARE
;
2262 lf
.lfQuality
= DEFAULT_QUALITY
;
2263 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2264 hfont
= create_font("Times New Roman", &lf
);
2265 SelectObject(hdc
, hfont
);
2267 testJustification(hdc
, testText
, &clientArea
);
2269 if (!pGetGlyphIndicesA
|| !pGetTextExtentExPointI
) goto done
;
2270 pGetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2272 SetTextJustification(hdc
, 0, 0);
2273 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2274 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2275 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2276 SetTextJustification(hdc
, 4, 1);
2277 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2278 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2279 SetTextJustification(hdc
, 9, 2);
2280 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2281 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2282 SetTextJustification(hdc
, 7, 3);
2283 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2284 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2285 SetTextJustification(hdc
, 7, 3);
2286 SetTextCharacterExtra(hdc
, 2 );
2287 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2288 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2289 SetTextJustification(hdc
, 0, 0);
2290 SetTextCharacterExtra(hdc
, 0);
2291 size
.cx
= size
.cy
= 1234;
2292 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2293 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
2294 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2295 SetTextJustification(hdc
, 5, 1);
2296 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2297 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2298 SetTextJustification(hdc
, 0, 0);
2300 SetMapMode( hdc
, MM_ANISOTROPIC
);
2301 SetWindowExtEx( hdc
, 2, 2, NULL
);
2302 GetClientRect( hwnd
, &clientArea
);
2303 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2304 testJustification(hdc
, testText
, &clientArea
);
2306 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2307 for (i
= 0; i
< 10; i
++)
2309 SetTextCharacterExtra(hdc
, i
);
2310 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2311 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2313 SetTextCharacterExtra(hdc
, 0);
2314 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2315 for (i
= 0; i
< 10; i
++)
2317 SetTextCharacterExtra(hdc
, i
);
2318 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2319 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2321 SetTextCharacterExtra(hdc
, 0);
2323 SetViewportExtEx( hdc
, 3, 3, NULL
);
2324 GetClientRect( hwnd
, &clientArea
);
2325 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2326 testJustification(hdc
, testText
, &clientArea
);
2328 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2329 for (i
= 0; i
< 10; i
++)
2331 SetTextCharacterExtra(hdc
, i
);
2332 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2333 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2337 DeleteObject(hfont
);
2338 ReleaseDC(hwnd
, hdc
);
2339 DestroyWindow(hwnd
);
2342 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2346 HFONT hfont
, hfont_old
;
2353 assert(count
<= 128);
2355 memset(&lf
, 0, sizeof(lf
));
2357 lf
.lfCharSet
= charset
;
2359 lstrcpyA(lf
.lfFaceName
, "Arial");
2360 SetLastError(0xdeadbeef);
2361 hfont
= CreateFontIndirectA(&lf
);
2362 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2365 hfont_old
= SelectObject(hdc
, hfont
);
2367 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2368 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2370 SetLastError(0xdeadbeef);
2371 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2372 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
2374 if (charset
== SYMBOL_CHARSET
)
2376 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2377 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
2381 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2382 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2385 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2387 trace("Can't find codepage for charset %d\n", cs
);
2391 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2393 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2395 skip("Font code page %d, looking for code page %d\n",
2396 pGdiGetCodePage(hdc
), code_page
);
2404 WCHAR unicode_buf
[128];
2406 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2408 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2410 SetLastError(0xdeadbeef);
2411 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2412 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2413 count
, ret
, GetLastError());
2419 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2421 SetLastError(0xdeadbeef);
2422 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2423 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2424 count
, ret
, GetLastError());
2427 SelectObject(hdc
, hfont_old
);
2428 DeleteObject(hfont
);
2435 static void test_font_charset(void)
2437 static struct charset_data
2441 WORD font_idxA
[128], font_idxW
[128];
2444 { ANSI_CHARSET
, 1252 },
2445 { RUSSIAN_CHARSET
, 1251 },
2446 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2450 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
2452 win_skip("Skipping the font charset test on a Win9x platform\n");
2456 if (!is_font_installed("Arial"))
2458 skip("Arial is not installed\n");
2462 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
2464 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2466 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2468 skip("Symbol or Wingdings is not installed\n");
2472 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2473 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2474 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2477 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2480 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2481 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2484 skip("Symbol or Wingdings is not installed\n");
2487 static void test_GdiGetCodePage(void)
2489 static const struct _matching_data
2491 UINT current_codepage
;
2494 UINT expected_codepage
;
2495 } matching_data
[] = {
2496 {1251, "Arial", ANSI_CHARSET
, 1252},
2497 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2499 {1252, "Arial", ANSI_CHARSET
, 1252},
2500 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2502 {1253, "Arial", ANSI_CHARSET
, 1252},
2503 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2505 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2506 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2507 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2509 { 936, "Arial", ANSI_CHARSET
, 936},
2510 { 936, "Tahoma", ANSI_CHARSET
, 936},
2511 { 936, "Simsun", ANSI_CHARSET
, 936},
2513 { 949, "Arial", ANSI_CHARSET
, 949},
2514 { 949, "Tahoma", ANSI_CHARSET
, 949},
2515 { 949, "Gulim", ANSI_CHARSET
, 949},
2517 { 950, "Arial", ANSI_CHARSET
, 950},
2518 { 950, "Tahoma", ANSI_CHARSET
, 950},
2519 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2528 if (!pGdiGetCodePage
)
2530 skip("GdiGetCodePage not available on this platform\n");
2536 for (i
= 0; i
< sizeof(matching_data
) / sizeof(struct _matching_data
); i
++)
2538 /* only test data matched current locale codepage */
2539 if (matching_data
[i
].current_codepage
!= acp
)
2542 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2544 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2550 memset(&lf
, 0, sizeof(lf
));
2552 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2553 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2554 hfont
= CreateFontIndirectA(&lf
);
2555 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2557 hfont
= SelectObject(hdc
, hfont
);
2558 charset
= GetTextCharset(hdc
);
2559 codepage
= pGdiGetCodePage(hdc
);
2560 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2561 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
, matching_data
[i
].expected_codepage
);
2562 ok(codepage
== matching_data
[i
].expected_codepage
,
2563 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2565 hfont
= SelectObject(hdc
, hfont
);
2566 DeleteObject(hfont
);
2567 ReleaseDC(NULL
, hdc
);
2571 static void test_GetFontUnicodeRanges(void)
2575 HFONT hfont
, hfont_old
;
2580 if (!pGetFontUnicodeRanges
)
2582 win_skip("GetFontUnicodeRanges not available before W2K\n");
2586 memset(&lf
, 0, sizeof(lf
));
2587 lstrcpyA(lf
.lfFaceName
, "Arial");
2588 hfont
= create_font("Arial", &lf
);
2591 hfont_old
= SelectObject(hdc
, hfont
);
2593 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2594 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2596 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2597 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2599 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2601 size
= pGetFontUnicodeRanges(hdc
, gs
);
2602 ok(size
, "GetFontUnicodeRanges failed\n");
2604 if (0) /* Disabled to limit console spam */
2605 for (i
= 0; i
< gs
->cRanges
; i
++)
2606 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2607 trace("found %u ranges\n", gs
->cRanges
);
2609 HeapFree(GetProcessHeap(), 0, gs
);
2611 SelectObject(hdc
, hfont_old
);
2612 DeleteObject(hfont
);
2613 ReleaseDC(NULL
, hdc
);
2616 #define MAX_ENUM_FONTS 4096
2618 struct enum_font_data
2621 LOGFONTA lf
[MAX_ENUM_FONTS
];
2624 struct enum_fullname_data
2627 ENUMLOGFONTA elf
[MAX_ENUM_FONTS
];
2630 struct enum_font_dataW
2633 LOGFONTW lf
[MAX_ENUM_FONTS
];
2636 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2638 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2639 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2641 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2642 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2644 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2646 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2648 if (0) /* Disabled to limit console spam */
2649 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2650 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2651 if (efd
->total
< MAX_ENUM_FONTS
)
2652 efd
->lf
[efd
->total
++] = *lf
;
2654 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2659 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2661 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2662 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2664 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2665 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2667 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2669 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2671 if (0) /* Disabled to limit console spam */
2672 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2673 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2674 if (efd
->total
< MAX_ENUM_FONTS
)
2675 efd
->lf
[efd
->total
++] = *lf
;
2677 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2682 static void get_charset_stats(struct enum_font_data
*efd
,
2683 int *ansi_charset
, int *symbol_charset
,
2684 int *russian_charset
)
2689 *symbol_charset
= 0;
2690 *russian_charset
= 0;
2692 for (i
= 0; i
< efd
->total
; i
++)
2694 switch (efd
->lf
[i
].lfCharSet
)
2699 case SYMBOL_CHARSET
:
2700 (*symbol_charset
)++;
2702 case RUSSIAN_CHARSET
:
2703 (*russian_charset
)++;
2709 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2710 int *ansi_charset
, int *symbol_charset
,
2711 int *russian_charset
)
2716 *symbol_charset
= 0;
2717 *russian_charset
= 0;
2719 for (i
= 0; i
< efd
->total
; i
++)
2721 switch (efd
->lf
[i
].lfCharSet
)
2726 case SYMBOL_CHARSET
:
2727 (*symbol_charset
)++;
2729 case RUSSIAN_CHARSET
:
2730 (*russian_charset
)++;
2736 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2738 struct enum_font_data efd
;
2739 struct enum_font_dataW efdw
;
2742 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2744 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2746 if (*font_name
&& !is_truetype_font_installed(font_name
))
2748 skip("%s is not installed\n", font_name
);
2754 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2755 * while EnumFontFamiliesEx doesn't.
2757 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2760 * Use EnumFontFamiliesW since win98 crashes when the
2761 * second parameter is NULL using EnumFontFamilies
2764 SetLastError(0xdeadbeef);
2765 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2766 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2769 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2770 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2771 ansi_charset
, symbol_charset
, russian_charset
);
2772 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2773 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2774 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2775 ok(russian_charset
> 0 ||
2776 broken(russian_charset
== 0), /* NT4 */
2777 "NULL family should enumerate RUSSIAN_CHARSET\n");
2781 SetLastError(0xdeadbeef);
2782 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2783 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2786 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2787 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2788 ansi_charset
, symbol_charset
, russian_charset
);
2789 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2790 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2791 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2792 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2797 SetLastError(0xdeadbeef);
2798 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2799 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2800 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2801 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2802 ansi_charset
, symbol_charset
, russian_charset
,
2803 *font_name
? font_name
: "<empty>");
2805 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2807 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2808 for (i
= 0; i
< efd
.total
; i
++)
2810 /* FIXME: remove completely once Wine is fixed */
2811 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2814 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2817 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2818 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2819 font_name
, efd
.lf
[i
].lfFaceName
);
2822 memset(&lf
, 0, sizeof(lf
));
2823 lf
.lfCharSet
= ANSI_CHARSET
;
2824 strcpy(lf
.lfFaceName
, font_name
);
2826 SetLastError(0xdeadbeef);
2827 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2828 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2829 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2830 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2831 ansi_charset
, symbol_charset
, russian_charset
,
2832 *font_name
? font_name
: "<empty>");
2833 if (font_charset
== SYMBOL_CHARSET
)
2836 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2838 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2842 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2843 for (i
= 0; i
< efd
.total
; i
++)
2845 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2847 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2848 font_name
, efd
.lf
[i
].lfFaceName
);
2852 /* DEFAULT_CHARSET should enumerate all available charsets */
2853 memset(&lf
, 0, sizeof(lf
));
2854 lf
.lfCharSet
= DEFAULT_CHARSET
;
2855 strcpy(lf
.lfFaceName
, font_name
);
2857 SetLastError(0xdeadbeef);
2858 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2859 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2860 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2861 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2862 ansi_charset
, symbol_charset
, russian_charset
,
2863 *font_name
? font_name
: "<empty>");
2864 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2865 for (i
= 0; i
< efd
.total
; i
++)
2868 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2869 font_name
, efd
.lf
[i
].lfFaceName
);
2873 switch (font_charset
)
2876 ok(ansi_charset
> 0,
2877 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2879 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2880 ok(russian_charset
> 0,
2881 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2883 case SYMBOL_CHARSET
:
2885 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2887 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2888 ok(!russian_charset
,
2889 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2891 case DEFAULT_CHARSET
:
2892 ok(ansi_charset
> 0,
2893 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2894 ok(symbol_charset
> 0,
2895 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2896 ok(russian_charset
> 0,
2897 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2903 ok(ansi_charset
> 0,
2904 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2905 ok(symbol_charset
> 0,
2906 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2907 ok(russian_charset
> 0,
2908 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2911 memset(&lf
, 0, sizeof(lf
));
2912 lf
.lfCharSet
= SYMBOL_CHARSET
;
2913 strcpy(lf
.lfFaceName
, font_name
);
2915 SetLastError(0xdeadbeef);
2916 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2917 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2918 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2919 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2920 ansi_charset
, symbol_charset
, russian_charset
,
2921 *font_name
? font_name
: "<empty>");
2922 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2923 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2926 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2927 for (i
= 0; i
< efd
.total
; i
++)
2929 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2931 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2932 font_name
, efd
.lf
[i
].lfFaceName
);
2936 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2937 ok(symbol_charset
> 0,
2938 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2939 ok(!russian_charset
,
2940 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2946 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2948 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
2949 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
2950 const DWORD valid_bits
= 0x003f01ff;
2954 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
2956 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
2957 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
2958 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
2967 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
2969 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2971 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2973 if (efd
->total
< MAX_ENUM_FONTS
)
2974 efd
->lf
[efd
->total
++] = *lf
;
2976 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2981 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
2983 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
2985 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2987 if (efnd
->total
< MAX_ENUM_FONTS
)
2988 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
2990 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2995 static void test_EnumFontFamiliesEx_default_charset(void)
2997 struct enum_font_data efd
;
2998 LOGFONTA target
, enum_font
;
3004 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3005 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3010 memset(&enum_font
, 0, sizeof(enum_font
));
3011 enum_font
.lfCharSet
= csi
.ciCharset
;
3012 target
.lfFaceName
[0] = '\0';
3013 target
.lfCharSet
= csi
.ciCharset
;
3014 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3015 if (target
.lfFaceName
[0] == '\0') {
3016 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3019 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3020 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3021 target
.lfCharSet
= ANSI_CHARSET
;
3025 memset(&enum_font
, 0, sizeof(enum_font
));
3026 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3027 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3028 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3031 trace("'%s' has %d charsets.\n", target
.lfFaceName
, efd
.total
);
3032 if (efd
.total
< 2) {
3033 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3037 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3038 "(%s) got charset %d expected %d\n",
3039 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3044 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3046 HFONT hfont
, hfont_prev
;
3048 GLYPHMETRICS gm1
, gm2
;
3052 if(!pGetGlyphIndicesA
)
3055 /* negative widths are handled just as positive ones */
3056 lf2
.lfWidth
= -lf
->lfWidth
;
3058 SetLastError(0xdeadbeef);
3059 hfont
= CreateFontIndirectA(lf
);
3060 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3061 check_font("original", lf
, hfont
);
3063 hfont_prev
= SelectObject(hdc
, hfont
);
3065 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3066 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3068 SelectObject(hdc
, hfont_prev
);
3069 DeleteObject(hfont
);
3070 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3074 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3075 memset(&gm1
, 0xab, sizeof(gm1
));
3076 SetLastError(0xdeadbeef);
3077 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3078 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3080 SelectObject(hdc
, hfont_prev
);
3081 DeleteObject(hfont
);
3083 SetLastError(0xdeadbeef);
3084 hfont
= CreateFontIndirectA(&lf2
);
3085 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3086 check_font("negative width", &lf2
, hfont
);
3088 hfont_prev
= SelectObject(hdc
, hfont
);
3090 memset(&gm2
, 0xbb, sizeof(gm2
));
3091 SetLastError(0xdeadbeef);
3092 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3093 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3095 SelectObject(hdc
, hfont_prev
);
3096 DeleteObject(hfont
);
3098 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3099 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3100 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3101 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3102 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3103 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3104 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3105 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3106 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3107 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3108 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3111 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3112 #include "pshpack2.h"
3116 SHORT xAvgCharWidth
;
3117 USHORT usWeightClass
;
3118 USHORT usWidthClass
;
3120 SHORT ySubscriptXSize
;
3121 SHORT ySubscriptYSize
;
3122 SHORT ySubscriptXOffset
;
3123 SHORT ySubscriptYOffset
;
3124 SHORT ySuperscriptXSize
;
3125 SHORT ySuperscriptYSize
;
3126 SHORT ySuperscriptXOffset
;
3127 SHORT ySuperscriptYOffset
;
3128 SHORT yStrikeoutSize
;
3129 SHORT yStrikeoutPosition
;
3132 ULONG ulUnicodeRange1
;
3133 ULONG ulUnicodeRange2
;
3134 ULONG ulUnicodeRange3
;
3135 ULONG ulUnicodeRange4
;
3138 USHORT usFirstCharIndex
;
3139 USHORT usLastCharIndex
;
3140 /* According to the Apple spec, original version didn't have the below fields,
3141 * version numbers were taken from the OpenType spec.
3143 /* version 0 (TrueType 1.5) */
3144 USHORT sTypoAscender
;
3145 USHORT sTypoDescender
;
3146 USHORT sTypoLineGap
;
3148 USHORT usWinDescent
;
3149 /* version 1 (TrueType 1.66) */
3150 ULONG ulCodePageRange1
;
3151 ULONG ulCodePageRange2
;
3152 /* version 2 (OpenType 1.2) */
3155 USHORT usDefaultChar
;
3157 USHORT usMaxContext
;
3159 #include "poppack.h"
3172 } cmap_encoding_record
;
3180 BYTE glyph_ids
[256];
3190 USHORT search_range
;
3191 USHORT entry_selector
;
3194 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3197 USHORT start_count[seg_countx2 / 2];
3198 USHORT id_delta[seg_countx2 / 2];
3199 USHORT id_range_offset[seg_countx2 / 2];
3209 USHORT id_range_offset
;
3210 } cmap_format_4_seg
;
3212 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
3214 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3215 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3216 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3217 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3218 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3221 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3224 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3228 for(i
= 0; i
< 256; i
++)
3230 if(cmap
->glyph_ids
[i
] == 0) continue;
3232 if(*first
== 256) *first
= i
;
3234 if(*first
== 256) return FALSE
;
3238 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3240 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3241 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3242 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3243 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3244 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3247 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3250 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3251 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3252 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
3256 for(i
= 0; i
< seg_count
; i
++)
3259 cmap_format_4_seg seg
;
3261 get_seg4(cmap
, i
, &seg
);
3262 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
3264 if(seg
.id_range_offset
== 0)
3265 index
= (seg
.id_delta
+ code
) & 0xffff;
3268 index
= seg
.id_range_offset
/ 2
3269 + code
- seg
.start_count
3272 /* some fonts have broken last segment */
3273 if ((char *)(glyph_ids
+ index
+ 1) < (char *)ptr
+ limit
)
3274 index
= GET_BE_WORD(glyph_ids
[index
]);
3277 trace("segment %04x/%04x index %04x points to nowhere\n",
3278 seg
.start_count
, seg
.end_count
, index
);
3281 if(index
) index
+= seg
.id_delta
;
3283 if(*first
== 0x10000)
3284 *last
= *first
= code
;
3290 if(*first
== 0x10000) return FALSE
;
3294 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3297 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3299 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3301 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3302 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3315 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3318 cmap_header
*header
;
3323 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3324 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3325 if(size
== GDI_ERROR
) return FALSE
;
3327 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3328 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3329 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3330 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3332 cmap
= get_cmap(header
, 3, 1);
3334 *cmap_type
= cmap_ms_unicode
;
3337 cmap
= get_cmap(header
, 3, 0);
3338 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3342 *cmap_type
= cmap_none
;
3346 format
= GET_BE_WORD(*(WORD
*)cmap
);
3350 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3353 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3356 trace("unhandled cmap format %d\n", format
);
3361 HeapFree(GetProcessHeap(), 0, header
);
3365 #define TT_PLATFORM_MICROSOFT 3
3366 #define TT_MS_ID_SYMBOL_CS 0
3367 #define TT_MS_ID_UNICODE_CS 1
3368 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3369 #define TT_NAME_ID_FONT_FAMILY 1
3370 #define TT_NAME_ID_FONT_SUBFAMILY 2
3371 #define TT_NAME_ID_UNIQUE_ID 3
3372 #define TT_NAME_ID_FULL_NAME 4
3374 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3376 struct sfnt_name_header
3379 USHORT number_of_record
;
3380 USHORT storage_offset
;
3392 LONG size
, offset
, length
;
3398 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3399 ok(size
!= GDI_ERROR
, "no name table found\n");
3400 if(size
== GDI_ERROR
) return FALSE
;
3402 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3403 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3404 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3406 header
= (void *)data
;
3407 header
->format
= GET_BE_WORD(header
->format
);
3408 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3409 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3410 if (header
->format
!= 0)
3412 trace("got format %u\n", header
->format
);
3415 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3417 trace("number records out of range: %d\n", header
->number_of_record
);
3420 if (header
->storage_offset
>= size
)
3422 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3426 entry
= (void *)&header
[1];
3427 for (i
= 0; i
< header
->number_of_record
; i
++)
3429 if (GET_BE_WORD(entry
[i
].platform_id
) != TT_PLATFORM_MICROSOFT
||
3430 (GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_UNICODE_CS
&& GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_SYMBOL_CS
) ||
3431 GET_BE_WORD(entry
[i
].language_id
) != language_id
||
3432 GET_BE_WORD(entry
[i
].name_id
) != name_id
)
3437 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[i
].offset
);
3438 length
= GET_BE_WORD(entry
[i
].length
);
3439 if (offset
+ length
> size
)
3441 trace("entry %d is out of range\n", i
);
3444 if (length
>= out_size
)
3446 trace("buffer too small for entry %d\n", i
);
3450 name
= (WCHAR
*)(data
+ offset
);
3451 for (c
= 0; c
< length
/ 2; c
++)
3452 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3460 HeapFree(GetProcessHeap(), 0, data
);
3464 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3467 HFONT hfont
, hfont_old
;
3471 const char *font_name
= lf
->lfFaceName
;
3472 DWORD cmap_first
= 0, cmap_last
= 0;
3473 UINT ascent
, descent
, cell_height
;
3474 cmap_type cmap_type
;
3475 BOOL sys_lang_non_english
;
3477 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3480 SetLastError(0xdeadbeef);
3481 hfont
= CreateFontIndirectA(lf
);
3482 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3484 hfont_old
= SelectObject(hdc
, hfont
);
3486 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3487 if (size
== GDI_ERROR
)
3489 trace("OS/2 chunk was not found\n");
3492 if (size
> sizeof(tt_os2
))
3494 trace("got too large OS/2 chunk of size %u\n", size
);
3495 size
= sizeof(tt_os2
);
3498 memset(&tt_os2
, 0, sizeof(tt_os2
));
3499 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3500 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3502 SetLastError(0xdeadbeef);
3503 ret
= GetTextMetricsA(hdc
, &tmA
);
3504 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3506 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3508 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3512 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3513 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3514 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3518 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3519 descent
= GET_BE_WORD(tt_os2
.usWinDescent
);
3520 cell_height
= ascent
+ descent
;
3521 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3522 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3524 version
= GET_BE_WORD(tt_os2
.version
);
3526 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3527 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3528 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3529 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3531 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3532 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3533 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3535 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3540 case 1257: /* Baltic */
3541 expect_last_W
= 0xf8fd;
3544 expect_last_W
= 0xf0ff;
3546 expect_break_W
= 0x20;
3547 expect_default_W
= expect_break_W
- 1;
3548 expect_first_A
= 0x1e;
3549 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3553 expect_first_W
= cmap_first
;
3554 expect_last_W
= min(cmap_last
, os2_last_char
);
3555 if(os2_first_char
<= 1)
3556 expect_break_W
= os2_first_char
+ 2;
3557 else if(os2_first_char
> 0xff)
3558 expect_break_W
= 0x20;
3560 expect_break_W
= os2_first_char
;
3561 expect_default_W
= expect_break_W
- 1;
3562 expect_first_A
= expect_default_W
- 1;
3563 expect_last_A
= min(expect_last_W
, 0xff);
3565 expect_break_A
= expect_break_W
;
3566 expect_default_A
= expect_default_W
;
3568 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3569 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3570 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
3571 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3572 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3574 ok(tmA
.tmFirstChar
== expect_first_A
||
3575 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3576 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3577 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3578 ok(tmA
.tmLastChar
== expect_last_A
||
3579 tmA
.tmLastChar
== 0xff /* win9x */,
3580 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3582 skip("tmLastChar is DBCS lead byte\n");
3583 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3584 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3585 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3586 "A: tmDefaultChar for %s got %02x expected %02x\n",
3587 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3590 SetLastError(0xdeadbeef);
3591 ret
= GetTextMetricsW(hdc
, &tmW
);
3592 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3593 "GetTextMetricsW error %u\n", GetLastError());
3596 /* Wine uses the os2 first char */
3597 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3598 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3599 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3601 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3602 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3604 /* Wine uses the os2 last char */
3605 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3606 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3607 font_name
, tmW
.tmLastChar
, expect_last_W
);
3609 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3610 font_name
, tmW
.tmLastChar
, expect_last_W
);
3611 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3612 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3613 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3614 "W: tmDefaultChar for %s got %02x expected %02x\n",
3615 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3617 /* Test the aspect ratio while we have tmW */
3618 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3619 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3620 tmW
.tmDigitizedAspectX
, ret
);
3621 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3622 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3623 tmW
.tmDigitizedAspectX
, ret
);
3627 /* test FF_ values */
3628 switch(tt_os2
.panose
.bFamilyType
)
3632 case PAN_FAMILY_TEXT_DISPLAY
:
3633 case PAN_FAMILY_PICTORIAL
:
3635 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3636 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3638 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3641 switch(tt_os2
.panose
.bSerifStyle
)
3646 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3649 case PAN_SERIF_COVE
:
3650 case PAN_SERIF_OBTUSE_COVE
:
3651 case PAN_SERIF_SQUARE_COVE
:
3652 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3653 case PAN_SERIF_SQUARE
:
3654 case PAN_SERIF_THIN
:
3655 case PAN_SERIF_BONE
:
3656 case PAN_SERIF_EXAGGERATED
:
3657 case PAN_SERIF_TRIANGLE
:
3658 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3661 case PAN_SERIF_NORMAL_SANS
:
3662 case PAN_SERIF_OBTUSE_SANS
:
3663 case PAN_SERIF_PERP_SANS
:
3664 case PAN_SERIF_FLARED
:
3665 case PAN_SERIF_ROUNDED
:
3666 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3671 case PAN_FAMILY_SCRIPT
:
3672 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3675 case PAN_FAMILY_DECORATIVE
:
3676 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3680 test_negative_width(hdc
, lf
);
3683 SelectObject(hdc
, hfont_old
);
3684 DeleteObject(hfont
);
3689 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3691 INT
*enumed
= (INT
*)lParam
;
3693 if (type
== TRUETYPE_FONTTYPE
)
3696 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
3701 static void test_GetTextMetrics(void)
3707 /* Report only once */
3708 if(!pGetGlyphIndicesA
)
3709 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3713 memset(&lf
, 0, sizeof(lf
));
3714 lf
.lfCharSet
= DEFAULT_CHARSET
;
3716 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
3717 trace("Tested metrics of %d truetype fonts\n", enumed
);
3722 static void test_nonexistent_font(void)
3730 { "Times New Roman Baltic", 186 },
3731 { "Times New Roman CE", 238 },
3732 { "Times New Roman CYR", 204 },
3733 { "Times New Roman Greek", 161 },
3734 { "Times New Roman TUR", 162 }
3740 INT cs
, expected_cs
, i
;
3741 char buf
[LF_FACESIZE
];
3743 if (!is_truetype_font_installed("Arial") ||
3744 !is_truetype_font_installed("Times New Roman"))
3746 skip("Arial or Times New Roman not installed\n");
3750 expected_cs
= GetACP();
3751 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3753 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3756 expected_cs
= csi
.ciCharset
;
3757 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3761 memset(&lf
, 0, sizeof(lf
));
3763 lf
.lfWeight
= FW_REGULAR
;
3764 lf
.lfCharSet
= ANSI_CHARSET
;
3765 lf
.lfPitchAndFamily
= FF_SWISS
;
3766 strcpy(lf
.lfFaceName
, "Nonexistent font");
3767 hfont
= CreateFontIndirectA(&lf
);
3768 hfont
= SelectObject(hdc
, hfont
);
3769 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3770 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
3771 cs
= GetTextCharset(hdc
);
3772 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3773 DeleteObject(SelectObject(hdc
, hfont
));
3775 memset(&lf
, 0, sizeof(lf
));
3777 lf
.lfWeight
= FW_DONTCARE
;
3778 strcpy(lf
.lfFaceName
, "Nonexistent font");
3779 hfont
= CreateFontIndirectA(&lf
);
3780 hfont
= SelectObject(hdc
, hfont
);
3781 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3782 todo_wine
/* Wine uses Arial for all substitutions */
3783 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
3784 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
3785 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3787 cs
= GetTextCharset(hdc
);
3788 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
3789 DeleteObject(SelectObject(hdc
, hfont
));
3791 memset(&lf
, 0, sizeof(lf
));
3793 lf
.lfWeight
= FW_REGULAR
;
3794 strcpy(lf
.lfFaceName
, "Nonexistent font");
3795 hfont
= CreateFontIndirectA(&lf
);
3796 hfont
= SelectObject(hdc
, hfont
);
3797 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3798 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3799 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
3800 cs
= GetTextCharset(hdc
);
3801 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3802 DeleteObject(SelectObject(hdc
, hfont
));
3804 memset(&lf
, 0, sizeof(lf
));
3806 lf
.lfWeight
= FW_DONTCARE
;
3807 strcpy(lf
.lfFaceName
, "Times New Roman");
3808 hfont
= CreateFontIndirectA(&lf
);
3809 hfont
= SelectObject(hdc
, hfont
);
3810 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3811 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
3812 cs
= GetTextCharset(hdc
);
3813 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3814 DeleteObject(SelectObject(hdc
, hfont
));
3816 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
3818 memset(&lf
, 0, sizeof(lf
));
3820 lf
.lfWeight
= FW_REGULAR
;
3821 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3822 hfont
= CreateFontIndirectA(&lf
);
3823 hfont
= SelectObject(hdc
, hfont
);
3824 cs
= GetTextCharset(hdc
);
3825 if (font_subst
[i
].charset
== expected_cs
)
3827 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3828 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3829 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
3833 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
3834 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3835 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3836 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
3838 DeleteObject(SelectObject(hdc
, hfont
));
3840 memset(&lf
, 0, sizeof(lf
));
3842 lf
.lfWeight
= FW_DONTCARE
;
3843 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3844 hfont
= CreateFontIndirectA(&lf
);
3845 hfont
= SelectObject(hdc
, hfont
);
3846 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3847 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
3848 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
3849 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
3850 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3851 "got %s for font %s\n", buf
, font_subst
[i
].name
);
3852 cs
= GetTextCharset(hdc
);
3853 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3854 DeleteObject(SelectObject(hdc
, hfont
));
3860 static void test_GdiRealizationInfo(void)
3865 HFONT hfont
, hfont_old
;
3868 if(!pGdiRealizationInfo
)
3870 win_skip("GdiRealizationInfo not available\n");
3876 memset(info
, 0xcc, sizeof(info
));
3877 r
= pGdiRealizationInfo(hdc
, info
);
3878 ok(r
!= 0, "ret 0\n");
3879 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
3880 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3882 if (!is_truetype_font_installed("Arial"))
3884 skip("skipping GdiRealizationInfo with truetype font\n");
3888 memset(&lf
, 0, sizeof(lf
));
3889 strcpy(lf
.lfFaceName
, "Arial");
3891 lf
.lfWeight
= FW_NORMAL
;
3892 hfont
= CreateFontIndirectA(&lf
);
3893 hfont_old
= SelectObject(hdc
, hfont
);
3895 memset(info
, 0xcc, sizeof(info
));
3896 r
= pGdiRealizationInfo(hdc
, info
);
3897 ok(r
!= 0, "ret 0\n");
3898 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
3899 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3901 DeleteObject(SelectObject(hdc
, hfont_old
));
3907 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3908 the nul in the count of characters copied when the face name buffer is not
3909 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3910 always includes it. */
3911 static void test_GetTextFace(void)
3913 static const char faceA
[] = "Tahoma";
3914 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
3917 char bufA
[LF_FACESIZE
];
3918 WCHAR bufW
[LF_FACESIZE
];
3923 if(!is_font_installed("Tahoma"))
3925 skip("Tahoma is not installed so skipping this test\n");
3930 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
3931 f
= CreateFontIndirectA(&fA
);
3932 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
3935 g
= SelectObject(dc
, f
);
3936 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
3937 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
3938 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
3940 /* Play with the count arg. */
3942 n
= GetTextFaceA(dc
, 0, bufA
);
3943 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3944 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3947 n
= GetTextFaceA(dc
, 1, bufA
);
3948 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3949 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3951 bufA
[0] = 'x'; bufA
[1] = 'y';
3952 n
= GetTextFaceA(dc
, 2, bufA
);
3953 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
3954 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
3956 n
= GetTextFaceA(dc
, 0, NULL
);
3957 ok(n
== sizeof faceA
||
3958 broken(n
== 0), /* win98, winMe */
3959 "GetTextFaceA returned %d\n", n
);
3961 DeleteObject(SelectObject(dc
, g
));
3962 ReleaseDC(NULL
, dc
);
3965 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3966 SetLastError(0xdeadbeef);
3967 f
= CreateFontIndirectW(&fW
);
3968 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3970 win_skip("CreateFontIndirectW is not implemented\n");
3973 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3976 g
= SelectObject(dc
, f
);
3977 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3978 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3979 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3981 /* Play with the count arg. */
3983 n
= GetTextFaceW(dc
, 0, bufW
);
3984 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3985 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3988 n
= GetTextFaceW(dc
, 1, bufW
);
3989 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3990 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3992 bufW
[0] = 'x'; bufW
[1] = 'y';
3993 n
= GetTextFaceW(dc
, 2, bufW
);
3994 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
3995 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
3997 n
= GetTextFaceW(dc
, 0, NULL
);
3998 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4000 DeleteObject(SelectObject(dc
, g
));
4001 ReleaseDC(NULL
, dc
);
4004 static void test_orientation(void)
4006 static const char test_str
[11] = "Test String";
4009 HFONT hfont
, old_hfont
;
4012 if (!is_truetype_font_installed("Arial"))
4014 skip("Arial is not installed\n");
4018 hdc
= CreateCompatibleDC(0);
4019 memset(&lf
, 0, sizeof(lf
));
4020 lstrcpyA(lf
.lfFaceName
, "Arial");
4022 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4023 hfont
= create_font("orientation", &lf
);
4024 old_hfont
= SelectObject(hdc
, hfont
);
4025 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4026 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4027 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4028 SelectObject(hdc
, old_hfont
);
4029 DeleteObject(hfont
);
4033 static void test_oemcharset(void)
4037 HFONT hfont
, old_hfont
;
4040 hdc
= CreateCompatibleDC(0);
4041 ZeroMemory(&lf
, sizeof(lf
));
4043 lf
.lfCharSet
= OEM_CHARSET
;
4044 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4045 lstrcpyA(lf
.lfFaceName
, "Terminal");
4046 hfont
= CreateFontIndirectA(&lf
);
4047 old_hfont
= SelectObject(hdc
, hfont
);
4048 charset
= GetTextCharset(hdc
);
4050 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4051 hfont
= SelectObject(hdc
, old_hfont
);
4052 GetObjectA(hfont
, sizeof(clf
), &clf
);
4053 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4054 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4055 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4056 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4057 DeleteObject(hfont
);
4061 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4062 const TEXTMETRICA
*lpntme
,
4063 DWORD FontType
, LPARAM lParam
)
4065 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4067 LOGFONTA lf
= *lpelfe
;
4071 /* skip bitmap, proportional or vertical font */
4072 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4073 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4074 lf
.lfFaceName
[0] == '@')
4077 /* skip linked font */
4078 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4079 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4082 /* skip linked font, like SimSun-ExtB */
4083 switch (lpelfe
->lfCharSet
) {
4084 case SHIFTJIS_CHARSET
:
4085 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4087 case GB2312_CHARSET
:
4088 case CHINESEBIG5_CHARSET
:
4089 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4091 case HANGEUL_CHARSET
:
4092 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4095 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4101 /* test with an odd height */
4104 hfont
= CreateFontIndirectA(&lf
);
4107 *(HFONT
*)lParam
= hfont
;
4113 static void test_GetGlyphOutline(void)
4116 GLYPHMETRICS gm
, gm2
;
4118 HFONT hfont
, old_hfont
;
4120 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4121 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4129 {ANSI_CHARSET
, 0x30, 0x30},
4130 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4131 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4132 {GB2312_CHARSET
, 0x8141, 0x4e04},
4133 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4137 if (!is_truetype_font_installed("Tahoma"))
4139 skip("Tahoma is not installed\n");
4143 hdc
= CreateCompatibleDC(0);
4144 memset(&lf
, 0, sizeof(lf
));
4146 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4147 SetLastError(0xdeadbeef);
4148 hfont
= CreateFontIndirectA(&lf
);
4149 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4150 old_hfont
= SelectObject(hdc
, hfont
);
4152 memset(&gm
, 0, sizeof(gm
));
4153 SetLastError(0xdeadbeef);
4154 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4155 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4157 memset(&gm
, 0, sizeof(gm
));
4158 SetLastError(0xdeadbeef);
4159 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4160 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4161 ok(GetLastError() == 0xdeadbeef ||
4162 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4163 "expected 0xdeadbeef, got %u\n", GetLastError());
4165 memset(&gm
, 0, sizeof(gm
));
4166 SetLastError(0xdeadbeef);
4167 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4168 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4169 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4171 memset(&gm
, 0, sizeof(gm
));
4172 SetLastError(0xdeadbeef);
4173 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4174 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4176 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4177 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4180 /* test for needed buffer size request on space char */
4181 memset(&gm
, 0, sizeof(gm
));
4182 SetLastError(0xdeadbeef);
4183 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4184 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4185 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4187 /* requesting buffer size for space char + error */
4188 memset(&gm
, 0, sizeof(gm
));
4189 SetLastError(0xdeadbeef);
4190 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4191 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4193 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4194 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4197 for (i
= 0; i
< sizeof(fmt
) / sizeof(fmt
[0]); ++i
)
4201 memset(&gm
, 0xab, sizeof(gm
));
4202 SetLastError(0xdeadbeef);
4203 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4204 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4206 if (fmt
[i
] == GGO_METRICS
)
4207 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4209 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4210 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4211 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4214 memset(&gm
, 0xab, sizeof(gm
));
4215 SetLastError(0xdeadbeef);
4216 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4217 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4219 if (fmt
[i
] == GGO_METRICS
)
4220 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4222 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4223 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4224 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4227 memset(&gm
, 0xab, sizeof(gm
));
4228 SetLastError(0xdeadbeef);
4229 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4230 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4232 if (fmt
[i
] == GGO_METRICS
)
4233 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4235 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4236 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4237 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4240 memset(&gm
, 0xab, sizeof(gm
));
4241 SetLastError(0xdeadbeef);
4242 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4243 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4245 if (fmt
[i
] == GGO_METRICS
) {
4246 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4247 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4248 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4252 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4253 memset(&gm2
, 0xab, sizeof(gm2
));
4254 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4255 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4260 SelectObject(hdc
, old_hfont
);
4261 DeleteObject(hfont
);
4263 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
4265 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4268 lf
.lfFaceName
[0] = '\0';
4269 lf
.lfCharSet
= c
[i
].cs
;
4270 lf
.lfPitchAndFamily
= 0;
4271 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4273 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4277 old_hfont
= SelectObject(hdc
, hfont
);
4279 /* expected to ignore superfluous bytes (sigle-byte character) */
4280 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4281 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4282 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4284 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4285 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4286 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4288 /* expected to ignore superfluous bytes (double-byte character) */
4289 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4290 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4291 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4292 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4294 /* expected to match wide-char version results */
4295 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4296 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4298 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4300 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4303 DeleteObject(SelectObject(hdc
, hfont
));
4306 DeleteObject(SelectObject(hdc
, old_hfont
));
4310 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4311 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4313 ret
= GetTextMetricsA(hdc
, &tm
);
4314 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4315 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4316 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4317 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4318 -lf
.lfHeight
, tm
.tmAveCharWidth
, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4319 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4320 "expected %d, got %d (%s:%d)\n",
4321 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4323 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4324 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4325 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4326 "expected %d, got %d (%s:%d)\n",
4327 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4330 hfont
= CreateFontIndirectA(&lf
);
4331 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4332 DeleteObject(SelectObject(hdc
, hfont
));
4333 ret
= GetTextMetricsA(hdc
, &tm
);
4334 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4335 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4336 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4337 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4338 "expected %d, got %d (%s:%d)\n",
4339 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4341 lf
.lfItalic
= FALSE
;
4342 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4343 hfont
= CreateFontIndirectA(&lf
);
4344 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4345 DeleteObject(SelectObject(hdc
, hfont
));
4346 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4347 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4348 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4349 "expected %d, got %d (%s:%d)\n",
4350 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4352 hfont
= SelectObject(hdc
, old_hfont
);
4353 DeleteObject(hfont
);
4359 /* bug #9995: there is a limit to the character width that can be specified */
4360 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4366 int ave_width
, height
, width
, ratio
, scale
;
4368 if (!is_truetype_font_installed( fontname
)) {
4369 skip("%s is not installed\n", fontname
);
4372 hdc
= CreateCompatibleDC(0);
4373 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4374 /* select width = 0 */
4375 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4376 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4377 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4379 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4380 of
= SelectObject( hdc
, hf
);
4381 ret
= GetTextMetricsA( hdc
, &tm
);
4382 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4383 height
= tm
.tmHeight
;
4384 ave_width
= tm
.tmAveCharWidth
;
4385 SelectObject( hdc
, of
);
4388 trace("height %d, ave width %d\n", height
, ave_width
);
4390 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4392 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4393 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4394 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4395 ok(hf
!= 0, "CreateFont failed\n");
4396 of
= SelectObject(hdc
, hf
);
4397 ret
= GetTextMetricsA(hdc
, &tm
);
4398 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4399 SelectObject(hdc
, of
);
4402 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4408 ratio
= width
/ height
;
4409 scale
= width
/ ave_width
;
4411 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4412 width
, height
, ratio
, width
, ave_width
, scale
);
4414 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4417 static void test_CreateFontIndirect(void)
4419 LOGFONTA lf
, getobj_lf
;
4422 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4424 memset(&lf
, 0, sizeof(lf
));
4425 lf
.lfCharSet
= ANSI_CHARSET
;
4426 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4429 lf
.lfQuality
= DEFAULT_QUALITY
;
4430 lf
.lfItalic
= FALSE
;
4431 lf
.lfWeight
= FW_DONTCARE
;
4433 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
4435 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4436 hfont
= CreateFontIndirectA(&lf
);
4437 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4438 SetLastError(0xdeadbeef);
4439 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
4440 ok(ret
, "GetObject failed: %d\n", GetLastError());
4441 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
4442 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
4443 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
4444 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
4445 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
4446 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
4447 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
4448 DeleteObject(hfont
);
4452 static void test_CreateFontIndirectEx(void)
4454 ENUMLOGFONTEXDVA lfex
;
4457 if (!pCreateFontIndirectExA
)
4459 win_skip("CreateFontIndirectExA is not available\n");
4463 if (!is_truetype_font_installed("Arial"))
4465 skip("Arial is not installed\n");
4469 SetLastError(0xdeadbeef);
4470 hfont
= pCreateFontIndirectExA(NULL
);
4471 ok(hfont
== NULL
, "got %p\n", hfont
);
4472 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4474 memset(&lfex
, 0, sizeof(lfex
));
4475 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
4476 hfont
= pCreateFontIndirectExA(&lfex
);
4477 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
4479 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
4480 DeleteObject(hfont
);
4483 static void free_font(void *font
)
4485 UnmapViewOfFile(font
);
4488 static void *load_font(const char *font_name
, DWORD
*font_size
)
4490 char file_name
[MAX_PATH
];
4491 HANDLE file
, mapping
;
4494 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
4495 strcat(file_name
, "\\fonts\\");
4496 strcat(file_name
, font_name
);
4498 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
4499 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
4501 *font_size
= GetFileSize(file
, NULL
);
4503 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4510 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
4513 CloseHandle(mapping
);
4517 static void test_AddFontMemResource(void)
4520 DWORD font_size
, num_fonts
;
4524 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
4526 win_skip("AddFontMemResourceEx is not available on this platform\n");
4530 font
= load_font("sserife.fon", &font_size
);
4533 skip("Unable to locate and load font sserife.fon\n");
4537 SetLastError(0xdeadbeef);
4538 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
4539 ok(!ret
, "AddFontMemResourceEx should fail\n");
4540 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4541 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4544 SetLastError(0xdeadbeef);
4545 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
4546 ok(!ret
, "AddFontMemResourceEx should fail\n");
4547 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4548 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4551 SetLastError(0xdeadbeef);
4552 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
4553 ok(!ret
, "AddFontMemResourceEx should fail\n");
4554 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4555 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4558 SetLastError(0xdeadbeef);
4559 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
4560 ok(!ret
, "AddFontMemResourceEx should fail\n");
4561 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4562 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4565 SetLastError(0xdeadbeef);
4566 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
4567 ok(!ret
, "AddFontMemResourceEx should fail\n");
4568 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4569 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4572 SetLastError(0xdeadbeef);
4573 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
4574 ok(!ret
, "AddFontMemResourceEx should fail\n");
4575 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4576 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4579 num_fonts
= 0xdeadbeef;
4580 SetLastError(0xdeadbeef);
4581 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
4582 ok(!ret
, "AddFontMemResourceEx should fail\n");
4583 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4584 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4586 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4588 if (0) /* hangs under windows 2000 */
4590 num_fonts
= 0xdeadbeef;
4591 SetLastError(0xdeadbeef);
4592 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
4593 ok(!ret
, "AddFontMemResourceEx should fail\n");
4594 ok(GetLastError() == 0xdeadbeef,
4595 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4597 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4600 num_fonts
= 0xdeadbeef;
4601 SetLastError(0xdeadbeef);
4602 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
4603 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
4604 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4605 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
4609 SetLastError(0xdeadbeef);
4610 bRet
= pRemoveFontMemResourceEx(ret
);
4611 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
4613 /* test invalid pointer to number of loaded fonts */
4614 font
= load_font("sserife.fon", &font_size
);
4615 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
4617 SetLastError(0xdeadbeef);
4618 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
4619 ok(!ret
, "AddFontMemResourceEx should fail\n");
4620 ok(GetLastError() == 0xdeadbeef,
4621 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4624 SetLastError(0xdeadbeef);
4625 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
4626 ok(!ret
, "AddFontMemResourceEx should fail\n");
4627 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4628 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4634 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4638 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4640 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4642 lf
= (LOGFONTA
*)lparam
;
4647 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4652 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4654 lf
= (LOGFONTA
*)lparam
;
4655 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
4658 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4665 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4670 static void test_EnumFonts(void)
4676 if (!is_truetype_font_installed("Arial"))
4678 skip("Arial is not installed\n");
4682 /* Windows uses localized font face names, so Arial Bold won't be found */
4683 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
4685 skip("User locale is not English, skipping the test\n");
4689 hdc
= CreateCompatibleDC(0);
4691 /* check that the enumproc's retval is returned */
4692 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
4693 ok(ret
== 0xcafe, "got %08x\n", ret
);
4695 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
4696 ok(!ret
, "font Arial is not enumerated\n");
4697 ret
= strcmp(lf
.lfFaceName
, "Arial");
4698 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4699 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4701 strcpy(lf
.lfFaceName
, "Arial");
4702 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4703 ok(!ret
, "font Arial is not enumerated\n");
4704 ret
= strcmp(lf
.lfFaceName
, "Arial");
4705 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4706 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4708 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4709 ok(!ret
, "font Arial Bold is not enumerated\n");
4710 ret
= strcmp(lf
.lfFaceName
, "Arial");
4711 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4712 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4714 strcpy(lf
.lfFaceName
, "Arial Bold");
4715 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4716 ok(ret
, "font Arial Bold should not be enumerated\n");
4718 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
4719 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
4720 ret
= strcmp(lf
.lfFaceName
, "Arial");
4721 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4722 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4724 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
4725 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4726 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
4728 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4729 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4731 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
4732 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4733 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4738 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4740 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
4741 const char *fullname
= (const char *)lParam
;
4743 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
4748 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
4753 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
4760 static void test_fullname(void)
4762 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4763 WCHAR bufW
[LF_FULLFACESIZE
];
4764 char bufA
[LF_FULLFACESIZE
];
4771 hdc
= CreateCompatibleDC(0);
4772 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4774 memset(&lf
, 0, sizeof(lf
));
4775 lf
.lfCharSet
= ANSI_CHARSET
;
4776 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4779 lf
.lfQuality
= DEFAULT_QUALITY
;
4780 lf
.lfItalic
= FALSE
;
4781 lf
.lfWeight
= FW_DONTCARE
;
4783 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
4785 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
4787 skip("%s is not installed\n", TestName
[i
]);
4791 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4792 hfont
= CreateFontIndirectA(&lf
);
4793 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4795 of
= SelectObject(hdc
, hfont
);
4798 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4799 ok(ret
, "face full name could not be read\n");
4800 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
4801 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
4802 SelectObject(hdc
, of
);
4803 DeleteObject(hfont
);
4808 static WCHAR
*prepend_at(WCHAR
*family
)
4813 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
4818 static void test_fullname2_helper(const char *Family
)
4820 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
4821 struct enum_fullname_data efnd
;
4828 DWORD otm_size
, ret
, buf_size
;
4829 OUTLINETEXTMETRICA
*otm
;
4830 BOOL want_vertical
, get_vertical
;
4831 want_vertical
= ( Family
[0] == '@' );
4833 hdc
= CreateCompatibleDC(0);
4834 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4836 memset(&lf
, 0, sizeof(lf
));
4837 lf
.lfCharSet
= DEFAULT_CHARSET
;
4838 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4841 lf
.lfQuality
= DEFAULT_QUALITY
;
4842 lf
.lfItalic
= FALSE
;
4843 lf
.lfWeight
= FW_DONTCARE
;
4844 strcpy(lf
.lfFaceName
, Family
);
4846 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4847 if (efnd
.total
== 0)
4848 skip("%s is not installed\n", lf
.lfFaceName
);
4850 for (i
= 0; i
< efnd
.total
; i
++)
4852 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
4853 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
4854 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
4856 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family
, FamilyName
, FaceName
, StyleName
);
4858 get_vertical
= ( FamilyName
[0] == '@' );
4859 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
4861 lstrcpyA(lf
.lfFaceName
, FaceName
);
4862 hfont
= CreateFontIndirectA(&lf
);
4863 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4865 of
= SelectObject(hdc
, hfont
);
4866 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
4867 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
4868 if (buf_size
== GDI_ERROR
) continue;
4870 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4871 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4873 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
4874 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
4875 memset(otm
, 0, otm_size
);
4876 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
4877 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
4878 if (ret
== 0) continue;
4882 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4885 trace("no localized FONT_FAMILY found.\n");
4886 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4888 ok(ret
, "FAMILY (family name) could not be read\n");
4889 if (want_vertical
) bufW
= prepend_at(bufW
);
4890 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4891 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
4892 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
4893 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
4897 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
4900 trace("no localized FULL_NAME found.\n");
4901 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4903 ok(ret
, "FULL_NAME (face name) could not be read\n");
4904 if (want_vertical
) bufW
= prepend_at(bufW
);
4905 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4906 ok(!lstrcmpA(FaceName
, bufA
), "font face names don't match: returned %s, expect %s\n", FaceName
, bufA
);
4907 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
4908 ok(!lstrcmpA(FaceName
, otmStr
), "FaceName %s doesn't match otmpFaceName %s\n", FaceName
, otmStr
);
4912 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4915 trace("no localized FONT_SUBFAMILY found.\n");
4916 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4918 ok(ret
, "SUBFAMILY (style name) could not be read\n");
4919 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4920 ok(!lstrcmpA(StyleName
, bufA
), "style names don't match: returned %s, expect %s\n", StyleName
, bufA
);
4921 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
4922 ok(!lstrcmpA(StyleName
, otmStr
), "StyleName %s doesn't match otmpStyleName %s\n", StyleName
, otmStr
);
4926 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
4929 trace("no localized UNIQUE_ID found.\n");
4930 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4932 ok(ret
, "UNIQUE_ID (full name) could not be read\n");
4933 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4934 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
4935 ok(!lstrcmpA(otmStr
, bufA
), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr
, bufA
);
4937 SelectObject(hdc
, of
);
4938 DeleteObject(hfont
);
4940 HeapFree(GetProcessHeap(), 0, otm
);
4941 HeapFree(GetProcessHeap(), 0, bufW
);
4942 HeapFree(GetProcessHeap(), 0, bufA
);
4947 static void test_fullname2(void)
4949 test_fullname2_helper("Arial");
4950 test_fullname2_helper("DejaVu Sans");
4951 test_fullname2_helper("Lucida Sans");
4952 test_fullname2_helper("Tahoma");
4953 test_fullname2_helper("Webdings");
4954 test_fullname2_helper("Wingdings");
4955 test_fullname2_helper("SimSun");
4956 test_fullname2_helper("NSimSun");
4957 test_fullname2_helper("MingLiu");
4958 test_fullname2_helper("PMingLiu");
4959 test_fullname2_helper("WenQuanYi Micro Hei");
4960 test_fullname2_helper("MS UI Gothic");
4961 test_fullname2_helper("Ume UI Gothic");
4962 test_fullname2_helper("MS Gothic");
4963 test_fullname2_helper("Ume Gothic");
4964 test_fullname2_helper("MS PGothic");
4965 test_fullname2_helper("Ume P Gothic");
4966 test_fullname2_helper("Gulim");
4967 test_fullname2_helper("Batang");
4968 test_fullname2_helper("UnBatang");
4969 test_fullname2_helper("UnDotum");
4970 test_fullname2_helper("@SimSun");
4971 test_fullname2_helper("@NSimSun");
4972 test_fullname2_helper("@MingLiu");
4973 test_fullname2_helper("@PMingLiu");
4974 test_fullname2_helper("@WenQuanYi Micro Hei");
4975 test_fullname2_helper("@MS UI Gothic");
4976 test_fullname2_helper("@Ume UI Gothic");
4977 test_fullname2_helper("@MS Gothic");
4978 test_fullname2_helper("@Ume Gothic");
4979 test_fullname2_helper("@MS PGothic");
4980 test_fullname2_helper("@Ume P Gothic");
4981 test_fullname2_helper("@Gulim");
4982 test_fullname2_helper("@Batang");
4983 test_fullname2_helper("@UnBatang");
4984 test_fullname2_helper("@UnDotum");
4988 static void test_GetGlyphOutline_empty_contour(void)
4992 HFONT hfont
, hfont_prev
;
4993 TTPOLYGONHEADER
*header
;
4998 memset(&lf
, 0, sizeof(lf
));
5000 lstrcpyA(lf
.lfFaceName
, "wine_test");
5002 hfont
= CreateFontIndirectA(&lf
);
5003 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5007 hfont_prev
= SelectObject(hdc
, hfont
);
5008 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5010 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5011 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5013 header
= (TTPOLYGONHEADER
*)buf
;
5014 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5015 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5016 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5017 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5018 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5019 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5020 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5021 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5023 SelectObject(hdc
, hfont_prev
);
5024 DeleteObject(hfont
);
5025 ReleaseDC(NULL
, hdc
);
5028 static void test_GetGlyphOutline_metric_clipping(void)
5032 HFONT hfont
, hfont_prev
;
5037 memset(&lf
, 0, sizeof(lf
));
5039 lstrcpyA(lf
.lfFaceName
, "wine_test");
5041 SetLastError(0xdeadbeef);
5042 hfont
= CreateFontIndirectA(&lf
);
5043 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5047 hfont_prev
= SelectObject(hdc
, hfont
);
5048 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5050 SetLastError(0xdeadbeef);
5051 ret
= GetTextMetricsA(hdc
, &tm
);
5052 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5054 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5055 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5056 "Glyph top(%d) exceeds ascent(%d)\n",
5057 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5058 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5059 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5060 "Glyph bottom(%d) exceeds descent(%d)\n",
5061 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5063 SelectObject(hdc
, hfont_prev
);
5064 DeleteObject(hfont
);
5065 ReleaseDC(NULL
, hdc
);
5068 static void test_CreateScalableFontResource(void)
5070 char ttf_name
[MAX_PATH
];
5071 char tmp_path
[MAX_PATH
];
5072 char fot_name
[MAX_PATH
];
5077 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
5079 win_skip("AddFontResourceExA is not available on this platform\n");
5083 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5085 skip("Failed to create ttf file for testing\n");
5089 trace("created %s\n", ttf_name
);
5091 ret
= is_truetype_font_installed("wine_test");
5092 ok(!ret
, "font wine_test should not be enumerated\n");
5094 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
5095 ok(ret
, "GetTempPath() error %d\n", GetLastError());
5096 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
5097 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
5099 ret
= GetFileAttributesA(fot_name
);
5100 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
5102 SetLastError(0xdeadbeef);
5103 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5104 ok(!ret
, "CreateScalableFontResource() should fail\n");
5105 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5107 SetLastError(0xdeadbeef);
5108 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
5109 ok(!ret
, "CreateScalableFontResource() should fail\n");
5110 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5112 file_part
= strrchr(ttf_name
, '\\');
5113 SetLastError(0xdeadbeef);
5114 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
5115 ok(!ret
, "CreateScalableFontResource() should fail\n");
5116 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5118 SetLastError(0xdeadbeef);
5119 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
5120 ok(!ret
, "CreateScalableFontResource() should fail\n");
5121 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5123 SetLastError(0xdeadbeef);
5124 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
5125 ok(!ret
, "CreateScalableFontResource() should fail\n");
5126 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5128 ret
= DeleteFileA(fot_name
);
5129 ok(ret
, "DeleteFile() error %d\n", GetLastError());
5131 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5132 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5134 /* test public font resource */
5135 SetLastError(0xdeadbeef);
5136 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5137 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5139 ret
= is_truetype_font_installed("wine_test");
5140 ok(!ret
, "font wine_test should not be enumerated\n");
5142 SetLastError(0xdeadbeef);
5143 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5144 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5146 ret
= is_truetype_font_installed("wine_test");
5147 ok(ret
, "font wine_test should be enumerated\n");
5149 test_GetGlyphOutline_empty_contour();
5150 test_GetGlyphOutline_metric_clipping();
5152 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5153 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
5155 SetLastError(0xdeadbeef);
5156 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5157 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5159 ret
= is_truetype_font_installed("wine_test");
5160 ok(!ret
, "font wine_test should not be enumerated\n");
5162 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5163 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5165 /* test refcounting */
5166 for (i
= 0; i
< 5; i
++)
5168 SetLastError(0xdeadbeef);
5169 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5170 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5172 for (i
= 0; i
< 5; i
++)
5174 SetLastError(0xdeadbeef);
5175 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5176 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5178 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5179 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5181 DeleteFileA(fot_name
);
5183 /* test hidden font resource */
5184 SetLastError(0xdeadbeef);
5185 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
5186 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5188 ret
= is_truetype_font_installed("wine_test");
5189 ok(!ret
, "font wine_test should not be enumerated\n");
5191 SetLastError(0xdeadbeef);
5192 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5193 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5195 ret
= is_truetype_font_installed("wine_test");
5197 ok(!ret
, "font wine_test should not be enumerated\n");
5199 /* XP allows removing a private font added with 0 flags */
5200 SetLastError(0xdeadbeef);
5201 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5202 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5204 ret
= is_truetype_font_installed("wine_test");
5205 ok(!ret
, "font wine_test should not be enumerated\n");
5207 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5208 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5210 DeleteFileA(fot_name
);
5211 DeleteFileA(ttf_name
);
5214 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
5217 HFONT hfont
, hfont_prev
;
5221 static const WCHAR str
[] = { 0x2025 };
5223 *installed
= is_truetype_font_installed(name
);
5227 lf
.lfEscapement
= 0;
5228 lf
.lfOrientation
= 0;
5229 lf
.lfWeight
= FW_DONTCARE
;
5233 lf
.lfCharSet
= DEFAULT_CHARSET
;
5234 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
5235 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5236 lf
.lfQuality
= DEFAULT_QUALITY
;
5237 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
5238 strcpy(lf
.lfFaceName
, name
);
5240 hfont
= CreateFontIndirectA(&lf
);
5241 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
5245 hfont_prev
= SelectObject(hdc
, hfont
);
5246 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5248 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
5249 ok(ret
, "GetTextFaceA failed\n");
5250 *selected
= !strcmp(facename
, name
);
5252 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
5253 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5255 memset(gm
, 0, sizeof *gm
);
5257 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
5258 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
5260 SelectObject(hdc
, hfont_prev
);
5261 DeleteObject(hfont
);
5262 ReleaseDC(NULL
, hdc
);
5265 static void check_vertical_metrics(const char *face
)
5268 HFONT hfont
, hfont_prev
;
5271 GLYPHMETRICS rgm
, vgm
;
5272 const UINT code
= 0x5EAD, height
= 1000;
5275 OUTLINETEXTMETRICA otm
;
5276 USHORT numOfLongVerMetrics
;
5280 memset(&lf
, 0, sizeof(lf
));
5281 strcpy(lf
.lfFaceName
, face
);
5282 lf
.lfHeight
= -height
;
5283 lf
.lfCharSet
= DEFAULT_CHARSET
;
5284 lf
.lfEscapement
= lf
.lfOrientation
= 900;
5285 hfont
= CreateFontIndirectA(&lf
);
5286 hfont_prev
= SelectObject(hdc
, hfont
);
5287 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
5288 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5289 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
5290 ok(ret
, "GetCharABCWidthsW failed\n");
5291 DeleteObject(SelectObject(hdc
, hfont_prev
));
5293 memset(&lf
, 0, sizeof(lf
));
5294 strcpy(lf
.lfFaceName
, "@");
5295 strcat(lf
.lfFaceName
, face
);
5296 lf
.lfHeight
= -height
;
5297 lf
.lfCharSet
= DEFAULT_CHARSET
;
5298 hfont
= CreateFontIndirectA(&lf
);
5299 hfont_prev
= SelectObject(hdc
, hfont
);
5300 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
5301 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5303 memset(&otm
, 0, sizeof(otm
));
5304 otm
.otmSize
= sizeof(otm
);
5305 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
5306 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
5308 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
5309 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
5311 SHORT topSideBearing
;
5313 if (!pGetGlyphIndicesW
) {
5314 win_skip("GetGlyphIndices is not available on this platform\n");
5317 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
5318 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
5319 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
5320 if (numOfLongVerMetrics
> idx
)
5321 offset
= idx
* 2 + 1;
5323 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
5324 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
5325 &topSideBearing
, sizeof(SHORT
));
5326 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
5327 topSideBearing
= GET_BE_WORD(topSideBearing
);
5328 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
5329 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
5330 "expected %d, got %d\n",
5331 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
5336 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
5337 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5338 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
5341 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
5342 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
5343 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5344 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
5346 DeleteObject(SelectObject(hdc
, hfont_prev
));
5347 ReleaseDC(NULL
, hdc
);
5350 static void test_vertical_font(void)
5352 char ttf_name
[MAX_PATH
];
5354 BOOL ret
, installed
, selected
;
5357 const char* face_list
[] = {
5358 "@WineTestVertical", /* has vmtx table */
5359 "@Ume Gothic", /* doesn't have vmtx table */
5360 "@MS UI Gothic", /* has vmtx table, available on native */
5363 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
5365 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5369 if (!write_ttf_file("vertical.ttf", ttf_name
))
5371 skip("Failed to create ttf file for testing\n");
5375 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5376 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5378 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
5379 ok(installed
, "WineTestVertical is not installed\n");
5380 ok(selected
, "WineTestVertical is not selected\n");
5381 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5382 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5383 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5385 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
5386 ok(installed
, "@WineTestVertical is not installed\n");
5387 ok(selected
, "@WineTestVertical is not selected\n");
5388 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5389 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5390 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5392 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
5394 for (i
= 0; i
< sizeof(face_list
)/sizeof(face_list
[0]); i
++) {
5395 const char* face
= face_list
[i
];
5396 if (!is_truetype_font_installed(face
)) {
5397 skip("%s is not installed\n", face
);
5400 trace("Testing %s...\n", face
);
5401 check_vertical_metrics(&face
[1]);
5404 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5405 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5407 DeleteFileA(ttf_name
);
5410 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
5411 DWORD type
, LPARAM lParam
)
5413 if (lf
->lfFaceName
[0] == '@') {
5419 static void test_east_asian_font_selection(void)
5422 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
5423 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
5428 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
5432 char face_name
[LF_FACESIZE
];
5435 memset(&lf
, 0, sizeof lf
);
5436 lf
.lfFaceName
[0] = '\0';
5437 lf
.lfCharSet
= charset
[i
];
5439 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
5441 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
5445 hfont
= CreateFontIndirectA(&lf
);
5446 hfont
= SelectObject(hdc
, hfont
);
5447 memset(face_name
, 0, sizeof face_name
);
5448 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5449 ok(ret
&& face_name
[0] != '@',
5450 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5451 DeleteObject(SelectObject(hdc
, hfont
));
5453 memset(&lf
, 0, sizeof lf
);
5454 strcpy(lf
.lfFaceName
, "@");
5455 lf
.lfCharSet
= charset
[i
];
5456 hfont
= CreateFontIndirectA(&lf
);
5457 hfont
= SelectObject(hdc
, hfont
);
5458 memset(face_name
, 0, sizeof face_name
);
5459 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5460 ok(ret
&& face_name
[0] == '@',
5461 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5462 DeleteObject(SelectObject(hdc
, hfont
));
5464 ReleaseDC(NULL
, hdc
);
5467 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
5469 HDC hdc
= CreateCompatibleDC(0);
5474 hfont
= CreateFontIndirectA(lf
);
5475 ok(hfont
!= 0, "CreateFontIndirect failed\n");
5477 SelectObject(hdc
, hfont
);
5478 ret
= GetTextMetricsA(hdc
, &tm
);
5479 ok(ret
, "GetTextMetrics failed\n");
5480 ret
= tm
.tmDigitizedAspectX
;
5481 if (height
) *height
= tm
.tmHeight
;
5484 DeleteObject(hfont
);
5489 static void test_stock_fonts(void)
5491 static const int font
[] =
5493 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
5494 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5496 static const struct test_data
5498 int charset
, weight
, height
, height_pixels
, dpi
;
5499 const char face_name
[LF_FACESIZE
];
5502 { /* ANSI_FIXED_FONT */
5503 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
5504 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
5507 { /* ANSI_VAR_FONT */
5508 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
5509 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
5513 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5514 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5515 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5516 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5517 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5518 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5521 { /* DEVICE_DEFAULT_FONT */
5522 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5523 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5524 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5525 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5526 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5527 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5530 { /* DEFAULT_GUI_FONT */
5531 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
5532 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
5533 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
5534 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
5535 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
5536 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
5537 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
5538 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
5539 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
5540 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
5546 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
5552 hfont
= GetStockObject(font
[i
]);
5553 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
5555 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
5556 if (ret
!= sizeof(lf
))
5559 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
5563 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
5565 if (lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
)
5570 ret
= get_font_dpi(&lf
, &height
);
5571 if (ret
!= td
[i
][j
].dpi
)
5573 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5574 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
5578 /* FIXME: Remove once Wine is fixed */
5579 if (td
[i
][j
].dpi
!= 96 &&
5580 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5581 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
5582 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5583 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
5585 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5587 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5589 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
5590 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
5591 if (td
[i
][j
].face_name
[0] == '?')
5593 /* Wine doesn't have this font, skip this case for now.
5594 Actually, the face name is localized on Windows and varies
5595 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5596 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
5600 ok(!strcmp(td
[i
][j
].face_name
, lf
.lfFaceName
), "%d(%d): expected lfFaceName %s, got %s\n", i
, j
, td
[i
][j
].face_name
, lf
.lfFaceName
);
5607 static void test_max_height(void)
5611 HFONT hfont
, hfont_old
;
5612 TEXTMETRICA tm1
, tm
;
5614 LONG invalid_height
[] = { -65536, -123456, 123456 };
5617 memset(&tm1
, 0, sizeof(tm1
));
5618 memset(&lf
, 0, sizeof(lf
));
5619 strcpy(lf
.lfFaceName
, "Tahoma");
5624 /* get 1 ppem value */
5625 hfont
= CreateFontIndirectA(&lf
);
5626 hfont_old
= SelectObject(hdc
, hfont
);
5627 r
= GetTextMetricsA(hdc
, &tm1
);
5628 ok(r
, "GetTextMetrics failed\n");
5629 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5630 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5631 DeleteObject(SelectObject(hdc
, hfont_old
));
5633 /* test the largest value */
5634 lf
.lfHeight
= -((1 << 16) - 1);
5635 hfont
= CreateFontIndirectA(&lf
);
5636 hfont_old
= SelectObject(hdc
, hfont
);
5637 memset(&tm
, 0, sizeof(tm
));
5638 r
= GetTextMetricsA(hdc
, &tm
);
5639 ok(r
, "GetTextMetrics failed\n");
5640 ok(tm
.tmHeight
> tm1
.tmHeight
,
5641 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5642 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
5643 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5644 DeleteObject(SelectObject(hdc
, hfont_old
));
5646 /* test an invalid value */
5647 for (i
= 0; i
< sizeof(invalid_height
)/sizeof(invalid_height
[0]); i
++) {
5648 lf
.lfHeight
= invalid_height
[i
];
5649 hfont
= CreateFontIndirectA(&lf
);
5650 hfont_old
= SelectObject(hdc
, hfont
);
5651 memset(&tm
, 0, sizeof(tm
));
5652 r
= GetTextMetricsA(hdc
, &tm
);
5653 ok(r
, "GetTextMetrics failed\n");
5654 ok(tm
.tmHeight
== tm1
.tmHeight
,
5655 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5656 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
5657 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5658 DeleteObject(SelectObject(hdc
, hfont_old
));
5661 ReleaseDC(NULL
, hdc
);
5665 static void test_vertical_order(void)
5667 struct enum_font_data efd
;
5672 hdc
= CreateCompatibleDC(0);
5673 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5675 memset(&lf
, 0, sizeof(lf
));
5676 lf
.lfCharSet
= DEFAULT_CHARSET
;
5677 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5680 lf
.lfQuality
= DEFAULT_QUALITY
;
5681 lf
.lfItalic
= FALSE
;
5682 lf
.lfWeight
= FW_DONTCARE
;
5684 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
5685 for (i
= 0; i
< efd
.total
; i
++)
5687 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
5688 for (j
= 0; j
< efd
.total
; j
++)
5690 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
5692 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
5700 static void test_GetCharWidth32(void)
5710 if (!pGetCharWidth32A
|| !pGetCharWidth32W
)
5712 win_skip("GetCharWidth32A/W not available on this platform\n");
5716 memset(&lf
, 0, sizeof(lf
));
5717 strcpy(lf
.lfFaceName
, "System");
5720 hfont
= CreateFontIndirectA(&lf
);
5722 hfont
= SelectObject(hdc
, hfont
);
5724 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5725 ok(ret
, "GetCharWidth32W should have succeeded\n");
5726 ret
= pGetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
5727 ok(ret
, "GetCharWidth32A should have succeeded\n");
5728 ok (bufferA
== bufferW
, "Widths should be the same\n");
5729 ok (bufferA
> 0," Width should be greater than zero\n");
5731 hfont
= SelectObject(hdc
, hfont
);
5732 DeleteObject(hfont
);
5733 ReleaseDC(NULL
, hdc
);
5735 memset(&lf
, 0, sizeof(lf
));
5736 strcpy(lf
.lfFaceName
, "Tahoma");
5739 hfont
= CreateFontIndirectA(&lf
);
5740 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
5743 SetMapMode( hdc
, MM_ANISOTROPIC
);
5744 SelectObject(hdc
, hfont
);
5746 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5747 ok(ret
, "GetCharWidth32W should have succeeded\n");
5748 ok (bufferW
> 0," Width should be greater than zero\n");
5749 SetWindowExtEx(hdc
, -1,-1,NULL
);
5750 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5751 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5752 ok(ret
, "GetCharWidth32W should have succeeded\n");
5753 ok (bufferW
> 0," Width should be greater than zero\n");
5754 SetGraphicsMode(hdc
, GM_ADVANCED
);
5755 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5756 ok(ret
, "GetCharWidth32W should have succeeded\n");
5757 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
5758 SetWindowExtEx(hdc
, 1,1,NULL
);
5759 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5760 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5761 ok(ret
, "GetCharWidth32W should have succeeded\n");
5762 ok (bufferW
> 0," Width should be greater than zero\n");
5763 SetGraphicsMode(hdc
, GM_ADVANCED
);
5764 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5765 ok(ret
, "GetCharWidth32W should have succeeded\n");
5766 ok (bufferW
> 0," Width should be greater than zero\n");
5768 ReleaseDC(hwnd
, hdc
);
5769 DestroyWindow(hwnd
);
5771 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
5774 SetMapMode( hdc
, MM_ANISOTROPIC
);
5775 SelectObject(hdc
, hfont
);
5777 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5778 ok(ret
, "GetCharWidth32W should have succeeded\n");
5779 ok (bufferW
> 0," Width should be greater than zero\n");
5780 SetWindowExtEx(hdc
, -1,-1,NULL
);
5781 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5782 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5783 ok(ret
, "GetCharWidth32W should have succeeded\n");
5784 ok (bufferW
> 0," Width should be greater than zero\n");
5785 SetGraphicsMode(hdc
, GM_ADVANCED
);
5786 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5787 ok(ret
, "GetCharWidth32W should have succeeded\n");
5788 ok (bufferW
> 0," Width should be greater than zero\n");
5789 SetWindowExtEx(hdc
, 1,1,NULL
);
5790 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5791 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5792 ok(ret
, "GetCharWidth32W should have succeeded\n");
5793 ok (bufferW
> 0," Width should be greater than zero\n");
5794 SetGraphicsMode(hdc
, GM_ADVANCED
);
5795 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5796 ok(ret
, "GetCharWidth32W should have succeeded\n");
5797 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
5799 ReleaseDC(hwnd
, hdc
);
5800 DestroyWindow(hwnd
);
5801 DeleteObject(hfont
);
5804 static void test_fake_bold_font(void)
5807 HFONT hfont
, hfont_old
;
5814 if (!pGetCharWidth32A
|| !pGetCharABCWidthsA
) {
5815 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
5819 /* Test outline font */
5820 memset(&lf
, 0, sizeof(lf
));
5821 strcpy(lf
.lfFaceName
, "Wingdings");
5822 lf
.lfWeight
= FW_NORMAL
;
5823 lf
.lfCharSet
= SYMBOL_CHARSET
;
5824 hfont
= CreateFontIndirectA(&lf
);
5827 hfont_old
= SelectObject(hdc
, hfont
);
5830 ret
= GetTextMetricsA(hdc
, &tm
[0]);
5831 ok(ret
, "got %d\n", ret
);
5832 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[0]);
5833 ok(ret
, "got %d\n", ret
);
5835 lf
.lfWeight
= FW_BOLD
;
5836 hfont
= CreateFontIndirectA(&lf
);
5837 DeleteObject(SelectObject(hdc
, hfont
));
5840 ret
= GetTextMetricsA(hdc
, &tm
[1]);
5841 ok(ret
, "got %d\n", ret
);
5842 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[1]);
5843 ok(ret
, "got %d\n", ret
);
5845 DeleteObject(SelectObject(hdc
, hfont_old
));
5846 ReleaseDC(NULL
, hdc
);
5848 /* compare results (outline) */
5849 ok(tm
[0].tmHeight
== tm
[1].tmHeight
, "expected %d, got %d\n", tm
[0].tmHeight
, tm
[1].tmHeight
);
5850 ok(tm
[0].tmAscent
== tm
[1].tmAscent
, "expected %d, got %d\n", tm
[0].tmAscent
, tm
[1].tmAscent
);
5851 ok(tm
[0].tmDescent
== tm
[1].tmDescent
, "expected %d, got %d\n", tm
[0].tmDescent
, tm
[1].tmDescent
);
5852 ok((tm
[0].tmAveCharWidth
+ 1) == tm
[1].tmAveCharWidth
,
5853 "expected %d, got %d\n", tm
[0].tmAveCharWidth
+ 1, tm
[1].tmAveCharWidth
);
5854 ok((tm
[0].tmMaxCharWidth
+ 1) == tm
[1].tmMaxCharWidth
,
5855 "expected %d, got %d\n", tm
[0].tmMaxCharWidth
+ 1, tm
[1].tmMaxCharWidth
);
5856 ok(tm
[0].tmOverhang
== tm
[1].tmOverhang
, "expected %d, got %d\n", tm
[0].tmOverhang
, tm
[1].tmOverhang
);
5857 w
[0] = abc
[0].abcA
+ abc
[0].abcB
+ abc
[0].abcC
;
5858 w
[1] = abc
[1].abcA
+ abc
[1].abcB
+ abc
[1].abcC
;
5859 ok((w
[0] + 1) == w
[1], "expected %d, got %d\n", w
[0] + 1, w
[1]);
5863 static void test_bitmap_font_glyph_index(void)
5865 const WCHAR text
[] = {'#','!','/','b','i','n','/','s','h',0};
5869 } bitmap_font_list
[] = {
5870 { "Courier", ANSI_CHARSET
},
5871 { "Small Fonts", ANSI_CHARSET
},
5872 { "Fixedsys", DEFAULT_CHARSET
},
5873 { "System", DEFAULT_CHARSET
}
5878 CHAR facename
[LF_FACESIZE
];
5889 if (!pGetGlyphIndicesW
|| !pGetGlyphIndicesA
) {
5890 win_skip("GetGlyphIndices is unavailable\n");
5894 hdc
= CreateCompatibleDC(0);
5895 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5897 memset(&bmi
, 0, sizeof(bmi
));
5898 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
5899 bmi
.bmiHeader
.biBitCount
= 32;
5900 bmi
.bmiHeader
.biPlanes
= 1;
5901 bmi
.bmiHeader
.biWidth
= 128;
5902 bmi
.bmiHeader
.biHeight
= 32;
5903 bmi
.bmiHeader
.biCompression
= BI_RGB
;
5905 for (i
= 0; i
< sizeof(bitmap_font_list
)/sizeof(bitmap_font_list
[0]); i
++) {
5906 memset(&lf
, 0, sizeof(lf
));
5907 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
5908 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
5909 hFont
= CreateFontIndirectA(&lf
);
5910 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
5911 hFont
= SelectObject(hdc
, hFont
);
5912 ret
= GetTextMetricsA(hdc
, &tm
);
5913 ok(ret
, "GetTextMetric failed\n");
5914 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
5915 ok(ret
, "GetTextFace failed\n");
5916 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
5917 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
5920 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
5921 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
5925 for (j
= 0; j
< 2; j
++) {
5927 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
5928 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
5929 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
5932 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
5936 int len
= lstrlenW(text
);
5937 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
5938 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
5939 ok(ret
, "GetGlyphIndices failed\n");
5940 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
5941 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
5942 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
5943 HeapFree(GetProcessHeap(), 0, indices
);
5947 ok(ret
, "ExtTextOutW failed\n");
5948 SelectObject(hdc
, hBmpPrev
);
5951 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
5952 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
5953 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
5955 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
5957 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
5960 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
5961 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
5965 for (j
= 0; j
< 2; j
++) {
5968 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
5971 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
5974 ret
= pGetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
5975 ok(ret
, "GetGlyphIndices failed\n");
5976 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
5977 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
5980 ok(ret
, "ExtTextOutA failed\n");
5981 SelectObject(hdc
, hBmpPrev
);
5984 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
5985 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
5987 for (j
= 0; j
< 2; j
++)
5988 DeleteObject(hBmp
[j
]);
5989 hFont
= SelectObject(hdc
, hFont
);
5990 DeleteObject(hFont
);
6003 test_outline_font();
6004 test_bitmap_font_metrics();
6005 test_GdiGetCharDimensions();
6006 test_GetCharABCWidths();
6007 test_text_extents();
6008 test_GetGlyphIndices();
6009 test_GetKerningPairs();
6010 test_GetOutlineTextMetrics();
6011 test_SetTextJustification();
6012 test_font_charset();
6013 test_GdiGetCodePage();
6014 test_GetFontUnicodeRanges();
6015 test_nonexistent_font();
6017 test_height_selection();
6018 test_AddFontMemResource();
6021 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6022 * I'd like to avoid them in this test.
6024 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
6025 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
6026 if (is_truetype_font_installed("Arial Black") &&
6027 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6029 test_EnumFontFamilies("", ANSI_CHARSET
);
6030 test_EnumFontFamilies("", SYMBOL_CHARSET
);
6031 test_EnumFontFamilies("", DEFAULT_CHARSET
);
6034 skip("Arial Black or Symbol/Wingdings is not installed\n");
6035 test_EnumFontFamiliesEx_default_charset();
6036 test_GetTextMetrics();
6037 test_GdiRealizationInfo();
6039 test_GetGlyphOutline();
6040 test_GetTextMetrics2("Tahoma", -11);
6041 test_GetTextMetrics2("Tahoma", -55);
6042 test_GetTextMetrics2("Tahoma", -110);
6043 test_GetTextMetrics2("Arial", -11);
6044 test_GetTextMetrics2("Arial", -55);
6045 test_GetTextMetrics2("Arial", -110);
6046 test_CreateFontIndirect();
6047 test_CreateFontIndirectEx();
6051 test_east_asian_font_selection();
6053 test_vertical_order();
6054 test_GetCharWidth32();
6055 test_fake_bold_font();
6056 test_bitmap_font_glyph_index();
6058 /* These tests should be last test until RemoveFontResource
6059 * is properly implemented.
6061 test_vertical_font();
6062 test_CreateScalableFontResource();