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 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
964 if (fd
[i
].height
& FH_SCALE
)
965 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
968 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
970 if (ret
) /* FIXME: Remove once Wine is fixed */
971 todo_wine
ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
973 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
976 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
979 hfont
= create_font(lf
.lfFaceName
, &lf
);
980 old_hfont
= SelectObject(hdc
, hfont
);
982 SetLastError(0xdeadbeef);
983 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
984 ok(ret
, "GetTextFace error %u\n", GetLastError());
986 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
988 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
989 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
990 SelectObject(hdc
, old_hfont
);
995 memset(&gm
, 0, sizeof(gm
));
996 SetLastError(0xdeadbeef);
997 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
999 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
1000 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1003 bRet
= GetTextMetricsA(hdc
, &tm
);
1004 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
1006 SetLastError(0xdeadbeef);
1007 ret
= GetTextCharset(hdc
);
1008 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1009 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1011 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1013 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
1014 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
1016 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1018 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1019 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
1021 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1022 if (fd
[i
].height
& FH_SCALE
)
1023 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
);
1025 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
);
1026 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1027 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1028 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
);
1029 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
);
1030 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
);
1031 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1032 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1033 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1034 make default char test fail */
1035 if (tm
.tmCharSet
== lf
.lfCharSet
)
1036 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1037 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1038 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
);
1040 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1041 that make the max width bigger */
1042 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1043 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
);
1046 skip("Skipping font metrics test for system langid 0x%x\n",
1049 SelectObject(hdc
, old_hfont
);
1050 DeleteObject(hfont
);
1057 static void test_GdiGetCharDimensions(void)
1063 LONG avgwidth
, height
;
1064 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1066 if (!pGdiGetCharDimensions
)
1068 win_skip("GdiGetCharDimensions not available on this platform\n");
1072 hdc
= CreateCompatibleDC(NULL
);
1074 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1075 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1077 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1078 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1079 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1081 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1082 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1084 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1085 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1088 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1089 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1090 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1095 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1096 const TEXTMETRICA
*lpntme
,
1097 DWORD FontType
, LPARAM lParam
)
1099 if (FontType
& TRUETYPE_FONTTYPE
)
1103 hfont
= CreateFontIndirectA(lpelfe
);
1106 *(HFONT
*)lParam
= hfont
;
1114 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, ABC
*base_abci
, ABC
*base_abcw
, ABCFLOAT
*base_abcf
, INT todo
)
1120 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1121 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1122 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1123 if (todo
) todo_wine
ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1124 else ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1125 if (todo
) todo_wine
ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1126 else ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1128 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1129 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1130 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1131 if (todo
) todo_wine
ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1132 else ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1133 if (todo
) todo_wine
ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1134 else ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's should be unchanged\n", description
);
1136 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1137 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1138 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1139 if (todo
) todo_wine
ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1140 else ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's should be unchanged\n", description
);
1141 if (todo
) todo_wine
ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1142 else ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1145 static void test_GetCharABCWidths(void)
1147 static const WCHAR str
[] = {'i',0};
1171 {0xffffff, 0xffffff},
1172 {0x1000000, 0x1000000},
1173 {0xffffff, 0x1000000},
1174 {0xffffffff, 0xffffffff},
1182 BOOL r
[sizeof range
/ sizeof range
[0]];
1185 {ANSI_CHARSET
, 0x30, 0x30,
1186 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1187 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1188 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1189 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1190 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1191 {GB2312_CHARSET
, 0x8141, 0x4e04,
1192 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1193 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1194 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1198 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1200 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1204 memset(&lf
, 0, sizeof(lf
));
1205 strcpy(lf
.lfFaceName
, "System");
1208 hfont
= CreateFontIndirectA(&lf
);
1210 hfont
= SelectObject(hdc
, hfont
);
1212 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1213 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1215 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1216 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1218 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1219 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1221 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1222 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1224 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1225 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1227 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1228 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1230 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1231 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1233 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1234 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1236 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1237 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1239 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1240 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1242 hfont
= SelectObject(hdc
, hfont
);
1243 DeleteObject(hfont
);
1245 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1249 UINT code
= 0x41, j
;
1251 lf
.lfFaceName
[0] = '\0';
1252 lf
.lfCharSet
= c
[i
].cs
;
1253 lf
.lfPitchAndFamily
= 0;
1254 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1256 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1260 memset(a
, 0, sizeof a
);
1261 memset(w
, 0, sizeof w
);
1262 hfont
= SelectObject(hdc
, hfont
);
1263 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1264 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1265 memcmp(a
, w
, sizeof a
) == 0,
1266 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1268 memset(a
, 0xbb, sizeof a
);
1269 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1270 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1271 memset(full
, 0xcc, sizeof full
);
1272 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1273 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1274 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1275 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1277 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1279 memset(full
, 0xdd, sizeof full
);
1280 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1281 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1282 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1285 UINT last
= range
[j
].last
- range
[j
].first
;
1286 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1287 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1288 "GetCharABCWidthsA %x should match. codepage = %u\n",
1289 range
[j
].last
, c
[i
].cs
);
1293 hfont
= SelectObject(hdc
, hfont
);
1294 DeleteObject(hfont
);
1297 memset(&lf
, 0, sizeof(lf
));
1298 strcpy(lf
.lfFaceName
, "Tahoma");
1300 hfont
= CreateFontIndirectA(&lf
);
1302 /* test empty glyph's metrics */
1303 hfont
= SelectObject(hdc
, hfont
);
1304 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1305 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1306 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1307 ret
= pGetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1308 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1309 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1311 /* 1) prepare unrotated font metrics */
1312 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1313 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1314 DeleteObject(SelectObject(hdc
, hfont
));
1316 /* 2) get rotated font metrics */
1317 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1318 hfont
= CreateFontIndirectA(&lf
);
1319 hfont
= SelectObject(hdc
, hfont
);
1320 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1321 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1323 /* 3) compare ABC results */
1324 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1325 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1326 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1327 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1328 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1329 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1331 DeleteObject(SelectObject(hdc
, hfont
));
1332 ReleaseDC(NULL
, hdc
);
1334 trace("ABC sign test for a variety of transforms:\n");
1335 memset(&lf
, 0, sizeof(lf
));
1336 strcpy(lf
.lfFaceName
, "Tahoma");
1338 hfont
= CreateFontIndirectA(&lf
);
1339 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1342 SetMapMode(hdc
, MM_ANISOTROPIC
);
1343 SelectObject(hdc
, hfont
);
1345 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1346 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1348 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1349 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1350 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1351 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1352 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1353 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1355 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1356 SetWindowExtEx(hdc
, -1, -1, NULL
);
1357 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1358 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1359 SetGraphicsMode(hdc
, GM_ADVANCED
);
1360 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1361 SetWindowExtEx(hdc
, 1, 1, NULL
);
1362 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1363 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1364 SetGraphicsMode(hdc
, GM_ADVANCED
);
1365 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1367 ReleaseDC(hwnd
, hdc
);
1368 DestroyWindow(hwnd
);
1370 trace("RTL layout\n");
1371 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1374 SetMapMode(hdc
, MM_ANISOTROPIC
);
1375 SelectObject(hdc
, hfont
);
1377 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1378 SetWindowExtEx(hdc
, -1, -1, NULL
);
1379 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1380 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1381 SetGraphicsMode(hdc
, GM_ADVANCED
);
1382 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1383 SetWindowExtEx(hdc
, 1, 1, NULL
);
1384 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1385 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1386 SetGraphicsMode(hdc
, GM_ADVANCED
);
1387 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1389 ReleaseDC(hwnd
, hdc
);
1390 DestroyWindow(hwnd
);
1391 DeleteObject(hfont
);
1394 static void test_text_extents(void)
1396 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1398 INT i
, len
, fit1
, fit2
, extents2
[3];
1407 memset(&lf
, 0, sizeof(lf
));
1408 strcpy(lf
.lfFaceName
, "Arial");
1411 hfont
= CreateFontIndirectA(&lf
);
1413 hfont
= SelectObject(hdc
, hfont
);
1414 GetTextMetricsA(hdc
, &tm
);
1415 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1416 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1418 SetLastError(0xdeadbeef);
1419 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1420 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1422 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1423 hfont
= SelectObject(hdc
, hfont
);
1424 DeleteObject(hfont
);
1430 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1431 extents
[0] = 1; /* So that the increasing sequence test will fail
1432 if the extents array is untouched. */
1433 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1434 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1435 ok(sz1
.cy
== sz2
.cy
,
1436 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1437 /* Because of the '\n' in the string GetTextExtentExPoint and
1438 GetTextExtentPoint return different widths under Win2k, but
1439 under WinXP they return the same width. So we don't test that
1442 for (i
= 1; i
< len
; ++i
)
1443 ok(extents
[i
-1] <= extents
[i
],
1444 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1446 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1447 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1448 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1449 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1450 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1451 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1452 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1453 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1455 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1456 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1457 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1458 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1459 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1461 /* extents functions fail with -ve counts (the interesting case being -1) */
1462 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1463 ok(ret
== FALSE
, "got %d\n", ret
);
1464 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1465 ok(ret
== FALSE
, "got %d\n", ret
);
1466 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1467 ok(ret
== FALSE
, "got %d\n", ret
);
1469 /* max_extent = 0 succeeds and returns zero */
1471 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1473 broken(ret
== FALSE
), /* NT4, 2k */
1476 broken(fit1
== -215), /* NT4, 2k */
1477 "fit = %d\n", fit1
);
1478 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1479 ok(ret
== TRUE
, "got %d\n", ret
);
1480 ok(fit2
== 0, "fit = %d\n", fit2
);
1482 /* max_extent = -1 is interpreted as a very large width that will
1483 * definitely fit our three characters */
1485 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1486 ok(ret
== TRUE
, "got %d\n", ret
);
1487 ok(fit1
== 3, "fit = %d\n", fit1
);
1488 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1489 ok(ret
== TRUE
, "got %d\n", ret
);
1490 ok(fit2
== 3, "fit = %d\n", fit2
);
1492 /* max_extent = -2 is interpreted similarly, but the Ansi version
1493 * rejects it while the Unicode one accepts it */
1495 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1496 ok(ret
== FALSE
, "got %d\n", ret
);
1497 ok(fit1
== -215, "fit = %d\n", fit1
);
1498 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1499 ok(ret
== TRUE
, "got %d\n", ret
);
1500 ok(fit2
== 3, "fit = %d\n", fit2
);
1502 hfont
= SelectObject(hdc
, hfont
);
1503 DeleteObject(hfont
);
1505 /* non-MM_TEXT mapping mode */
1507 hfont
= CreateFontIndirectA(&lf
);
1508 hfont
= SelectObject(hdc
, hfont
);
1510 SetMapMode( hdc
, MM_HIMETRIC
);
1511 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1512 ok(ret
, "got %d\n", ret
);
1513 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1515 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1516 ok(ret
, "got %d\n", ret
);
1517 ok(fit1
== 2, "got %d\n", fit1
);
1518 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1519 for(i
= 0; i
< 2; i
++)
1520 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1522 hfont
= SelectObject(hdc
, hfont
);
1523 DeleteObject(hfont
);
1524 HeapFree(GetProcessHeap(), 0, extents
);
1525 ReleaseDC(NULL
, hdc
);
1528 static void test_GetGlyphIndices(void)
1535 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1536 WORD glyphs
[(sizeof(testtext
)/2)-1];
1540 if (!pGetGlyphIndicesW
) {
1541 win_skip("GetGlyphIndicesW not available on platform\n");
1547 memset(&lf
, 0, sizeof(lf
));
1548 strcpy(lf
.lfFaceName
, "System");
1550 lf
.lfCharSet
= ANSI_CHARSET
;
1552 hfont
= CreateFontIndirectA(&lf
);
1553 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1554 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1555 if (textm
.tmCharSet
== ANSI_CHARSET
)
1557 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1558 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1559 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1560 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1562 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1563 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1564 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1565 textm
.tmDefaultChar
, glyphs
[4]);
1568 /* FIXME: Write tests for non-ANSI charsets. */
1569 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1571 if(!is_font_installed("Tahoma"))
1573 skip("Tahoma is not installed so skipping this test\n");
1576 memset(&lf
, 0, sizeof(lf
));
1577 strcpy(lf
.lfFaceName
, "Tahoma");
1580 hfont
= CreateFontIndirectA(&lf
);
1581 hOldFont
= SelectObject(hdc
, hfont
);
1582 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1583 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1584 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1585 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1586 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1588 testtext
[0] = textm
.tmDefaultChar
;
1589 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1590 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1591 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1592 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1593 DeleteObject(SelectObject(hdc
, hOldFont
));
1596 static void test_GetKerningPairs(void)
1598 static const struct kerning_data
1600 const char face_name
[LF_FACESIZE
];
1602 /* some interesting fields from OUTLINETEXTMETRIC */
1603 LONG tmHeight
, tmAscent
, tmDescent
;
1608 UINT otmsCapEmHeight
;
1613 UINT otmusMinimumPPEM
;
1614 /* small subset of kerning pairs to test */
1615 DWORD total_kern_pairs
;
1616 const KERNINGPAIR kern_pair
[26];
1619 {"Arial", 12, 12, 9, 3,
1620 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1623 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1624 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1625 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1626 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1627 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1628 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1629 {933,970,+1},{933,972,-1}
1632 {"Arial", -34, 39, 32, 7,
1633 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1636 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1637 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1638 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1639 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1640 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1641 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1642 {933,970,+2},{933,972,-3}
1645 { "Arial", 120, 120, 97, 23,
1646 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1649 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1650 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1651 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1652 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1653 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1654 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1655 {933,970,+6},{933,972,-10}
1658 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1659 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1660 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1663 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1664 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1665 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1666 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1667 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1668 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1669 {933,970,+54},{933,972,-83}
1675 HFONT hfont
, hfont_old
;
1676 KERNINGPAIR
*kern_pair
;
1678 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1682 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1683 * which may render this test unusable, so we're trying to avoid that.
1685 SetLastError(0xdeadbeef);
1686 GetKerningPairsW(hdc
, 0, NULL
);
1687 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1689 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1694 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1696 OUTLINETEXTMETRICW otm
;
1699 if (!is_font_installed(kd
[i
].face_name
))
1701 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1705 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1707 memset(&lf
, 0, sizeof(lf
));
1708 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1709 lf
.lfHeight
= kd
[i
].height
;
1710 hfont
= CreateFontIndirectA(&lf
);
1713 hfont_old
= SelectObject(hdc
, hfont
);
1715 SetLastError(0xdeadbeef);
1716 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1717 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1718 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1720 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1721 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1722 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1723 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1724 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1725 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1727 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1728 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1729 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1730 kd
[i
].otmAscent
, otm
.otmAscent
);
1731 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1732 kd
[i
].otmDescent
, otm
.otmDescent
);
1733 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1734 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1735 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1736 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1737 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1738 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1740 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1741 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1742 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1743 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1744 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1745 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1746 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1747 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1748 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1751 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1752 trace("total_kern_pairs %u\n", total_kern_pairs
);
1753 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1755 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1758 SetLastError(0xdeadbeef);
1759 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1760 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1761 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1762 ok(ret
== 0, "got %u, expected 0\n", ret
);
1764 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1765 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1767 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1768 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1770 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1771 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1775 for (n
= 0; n
< ret
; n
++)
1778 /* Disabled to limit console spam */
1779 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1780 trace("{'%c','%c',%d},\n",
1781 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1782 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1784 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1785 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1787 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1788 "pair %d:%d got %d, expected %d\n",
1789 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1790 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1796 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1797 matches
, kd
[i
].total_kern_pairs
);
1799 HeapFree(GetProcessHeap(), 0, kern_pair
);
1801 SelectObject(hdc
, hfont_old
);
1802 DeleteObject(hfont
);
1810 const char face_name
[LF_FACESIZE
];
1811 int requested_height
;
1812 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1816 static void test_height( HDC hdc
, const struct font_data
*fd
)
1819 HFONT hfont
, old_hfont
;
1823 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1825 if (!is_truetype_font_installed(fd
[i
].face_name
))
1827 skip("%s is not installed\n", fd
[i
].face_name
);
1831 memset(&lf
, 0, sizeof(lf
));
1832 lf
.lfHeight
= fd
[i
].requested_height
;
1833 lf
.lfWeight
= fd
[i
].weight
;
1834 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1836 hfont
= CreateFontIndirectA(&lf
);
1839 old_hfont
= SelectObject(hdc
, hfont
);
1840 ret
= GetTextMetricsA(hdc
, &tm
);
1841 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1842 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1844 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
);
1845 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
);
1846 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
);
1847 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
);
1848 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
);
1849 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
);
1852 SelectObject(hdc
, old_hfont
);
1853 DeleteObject(hfont
);
1857 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1859 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1860 DWORD
*table
= (DWORD
*)ttf
+ 3;
1862 for (i
= 0; i
< num_tables
; i
++)
1864 if (table
[0] == tag
)
1865 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
1871 static void test_height_selection_vdmx( HDC hdc
)
1873 static const struct font_data charset_0
[] = /* doesn't use VDMX */
1875 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1876 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1877 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1878 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1879 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1880 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
1881 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1882 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1883 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1884 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1885 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
1886 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1887 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1888 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1889 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1890 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1891 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
1892 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1893 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1894 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1895 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1896 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1897 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
1898 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
1899 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
1900 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
1901 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1902 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1903 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1904 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1905 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1906 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1907 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1908 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1909 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1910 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1911 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1912 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1913 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1914 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1915 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1916 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1917 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1918 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
1919 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
1920 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
1921 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
1922 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
1923 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
1924 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
1925 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
1926 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
1927 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1930 static const struct font_data charset_1
[] = /* Uses VDMX */
1932 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1933 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1934 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1935 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1936 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1937 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1938 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1939 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1940 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1941 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1942 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1943 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1944 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1945 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1946 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1947 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1948 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1949 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1950 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1951 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1952 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1953 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1954 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1955 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
1956 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
1957 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
1958 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1959 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1960 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1961 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1962 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1963 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1964 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1965 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1966 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1967 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1968 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1969 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1970 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1971 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1972 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1973 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
1974 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
1975 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
1976 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
1977 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
1978 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
1979 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
1980 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
1981 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
1982 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
1983 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
1984 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1987 static const struct vdmx_data
1991 const struct font_data
*fd
;
1994 { 0, 0, charset_0
},
1995 { 0, 1, charset_1
},
1996 { 1, 0, charset_0
},
2003 char ttf_name
[MAX_PATH
];
2006 if (!pAddFontResourceExA
)
2008 win_skip("AddFontResourceExA unavailable\n");
2012 for (i
= 0; i
< sizeof(data
) / sizeof(data
[0]); i
++)
2014 res
= get_res_data( "wine_vdmx.ttf", &size
);
2016 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2017 memcpy( copy
, res
, size
);
2018 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2019 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2020 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2021 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2022 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2023 ratio_rec
[0] = data
[i
].bCharSet
;
2025 write_tmp_file( copy
, &size
, ttf_name
);
2026 HeapFree( GetProcessHeap(), 0, copy
);
2028 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2029 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2030 if (!num
) win_skip("Unable to add ttf font resource\n");
2033 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2034 test_height( hdc
, data
[i
].fd
);
2035 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2037 DeleteFileA( ttf_name
);
2041 static void test_height_selection(void)
2043 static const struct font_data tahoma
[] =
2045 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2046 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2047 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2048 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2049 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2050 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2051 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2052 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2053 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2054 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2055 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2057 HDC hdc
= CreateCompatibleDC(0);
2060 test_height( hdc
, tahoma
);
2061 test_height_selection_vdmx( hdc
);
2066 static void test_GetOutlineTextMetrics(void)
2068 OUTLINETEXTMETRICA
*otm
;
2070 HFONT hfont
, hfont_old
;
2072 DWORD ret
, otm_size
;
2075 if (!is_font_installed("Arial"))
2077 skip("Arial is not installed\n");
2083 memset(&lf
, 0, sizeof(lf
));
2084 strcpy(lf
.lfFaceName
, "Arial");
2086 lf
.lfWeight
= FW_NORMAL
;
2087 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2088 lf
.lfQuality
= PROOF_QUALITY
;
2089 hfont
= CreateFontIndirectA(&lf
);
2092 hfont_old
= SelectObject(hdc
, hfont
);
2093 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2094 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
2096 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2098 memset(otm
, 0xAA, otm_size
);
2099 SetLastError(0xdeadbeef);
2100 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2101 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2102 ok(ret
== 1 /* Win9x */ ||
2103 ret
== otm
->otmSize
/* XP*/,
2104 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2105 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2107 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2108 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2109 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2110 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2113 memset(otm
, 0xAA, otm_size
);
2114 SetLastError(0xdeadbeef);
2115 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2116 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2117 ok(ret
== 1 /* Win9x */ ||
2118 ret
== otm
->otmSize
/* XP*/,
2119 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2120 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2122 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2123 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2124 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2125 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2128 /* ask about truncated data */
2129 memset(otm
, 0xAA, otm_size
);
2130 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2131 SetLastError(0xdeadbeef);
2132 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2133 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2134 ok(ret
== 1 /* Win9x */ ||
2135 ret
== otm
->otmSize
/* XP*/,
2136 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2137 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2139 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2140 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2141 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2143 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2145 HeapFree(GetProcessHeap(), 0, otm
);
2147 SelectObject(hdc
, hfont_old
);
2148 DeleteObject(hfont
);
2153 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2157 areaWidth
= clientArea
->right
- clientArea
->left
,
2159 const char *pFirstChar
, *pLastChar
;
2166 int GetTextExtentExPointWWidth
;
2169 GetTextMetricsA(hdc
, &tm
);
2170 y
= clientArea
->top
;
2173 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2179 /* if not at the end of the string, ... */
2180 if (*str
== '\0') break;
2181 /* ... add the next word to the current extent */
2182 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2184 SetTextJustification(hdc
, 0, 0);
2185 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2186 } while ((int) size
.cx
< areaWidth
);
2188 /* ignore trailing break chars */
2190 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2196 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2198 SetTextJustification(hdc
, 0, 0);
2199 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2201 /* do not justify the last extent */
2202 if (*str
!= '\0' && breakCount
> 0)
2204 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2205 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2206 if (size
.cx
!= areaWidth
&& nErrors
< sizeof(error
)/sizeof(error
[0]) - 1)
2208 error
[nErrors
].start
= pFirstChar
;
2209 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2210 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2217 } while (*str
&& y
< clientArea
->bottom
);
2219 for (e
= 0; e
< nErrors
; e
++)
2221 /* The width returned by GetTextExtentPoint32() is exactly the same
2222 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2223 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2224 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2225 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2229 static void test_SetTextJustification(void)
2239 static const char testText
[] =
2240 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2241 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2242 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2243 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2244 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2245 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2246 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2248 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2249 GetClientRect( hwnd
, &clientArea
);
2250 hdc
= GetDC( hwnd
);
2252 if (!is_font_installed("Times New Roman"))
2254 skip("Times New Roman is not installed\n");
2258 memset(&lf
, 0, sizeof lf
);
2259 lf
.lfCharSet
= ANSI_CHARSET
;
2260 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2261 lf
.lfWeight
= FW_DONTCARE
;
2263 lf
.lfQuality
= DEFAULT_QUALITY
;
2264 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2265 hfont
= create_font("Times New Roman", &lf
);
2266 SelectObject(hdc
, hfont
);
2268 testJustification(hdc
, testText
, &clientArea
);
2270 if (!pGetGlyphIndicesA
|| !pGetTextExtentExPointI
) goto done
;
2271 pGetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2273 SetTextJustification(hdc
, 0, 0);
2274 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2275 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2276 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2277 SetTextJustification(hdc
, 4, 1);
2278 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2279 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2280 SetTextJustification(hdc
, 9, 2);
2281 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2282 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2283 SetTextJustification(hdc
, 7, 3);
2284 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2285 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2286 SetTextJustification(hdc
, 7, 3);
2287 SetTextCharacterExtra(hdc
, 2 );
2288 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2289 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2290 SetTextJustification(hdc
, 0, 0);
2291 SetTextCharacterExtra(hdc
, 0);
2292 size
.cx
= size
.cy
= 1234;
2293 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2294 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
2295 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2296 SetTextJustification(hdc
, 5, 1);
2297 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2298 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2299 SetTextJustification(hdc
, 0, 0);
2301 SetMapMode( hdc
, MM_ANISOTROPIC
);
2302 SetWindowExtEx( hdc
, 2, 2, NULL
);
2303 GetClientRect( hwnd
, &clientArea
);
2304 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2305 testJustification(hdc
, testText
, &clientArea
);
2307 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2308 for (i
= 0; i
< 10; i
++)
2310 SetTextCharacterExtra(hdc
, i
);
2311 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2312 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2314 SetTextCharacterExtra(hdc
, 0);
2315 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2316 for (i
= 0; i
< 10; i
++)
2318 SetTextCharacterExtra(hdc
, i
);
2319 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2320 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2322 SetTextCharacterExtra(hdc
, 0);
2324 SetViewportExtEx( hdc
, 3, 3, NULL
);
2325 GetClientRect( hwnd
, &clientArea
);
2326 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2327 testJustification(hdc
, testText
, &clientArea
);
2329 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2330 for (i
= 0; i
< 10; i
++)
2332 SetTextCharacterExtra(hdc
, i
);
2333 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2334 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2338 DeleteObject(hfont
);
2339 ReleaseDC(hwnd
, hdc
);
2340 DestroyWindow(hwnd
);
2343 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2347 HFONT hfont
, hfont_old
;
2354 assert(count
<= 128);
2356 memset(&lf
, 0, sizeof(lf
));
2358 lf
.lfCharSet
= charset
;
2360 lstrcpyA(lf
.lfFaceName
, "Arial");
2361 SetLastError(0xdeadbeef);
2362 hfont
= CreateFontIndirectA(&lf
);
2363 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2366 hfont_old
= SelectObject(hdc
, hfont
);
2368 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2369 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2371 SetLastError(0xdeadbeef);
2372 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2373 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
2375 if (charset
== SYMBOL_CHARSET
)
2377 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2378 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
2382 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2383 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2386 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2388 trace("Can't find codepage for charset %d\n", cs
);
2392 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2394 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2396 skip("Font code page %d, looking for code page %d\n",
2397 pGdiGetCodePage(hdc
), code_page
);
2405 WCHAR unicode_buf
[128];
2407 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2409 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2411 SetLastError(0xdeadbeef);
2412 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2413 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2414 count
, ret
, GetLastError());
2420 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2422 SetLastError(0xdeadbeef);
2423 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2424 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2425 count
, ret
, GetLastError());
2428 SelectObject(hdc
, hfont_old
);
2429 DeleteObject(hfont
);
2436 static void test_font_charset(void)
2438 static struct charset_data
2442 WORD font_idxA
[128], font_idxW
[128];
2445 { ANSI_CHARSET
, 1252 },
2446 { RUSSIAN_CHARSET
, 1251 },
2447 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2451 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
2453 win_skip("Skipping the font charset test on a Win9x platform\n");
2457 if (!is_font_installed("Arial"))
2459 skip("Arial is not installed\n");
2463 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
2465 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2467 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2469 skip("Symbol or Wingdings is not installed\n");
2473 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2474 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2475 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2478 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2481 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2482 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2485 skip("Symbol or Wingdings is not installed\n");
2488 static void test_GdiGetCodePage(void)
2490 static const struct _matching_data
2492 UINT current_codepage
;
2495 UINT expected_codepage
;
2496 } matching_data
[] = {
2497 {1251, "Arial", ANSI_CHARSET
, 1252},
2498 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2500 {1252, "Arial", ANSI_CHARSET
, 1252},
2501 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2503 {1253, "Arial", ANSI_CHARSET
, 1252},
2504 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2506 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2507 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2508 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2510 { 936, "Arial", ANSI_CHARSET
, 936},
2511 { 936, "Tahoma", ANSI_CHARSET
, 936},
2512 { 936, "Simsun", ANSI_CHARSET
, 936},
2514 { 949, "Arial", ANSI_CHARSET
, 949},
2515 { 949, "Tahoma", ANSI_CHARSET
, 949},
2516 { 949, "Gulim", ANSI_CHARSET
, 949},
2518 { 950, "Arial", ANSI_CHARSET
, 950},
2519 { 950, "Tahoma", ANSI_CHARSET
, 950},
2520 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2529 if (!pGdiGetCodePage
)
2531 skip("GdiGetCodePage not available on this platform\n");
2537 for (i
= 0; i
< sizeof(matching_data
) / sizeof(struct _matching_data
); i
++)
2539 /* only test data matched current locale codepage */
2540 if (matching_data
[i
].current_codepage
!= acp
)
2543 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2545 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2551 memset(&lf
, 0, sizeof(lf
));
2553 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2554 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2555 hfont
= CreateFontIndirectA(&lf
);
2556 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2558 hfont
= SelectObject(hdc
, hfont
);
2559 charset
= GetTextCharset(hdc
);
2560 codepage
= pGdiGetCodePage(hdc
);
2561 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2562 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
, matching_data
[i
].expected_codepage
);
2563 ok(codepage
== matching_data
[i
].expected_codepage
,
2564 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2566 hfont
= SelectObject(hdc
, hfont
);
2567 DeleteObject(hfont
);
2569 /* CLIP_DFA_DISABLE turns off the font association */
2570 lf
.lfClipPrecision
= CLIP_DFA_DISABLE
;
2571 hfont
= CreateFontIndirectA(&lf
);
2572 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2574 hfont
= SelectObject(hdc
, hfont
);
2575 charset
= GetTextCharset(hdc
);
2576 codepage
= pGdiGetCodePage(hdc
);
2577 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2578 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
);
2579 ok(codepage
== 1252, "GdiGetCodePage returned %d\n", codepage
);
2581 hfont
= SelectObject(hdc
, hfont
);
2582 DeleteObject(hfont
);
2584 ReleaseDC(NULL
, hdc
);
2588 static void test_GetFontUnicodeRanges(void)
2592 HFONT hfont
, hfont_old
;
2597 if (!pGetFontUnicodeRanges
)
2599 win_skip("GetFontUnicodeRanges not available before W2K\n");
2603 memset(&lf
, 0, sizeof(lf
));
2604 lstrcpyA(lf
.lfFaceName
, "Arial");
2605 hfont
= create_font("Arial", &lf
);
2608 hfont_old
= SelectObject(hdc
, hfont
);
2610 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2611 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2613 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2614 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2616 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2618 size
= pGetFontUnicodeRanges(hdc
, gs
);
2619 ok(size
, "GetFontUnicodeRanges failed\n");
2621 if (0) /* Disabled to limit console spam */
2622 for (i
= 0; i
< gs
->cRanges
; i
++)
2623 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2624 trace("found %u ranges\n", gs
->cRanges
);
2626 HeapFree(GetProcessHeap(), 0, gs
);
2628 SelectObject(hdc
, hfont_old
);
2629 DeleteObject(hfont
);
2630 ReleaseDC(NULL
, hdc
);
2633 #define MAX_ENUM_FONTS 4096
2635 struct enum_font_data
2638 LOGFONTA lf
[MAX_ENUM_FONTS
];
2641 struct enum_fullname_data
2644 ENUMLOGFONTA elf
[MAX_ENUM_FONTS
];
2647 struct enum_font_dataW
2650 LOGFONTW lf
[MAX_ENUM_FONTS
];
2653 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2655 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2656 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2658 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2659 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2661 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2663 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2665 if (0) /* Disabled to limit console spam */
2666 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2667 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2668 if (efd
->total
< MAX_ENUM_FONTS
)
2669 efd
->lf
[efd
->total
++] = *lf
;
2671 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2676 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2678 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2679 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2681 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2682 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2684 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2686 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2688 if (0) /* Disabled to limit console spam */
2689 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2690 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2691 if (efd
->total
< MAX_ENUM_FONTS
)
2692 efd
->lf
[efd
->total
++] = *lf
;
2694 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2699 static void get_charset_stats(struct enum_font_data
*efd
,
2700 int *ansi_charset
, int *symbol_charset
,
2701 int *russian_charset
)
2706 *symbol_charset
= 0;
2707 *russian_charset
= 0;
2709 for (i
= 0; i
< efd
->total
; i
++)
2711 switch (efd
->lf
[i
].lfCharSet
)
2716 case SYMBOL_CHARSET
:
2717 (*symbol_charset
)++;
2719 case RUSSIAN_CHARSET
:
2720 (*russian_charset
)++;
2726 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2727 int *ansi_charset
, int *symbol_charset
,
2728 int *russian_charset
)
2733 *symbol_charset
= 0;
2734 *russian_charset
= 0;
2736 for (i
= 0; i
< efd
->total
; i
++)
2738 switch (efd
->lf
[i
].lfCharSet
)
2743 case SYMBOL_CHARSET
:
2744 (*symbol_charset
)++;
2746 case RUSSIAN_CHARSET
:
2747 (*russian_charset
)++;
2753 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2755 struct enum_font_data efd
;
2756 struct enum_font_dataW efdw
;
2759 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2761 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2763 if (*font_name
&& !is_truetype_font_installed(font_name
))
2765 skip("%s is not installed\n", font_name
);
2771 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2772 * while EnumFontFamiliesEx doesn't.
2774 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2777 * Use EnumFontFamiliesW since win98 crashes when the
2778 * second parameter is NULL using EnumFontFamilies
2781 SetLastError(0xdeadbeef);
2782 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2783 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW 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 ||
2793 broken(russian_charset
== 0), /* NT4 */
2794 "NULL family should enumerate RUSSIAN_CHARSET\n");
2798 SetLastError(0xdeadbeef);
2799 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2800 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2803 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2804 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2805 ansi_charset
, symbol_charset
, russian_charset
);
2806 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2807 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2808 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2809 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2814 SetLastError(0xdeadbeef);
2815 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2816 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2817 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2818 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2819 ansi_charset
, symbol_charset
, russian_charset
,
2820 *font_name
? font_name
: "<empty>");
2822 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2824 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2825 for (i
= 0; i
< efd
.total
; i
++)
2827 /* FIXME: remove completely once Wine is fixed */
2828 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2831 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2834 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2835 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2836 font_name
, efd
.lf
[i
].lfFaceName
);
2839 memset(&lf
, 0, sizeof(lf
));
2840 lf
.lfCharSet
= ANSI_CHARSET
;
2841 strcpy(lf
.lfFaceName
, font_name
);
2843 SetLastError(0xdeadbeef);
2844 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2845 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2846 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2847 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2848 ansi_charset
, symbol_charset
, russian_charset
,
2849 *font_name
? font_name
: "<empty>");
2850 if (font_charset
== SYMBOL_CHARSET
)
2853 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2855 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2859 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2860 for (i
= 0; i
< efd
.total
; i
++)
2862 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2864 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2865 font_name
, efd
.lf
[i
].lfFaceName
);
2869 /* DEFAULT_CHARSET should enumerate all available charsets */
2870 memset(&lf
, 0, sizeof(lf
));
2871 lf
.lfCharSet
= DEFAULT_CHARSET
;
2872 strcpy(lf
.lfFaceName
, font_name
);
2874 SetLastError(0xdeadbeef);
2875 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2876 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2877 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2878 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2879 ansi_charset
, symbol_charset
, russian_charset
,
2880 *font_name
? font_name
: "<empty>");
2881 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2882 for (i
= 0; i
< efd
.total
; i
++)
2885 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2886 font_name
, efd
.lf
[i
].lfFaceName
);
2890 switch (font_charset
)
2893 ok(ansi_charset
> 0,
2894 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2896 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2897 ok(russian_charset
> 0,
2898 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2900 case SYMBOL_CHARSET
:
2902 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2904 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2905 ok(!russian_charset
,
2906 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2908 case DEFAULT_CHARSET
:
2909 ok(ansi_charset
> 0,
2910 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2911 ok(symbol_charset
> 0,
2912 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2913 ok(russian_charset
> 0,
2914 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2920 ok(ansi_charset
> 0,
2921 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2922 ok(symbol_charset
> 0,
2923 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2924 ok(russian_charset
> 0,
2925 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2928 memset(&lf
, 0, sizeof(lf
));
2929 lf
.lfCharSet
= SYMBOL_CHARSET
;
2930 strcpy(lf
.lfFaceName
, font_name
);
2932 SetLastError(0xdeadbeef);
2933 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2934 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2935 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2936 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2937 ansi_charset
, symbol_charset
, russian_charset
,
2938 *font_name
? font_name
: "<empty>");
2939 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2940 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2943 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2944 for (i
= 0; i
< efd
.total
; i
++)
2946 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2948 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2949 font_name
, efd
.lf
[i
].lfFaceName
);
2953 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2954 ok(symbol_charset
> 0,
2955 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2956 ok(!russian_charset
,
2957 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2963 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2965 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
2966 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
2967 const DWORD valid_bits
= 0x003f01ff;
2971 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
2973 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
2974 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
2975 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
2984 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
2986 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2988 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2990 if (efd
->total
< MAX_ENUM_FONTS
)
2991 efd
->lf
[efd
->total
++] = *lf
;
2993 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2998 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3000 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
3002 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3004 if (efnd
->total
< MAX_ENUM_FONTS
)
3005 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
3007 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
3012 static void test_EnumFontFamiliesEx_default_charset(void)
3014 struct enum_font_data efd
;
3015 LOGFONTA target
, enum_font
;
3021 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3022 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3027 memset(&enum_font
, 0, sizeof(enum_font
));
3028 enum_font
.lfCharSet
= csi
.ciCharset
;
3029 target
.lfFaceName
[0] = '\0';
3030 target
.lfCharSet
= csi
.ciCharset
;
3031 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3032 if (target
.lfFaceName
[0] == '\0') {
3033 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3036 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3037 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3038 target
.lfCharSet
= ANSI_CHARSET
;
3042 memset(&enum_font
, 0, sizeof(enum_font
));
3043 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3044 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3045 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3048 trace("'%s' has %d charsets.\n", target
.lfFaceName
, efd
.total
);
3049 if (efd
.total
< 2) {
3050 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3054 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3055 "(%s) got charset %d expected %d\n",
3056 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3061 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3063 HFONT hfont
, hfont_prev
;
3065 GLYPHMETRICS gm1
, gm2
;
3069 if(!pGetGlyphIndicesA
)
3072 /* negative widths are handled just as positive ones */
3073 lf2
.lfWidth
= -lf
->lfWidth
;
3075 SetLastError(0xdeadbeef);
3076 hfont
= CreateFontIndirectA(lf
);
3077 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3078 check_font("original", lf
, hfont
);
3080 hfont_prev
= SelectObject(hdc
, hfont
);
3082 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3083 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3085 SelectObject(hdc
, hfont_prev
);
3086 DeleteObject(hfont
);
3087 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3091 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3092 memset(&gm1
, 0xab, sizeof(gm1
));
3093 SetLastError(0xdeadbeef);
3094 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3095 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3097 SelectObject(hdc
, hfont_prev
);
3098 DeleteObject(hfont
);
3100 SetLastError(0xdeadbeef);
3101 hfont
= CreateFontIndirectA(&lf2
);
3102 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3103 check_font("negative width", &lf2
, hfont
);
3105 hfont_prev
= SelectObject(hdc
, hfont
);
3107 memset(&gm2
, 0xbb, sizeof(gm2
));
3108 SetLastError(0xdeadbeef);
3109 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3110 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3112 SelectObject(hdc
, hfont_prev
);
3113 DeleteObject(hfont
);
3115 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3116 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3117 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3118 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3119 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3120 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3121 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3122 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3123 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3124 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3125 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3128 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3129 #include "pshpack2.h"
3133 SHORT xAvgCharWidth
;
3134 USHORT usWeightClass
;
3135 USHORT usWidthClass
;
3137 SHORT ySubscriptXSize
;
3138 SHORT ySubscriptYSize
;
3139 SHORT ySubscriptXOffset
;
3140 SHORT ySubscriptYOffset
;
3141 SHORT ySuperscriptXSize
;
3142 SHORT ySuperscriptYSize
;
3143 SHORT ySuperscriptXOffset
;
3144 SHORT ySuperscriptYOffset
;
3145 SHORT yStrikeoutSize
;
3146 SHORT yStrikeoutPosition
;
3149 ULONG ulUnicodeRange1
;
3150 ULONG ulUnicodeRange2
;
3151 ULONG ulUnicodeRange3
;
3152 ULONG ulUnicodeRange4
;
3155 USHORT usFirstCharIndex
;
3156 USHORT usLastCharIndex
;
3157 /* According to the Apple spec, original version didn't have the below fields,
3158 * version numbers were taken from the OpenType spec.
3160 /* version 0 (TrueType 1.5) */
3161 USHORT sTypoAscender
;
3162 USHORT sTypoDescender
;
3163 USHORT sTypoLineGap
;
3165 USHORT usWinDescent
;
3166 /* version 1 (TrueType 1.66) */
3167 ULONG ulCodePageRange1
;
3168 ULONG ulCodePageRange2
;
3169 /* version 2 (OpenType 1.2) */
3172 USHORT usDefaultChar
;
3174 USHORT usMaxContext
;
3176 #include "poppack.h"
3189 } cmap_encoding_record
;
3197 BYTE glyph_ids
[256];
3207 USHORT search_range
;
3208 USHORT entry_selector
;
3211 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3214 USHORT start_count[seg_countx2 / 2];
3215 USHORT id_delta[seg_countx2 / 2];
3216 USHORT id_range_offset[seg_countx2 / 2];
3226 USHORT id_range_offset
;
3227 } cmap_format_4_seg
;
3229 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
3231 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3232 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3233 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3234 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3235 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3238 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3241 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3245 for(i
= 0; i
< 256; i
++)
3247 if(cmap
->glyph_ids
[i
] == 0) continue;
3249 if(*first
== 256) *first
= i
;
3251 if(*first
== 256) return FALSE
;
3255 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3257 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3258 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3259 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3260 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3261 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3264 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3267 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3268 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3272 for(i
= 0; i
< seg_count
; i
++)
3274 cmap_format_4_seg seg
;
3276 get_seg4(cmap
, i
, &seg
);
3278 if(seg
.start_count
> 0xfffe) break;
3280 if(*first
== 0x10000) *first
= seg
.start_count
;
3282 *last
= min(seg
.end_count
, 0xfffe);
3285 if(*first
== 0x10000) return FALSE
;
3289 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3292 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3294 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3296 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3297 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3310 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3313 cmap_header
*header
;
3318 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3319 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3320 if(size
== GDI_ERROR
) return FALSE
;
3322 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3323 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3324 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3325 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3327 cmap
= get_cmap(header
, 3, 1);
3329 *cmap_type
= cmap_ms_unicode
;
3332 cmap
= get_cmap(header
, 3, 0);
3333 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3337 *cmap_type
= cmap_none
;
3341 format
= GET_BE_WORD(*(WORD
*)cmap
);
3345 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3348 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3351 trace("unhandled cmap format %d\n", format
);
3356 HeapFree(GetProcessHeap(), 0, header
);
3360 #define TT_PLATFORM_APPLE_UNICODE 0
3361 #define TT_PLATFORM_MACINTOSH 1
3362 #define TT_PLATFORM_MICROSOFT 3
3363 #define TT_APPLE_ID_DEFAULT 0
3364 #define TT_APPLE_ID_ISO_10646 2
3365 #define TT_APPLE_ID_UNICODE_2_0 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
3373 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3375 typedef struct sfnt_name
3385 static const LANGID mac_langid_table
[] =
3387 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
3388 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
3389 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
3390 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
3391 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
3392 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
3393 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
3394 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
3395 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
3396 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
3397 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
3398 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
3399 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
3400 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
3401 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
3402 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
3403 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
3404 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
3405 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
3406 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3407 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
3408 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
3409 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
3410 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
3411 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
3412 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
3413 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
3414 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
3415 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
3416 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
3417 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
3418 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
3419 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
3420 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3421 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
3422 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
3423 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
3424 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
3425 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
3426 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
3427 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
3428 0, /* TT_MAC_LANGID_YIDDISH */
3429 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
3430 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
3431 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
3432 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
3433 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
3434 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
3435 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
3436 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
3437 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3438 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
3439 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
3440 0, /* TT_MAC_LANGID_MOLDAVIAN */
3441 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
3442 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
3443 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
3444 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
3445 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3446 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
3447 0, /* TT_MAC_LANGID_KURDISH */
3448 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
3449 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
3450 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
3451 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
3452 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
3453 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
3454 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
3455 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
3456 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
3457 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
3458 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
3459 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
3460 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
3461 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
3462 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
3463 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
3464 0, /* TT_MAC_LANGID_BURMESE */
3465 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
3466 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
3467 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
3468 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
3469 0, /* TT_MAC_LANGID_TAGALOG */
3470 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3471 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3472 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
3473 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
3474 0, /* TT_MAC_LANGID_GALLA */
3475 0, /* TT_MAC_LANGID_SOMALI */
3476 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
3477 0, /* TT_MAC_LANGID_RUANDA */
3478 0, /* TT_MAC_LANGID_RUNDI */
3479 0, /* TT_MAC_LANGID_CHEWA */
3480 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
3481 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
3482 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3483 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3484 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
3485 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
3486 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
3487 0, /* TT_MAC_LANGID_LATIN */
3488 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
3489 0, /* TT_MAC_LANGID_GUARANI */
3490 0, /* TT_MAC_LANGID_AYMARA */
3491 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
3492 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
3493 0, /* TT_MAC_LANGID_DZONGKHA */
3494 0, /* TT_MAC_LANGID_JAVANESE */
3495 0, /* TT_MAC_LANGID_SUNDANESE */
3496 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
3497 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
3498 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
3499 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
3500 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3501 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
3502 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
3503 0, /* TT_MAC_LANGID_TONGAN */
3504 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3505 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
3506 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3509 static inline WORD
get_mac_code_page( const sfnt_name
*name
)
3511 if (GET_BE_WORD(name
->encoding_id
) == TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
3512 return 10000 + GET_BE_WORD(name
->encoding_id
);
3515 static int match_name_table_language( const sfnt_name
*name
, LANGID lang
)
3520 switch (GET_BE_WORD(name
->platform_id
))
3522 case TT_PLATFORM_MICROSOFT
:
3523 res
+= 5; /* prefer the Microsoft name */
3524 switch (GET_BE_WORD(name
->encoding_id
))
3526 case TT_MS_ID_UNICODE_CS
:
3527 case TT_MS_ID_SYMBOL_CS
:
3528 name_lang
= GET_BE_WORD(name
->language_id
);
3534 case TT_PLATFORM_MACINTOSH
:
3535 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
3536 if (GET_BE_WORD(name
->language_id
) >= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
3537 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3539 case TT_PLATFORM_APPLE_UNICODE
:
3540 res
+= 2; /* prefer Unicode encodings */
3541 switch (GET_BE_WORD(name
->encoding_id
))
3543 case TT_APPLE_ID_DEFAULT
:
3544 case TT_APPLE_ID_ISO_10646
:
3545 case TT_APPLE_ID_UNICODE_2_0
:
3546 if (GET_BE_WORD(name
->language_id
) >= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
3547 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3556 if (name_lang
== lang
) res
+= 30;
3557 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
3558 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
3562 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3564 struct sfnt_name_header
3567 USHORT number_of_record
;
3568 USHORT storage_offset
;
3572 LONG size
, offset
, length
;
3577 int res
, best_lang
= 0, best_index
= -1;
3579 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3580 ok(size
!= GDI_ERROR
, "no name table found\n");
3581 if(size
== GDI_ERROR
) return FALSE
;
3583 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3584 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3585 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3587 header
= (void *)data
;
3588 header
->format
= GET_BE_WORD(header
->format
);
3589 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3590 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3591 if (header
->format
!= 0)
3593 trace("got format %u\n", header
->format
);
3596 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3598 trace("number records out of range: %d\n", header
->number_of_record
);
3601 if (header
->storage_offset
>= size
)
3603 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3607 entry
= (void *)&header
[1];
3608 for (i
= 0; i
< header
->number_of_record
; i
++)
3610 if (GET_BE_WORD(entry
[i
].name_id
) != name_id
) continue;
3611 res
= match_name_table_language( &entry
[i
], language_id
);
3612 if (res
> best_lang
)
3619 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[best_index
].offset
);
3620 length
= GET_BE_WORD(entry
[best_index
].length
);
3621 if (offset
+ length
> size
)
3623 trace("entry %d is out of range\n", best_index
);
3626 if (length
>= out_size
)
3628 trace("buffer too small for entry %d\n", best_index
);
3632 name
= (WCHAR
*)(data
+ offset
);
3633 for (c
= 0; c
< length
/ 2; c
++)
3634 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3640 HeapFree(GetProcessHeap(), 0, data
);
3644 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3647 HFONT hfont
, hfont_old
;
3651 const char *font_name
= lf
->lfFaceName
;
3652 DWORD cmap_first
= 0, cmap_last
= 0;
3653 UINT ascent
, descent
, cell_height
;
3654 cmap_type cmap_type
;
3655 BOOL sys_lang_non_english
;
3657 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3660 SetLastError(0xdeadbeef);
3661 hfont
= CreateFontIndirectA(lf
);
3662 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3664 hfont_old
= SelectObject(hdc
, hfont
);
3666 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3667 if (size
== GDI_ERROR
)
3669 trace("OS/2 chunk was not found\n");
3672 if (size
> sizeof(tt_os2
))
3674 trace("got too large OS/2 chunk of size %u\n", size
);
3675 size
= sizeof(tt_os2
);
3678 memset(&tt_os2
, 0, sizeof(tt_os2
));
3679 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3680 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3682 SetLastError(0xdeadbeef);
3683 ret
= GetTextMetricsA(hdc
, &tmA
);
3684 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3686 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3688 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3692 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3693 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3694 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3698 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3699 descent
= GET_BE_WORD(tt_os2
.usWinDescent
);
3700 cell_height
= ascent
+ descent
;
3701 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3702 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3704 version
= GET_BE_WORD(tt_os2
.version
);
3706 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3707 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3708 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3709 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3711 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3712 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3713 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3715 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3720 case 1255: /* Hebrew */
3721 expect_last_W
= 0xf896;
3723 case 1257: /* Baltic */
3724 expect_last_W
= 0xf8fd;
3727 expect_last_W
= 0xf0ff;
3729 expect_break_W
= 0x20;
3730 expect_default_W
= expect_break_W
- 1;
3731 expect_first_A
= 0x1e;
3732 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3736 expect_first_W
= cmap_first
;
3737 expect_last_W
= cmap_last
;
3738 if(os2_first_char
<= 1)
3739 expect_break_W
= os2_first_char
+ 2;
3740 else if(os2_first_char
> 0xff)
3741 expect_break_W
= 0x20;
3743 expect_break_W
= os2_first_char
;
3744 expect_default_W
= expect_break_W
- 1;
3745 expect_first_A
= expect_default_W
- 1;
3746 expect_last_A
= min(expect_last_W
, 0xff);
3748 expect_break_A
= expect_break_W
;
3749 expect_default_A
= expect_default_W
;
3751 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3752 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3753 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
3754 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3755 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3757 ok(tmA
.tmFirstChar
== expect_first_A
||
3758 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3759 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3760 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3761 ok(tmA
.tmLastChar
== expect_last_A
||
3762 tmA
.tmLastChar
== 0xff /* win9x */,
3763 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3765 skip("tmLastChar is DBCS lead byte\n");
3766 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3767 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3768 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3769 "A: tmDefaultChar for %s got %02x expected %02x\n",
3770 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3773 SetLastError(0xdeadbeef);
3774 ret
= GetTextMetricsW(hdc
, &tmW
);
3775 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3776 "GetTextMetricsW error %u\n", GetLastError());
3779 /* Wine uses the os2 first char */
3780 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3781 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3782 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3784 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3785 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3787 /* Wine uses the os2 last char */
3788 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3789 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3790 font_name
, tmW
.tmLastChar
, expect_last_W
);
3792 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3793 font_name
, tmW
.tmLastChar
, expect_last_W
);
3794 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3795 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3796 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3797 "W: tmDefaultChar for %s got %02x expected %02x\n",
3798 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3800 /* Test the aspect ratio while we have tmW */
3801 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3802 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3803 tmW
.tmDigitizedAspectX
, ret
);
3804 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3805 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3806 tmW
.tmDigitizedAspectX
, ret
);
3810 /* test FF_ values */
3811 switch(tt_os2
.panose
.bFamilyType
)
3815 case PAN_FAMILY_TEXT_DISPLAY
:
3816 case PAN_FAMILY_PICTORIAL
:
3818 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3819 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3821 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3824 switch(tt_os2
.panose
.bSerifStyle
)
3829 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3832 case PAN_SERIF_COVE
:
3833 case PAN_SERIF_OBTUSE_COVE
:
3834 case PAN_SERIF_SQUARE_COVE
:
3835 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3836 case PAN_SERIF_SQUARE
:
3837 case PAN_SERIF_THIN
:
3838 case PAN_SERIF_BONE
:
3839 case PAN_SERIF_EXAGGERATED
:
3840 case PAN_SERIF_TRIANGLE
:
3841 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3844 case PAN_SERIF_NORMAL_SANS
:
3845 case PAN_SERIF_OBTUSE_SANS
:
3846 case PAN_SERIF_PERP_SANS
:
3847 case PAN_SERIF_FLARED
:
3848 case PAN_SERIF_ROUNDED
:
3849 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3854 case PAN_FAMILY_SCRIPT
:
3855 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3858 case PAN_FAMILY_DECORATIVE
:
3859 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3863 test_negative_width(hdc
, lf
);
3866 SelectObject(hdc
, hfont_old
);
3867 DeleteObject(hfont
);
3872 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3874 INT
*enumed
= (INT
*)lParam
;
3876 if (type
== TRUETYPE_FONTTYPE
)
3879 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
3884 static void test_GetTextMetrics(void)
3890 /* Report only once */
3891 if(!pGetGlyphIndicesA
)
3892 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3896 memset(&lf
, 0, sizeof(lf
));
3897 lf
.lfCharSet
= DEFAULT_CHARSET
;
3899 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
3900 trace("Tested metrics of %d truetype fonts\n", enumed
);
3905 static void test_nonexistent_font(void)
3913 { "Times New Roman Baltic", 186 },
3914 { "Times New Roman CE", 238 },
3915 { "Times New Roman CYR", 204 },
3916 { "Times New Roman Greek", 161 },
3917 { "Times New Roman TUR", 162 }
3923 INT cs
, expected_cs
, i
;
3924 char buf
[LF_FACESIZE
];
3926 if (!is_truetype_font_installed("Arial") ||
3927 !is_truetype_font_installed("Times New Roman"))
3929 skip("Arial or Times New Roman not installed\n");
3933 expected_cs
= GetACP();
3934 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3936 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3939 expected_cs
= csi
.ciCharset
;
3940 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3944 memset(&lf
, 0, sizeof(lf
));
3946 lf
.lfWeight
= FW_REGULAR
;
3947 lf
.lfCharSet
= ANSI_CHARSET
;
3948 lf
.lfPitchAndFamily
= FF_SWISS
;
3949 strcpy(lf
.lfFaceName
, "Nonexistent font");
3950 hfont
= CreateFontIndirectA(&lf
);
3951 hfont
= SelectObject(hdc
, hfont
);
3952 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3953 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
3954 cs
= GetTextCharset(hdc
);
3955 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3956 DeleteObject(SelectObject(hdc
, hfont
));
3958 memset(&lf
, 0, sizeof(lf
));
3960 lf
.lfWeight
= FW_DONTCARE
;
3961 strcpy(lf
.lfFaceName
, "Nonexistent font");
3962 hfont
= CreateFontIndirectA(&lf
);
3963 hfont
= SelectObject(hdc
, hfont
);
3964 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3965 todo_wine
/* Wine uses Arial for all substitutions */
3966 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
3967 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
3968 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3970 cs
= GetTextCharset(hdc
);
3971 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
3972 DeleteObject(SelectObject(hdc
, hfont
));
3974 memset(&lf
, 0, sizeof(lf
));
3976 lf
.lfWeight
= FW_REGULAR
;
3977 strcpy(lf
.lfFaceName
, "Nonexistent font");
3978 hfont
= CreateFontIndirectA(&lf
);
3979 hfont
= SelectObject(hdc
, hfont
);
3980 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3981 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3982 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
3983 cs
= GetTextCharset(hdc
);
3984 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3985 DeleteObject(SelectObject(hdc
, hfont
));
3987 memset(&lf
, 0, sizeof(lf
));
3989 lf
.lfWeight
= FW_DONTCARE
;
3990 strcpy(lf
.lfFaceName
, "Times New Roman");
3991 hfont
= CreateFontIndirectA(&lf
);
3992 hfont
= SelectObject(hdc
, hfont
);
3993 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3994 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
3995 cs
= GetTextCharset(hdc
);
3996 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3997 DeleteObject(SelectObject(hdc
, hfont
));
3999 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
4001 memset(&lf
, 0, sizeof(lf
));
4003 lf
.lfWeight
= FW_REGULAR
;
4004 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4005 hfont
= CreateFontIndirectA(&lf
);
4006 hfont
= SelectObject(hdc
, hfont
);
4007 cs
= GetTextCharset(hdc
);
4008 if (font_subst
[i
].charset
== expected_cs
)
4010 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4011 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4012 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
4016 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
4017 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4018 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4019 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
4021 DeleteObject(SelectObject(hdc
, hfont
));
4023 memset(&lf
, 0, sizeof(lf
));
4025 lf
.lfWeight
= FW_DONTCARE
;
4026 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4027 hfont
= CreateFontIndirectA(&lf
);
4028 hfont
= SelectObject(hdc
, hfont
);
4029 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4030 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
4031 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
4032 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
4033 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4034 "got %s for font %s\n", buf
, font_subst
[i
].name
);
4035 cs
= GetTextCharset(hdc
);
4036 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4037 DeleteObject(SelectObject(hdc
, hfont
));
4043 static void test_GdiRealizationInfo(void)
4048 HFONT hfont
, hfont_old
;
4051 if(!pGdiRealizationInfo
)
4053 win_skip("GdiRealizationInfo not available\n");
4059 memset(info
, 0xcc, sizeof(info
));
4060 r
= pGdiRealizationInfo(hdc
, info
);
4061 ok(r
!= 0, "ret 0\n");
4062 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
4063 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4065 if (!is_truetype_font_installed("Arial"))
4067 skip("skipping GdiRealizationInfo with truetype font\n");
4071 memset(&lf
, 0, sizeof(lf
));
4072 strcpy(lf
.lfFaceName
, "Arial");
4074 lf
.lfWeight
= FW_NORMAL
;
4075 hfont
= CreateFontIndirectA(&lf
);
4076 hfont_old
= SelectObject(hdc
, hfont
);
4078 memset(info
, 0xcc, sizeof(info
));
4079 r
= pGdiRealizationInfo(hdc
, info
);
4080 ok(r
!= 0, "ret 0\n");
4081 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
4082 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4084 DeleteObject(SelectObject(hdc
, hfont_old
));
4090 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4091 the nul in the count of characters copied when the face name buffer is not
4092 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4093 always includes it. */
4094 static void test_GetTextFace(void)
4096 static const char faceA
[] = "Tahoma";
4097 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
4100 char bufA
[LF_FACESIZE
];
4101 WCHAR bufW
[LF_FACESIZE
];
4106 if(!is_font_installed("Tahoma"))
4108 skip("Tahoma is not installed so skipping this test\n");
4113 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
4114 f
= CreateFontIndirectA(&fA
);
4115 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
4118 g
= SelectObject(dc
, f
);
4119 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
4120 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
4121 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
4123 /* Play with the count arg. */
4125 n
= GetTextFaceA(dc
, 0, bufA
);
4126 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4127 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4130 n
= GetTextFaceA(dc
, 1, bufA
);
4131 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4132 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4134 bufA
[0] = 'x'; bufA
[1] = 'y';
4135 n
= GetTextFaceA(dc
, 2, bufA
);
4136 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
4137 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
4139 n
= GetTextFaceA(dc
, 0, NULL
);
4140 ok(n
== sizeof faceA
||
4141 broken(n
== 0), /* win98, winMe */
4142 "GetTextFaceA returned %d\n", n
);
4144 DeleteObject(SelectObject(dc
, g
));
4145 ReleaseDC(NULL
, dc
);
4148 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
4149 SetLastError(0xdeadbeef);
4150 f
= CreateFontIndirectW(&fW
);
4151 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4153 win_skip("CreateFontIndirectW is not implemented\n");
4156 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
4159 g
= SelectObject(dc
, f
);
4160 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
4161 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4162 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
4164 /* Play with the count arg. */
4166 n
= GetTextFaceW(dc
, 0, bufW
);
4167 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
4168 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4171 n
= GetTextFaceW(dc
, 1, bufW
);
4172 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
4173 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4175 bufW
[0] = 'x'; bufW
[1] = 'y';
4176 n
= GetTextFaceW(dc
, 2, bufW
);
4177 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4178 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4180 n
= GetTextFaceW(dc
, 0, NULL
);
4181 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4183 DeleteObject(SelectObject(dc
, g
));
4184 ReleaseDC(NULL
, dc
);
4187 static void test_orientation(void)
4189 static const char test_str
[11] = "Test String";
4192 HFONT hfont
, old_hfont
;
4195 if (!is_truetype_font_installed("Arial"))
4197 skip("Arial is not installed\n");
4201 hdc
= CreateCompatibleDC(0);
4202 memset(&lf
, 0, sizeof(lf
));
4203 lstrcpyA(lf
.lfFaceName
, "Arial");
4205 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4206 hfont
= create_font("orientation", &lf
);
4207 old_hfont
= SelectObject(hdc
, hfont
);
4208 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4209 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4210 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4211 SelectObject(hdc
, old_hfont
);
4212 DeleteObject(hfont
);
4216 static void test_oemcharset(void)
4220 HFONT hfont
, old_hfont
;
4223 hdc
= CreateCompatibleDC(0);
4224 ZeroMemory(&lf
, sizeof(lf
));
4226 lf
.lfCharSet
= OEM_CHARSET
;
4227 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4228 lstrcpyA(lf
.lfFaceName
, "Terminal");
4229 hfont
= CreateFontIndirectA(&lf
);
4230 old_hfont
= SelectObject(hdc
, hfont
);
4231 charset
= GetTextCharset(hdc
);
4233 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4234 hfont
= SelectObject(hdc
, old_hfont
);
4235 GetObjectA(hfont
, sizeof(clf
), &clf
);
4236 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4237 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4238 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4239 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4240 DeleteObject(hfont
);
4244 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4245 const TEXTMETRICA
*lpntme
,
4246 DWORD FontType
, LPARAM lParam
)
4248 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4250 LOGFONTA lf
= *lpelfe
;
4254 /* skip bitmap, proportional or vertical font */
4255 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4256 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4257 lf
.lfFaceName
[0] == '@')
4260 /* skip linked font */
4261 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4262 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4265 /* skip linked font, like SimSun-ExtB */
4266 switch (lpelfe
->lfCharSet
) {
4267 case SHIFTJIS_CHARSET
:
4268 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4270 case GB2312_CHARSET
:
4271 case CHINESEBIG5_CHARSET
:
4272 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4274 case HANGEUL_CHARSET
:
4275 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4278 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4284 /* test with an odd height */
4287 hfont
= CreateFontIndirectA(&lf
);
4290 *(HFONT
*)lParam
= hfont
;
4296 static void test_GetGlyphOutline(void)
4299 GLYPHMETRICS gm
, gm2
;
4301 HFONT hfont
, old_hfont
;
4303 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4304 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4312 {ANSI_CHARSET
, 0x30, 0x30},
4313 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4314 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4315 {GB2312_CHARSET
, 0x8141, 0x4e04},
4316 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4320 if (!is_truetype_font_installed("Tahoma"))
4322 skip("Tahoma is not installed\n");
4326 hdc
= CreateCompatibleDC(0);
4327 memset(&lf
, 0, sizeof(lf
));
4329 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4330 SetLastError(0xdeadbeef);
4331 hfont
= CreateFontIndirectA(&lf
);
4332 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4333 old_hfont
= SelectObject(hdc
, hfont
);
4335 memset(&gm
, 0, sizeof(gm
));
4336 SetLastError(0xdeadbeef);
4337 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4338 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4340 memset(&gm
, 0, sizeof(gm
));
4341 SetLastError(0xdeadbeef);
4342 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4343 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4344 ok(GetLastError() == 0xdeadbeef ||
4345 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4346 "expected 0xdeadbeef, got %u\n", GetLastError());
4348 memset(&gm
, 0, sizeof(gm
));
4349 SetLastError(0xdeadbeef);
4350 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4351 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4352 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4354 memset(&gm
, 0, sizeof(gm
));
4355 SetLastError(0xdeadbeef);
4356 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4357 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4359 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4360 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4363 /* test for needed buffer size request on space char */
4364 memset(&gm
, 0, sizeof(gm
));
4365 SetLastError(0xdeadbeef);
4366 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4367 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4369 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4370 ok(gm
.gmBlackBoxX
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxX
);
4371 ok(gm
.gmBlackBoxY
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxY
);
4374 /* requesting buffer size for space char + error */
4375 memset(&gm
, 0, sizeof(gm
));
4376 SetLastError(0xdeadbeef);
4377 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4378 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4380 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4381 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4382 ok(gm
.gmBlackBoxX
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxX
);
4383 ok(gm
.gmBlackBoxY
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxY
);
4386 /* test GetGlyphOutline with a buffer too small */
4387 SetLastError(0xdeadbeef);
4388 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_NATIVE
, &gm
, sizeof(i
), &i
, &mat
);
4389 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4390 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4392 for (i
= 0; i
< sizeof(fmt
) / sizeof(fmt
[0]); ++i
)
4396 memset(&gm
, 0xab, sizeof(gm
));
4397 SetLastError(0xdeadbeef);
4398 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4399 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4401 if (fmt
[i
] == GGO_METRICS
)
4402 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4404 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4405 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4406 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4409 memset(&gm
, 0xab, sizeof(gm
));
4410 SetLastError(0xdeadbeef);
4411 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4412 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4414 if (fmt
[i
] == GGO_METRICS
)
4415 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4417 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4418 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4419 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4422 memset(&gm
, 0xab, sizeof(gm
));
4423 SetLastError(0xdeadbeef);
4424 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4425 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4427 if (fmt
[i
] == GGO_METRICS
)
4428 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4430 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4431 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4432 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4435 memset(&gm
, 0xab, sizeof(gm
));
4436 SetLastError(0xdeadbeef);
4437 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4438 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4440 if (fmt
[i
] == GGO_METRICS
) {
4441 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4442 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4443 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4447 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4448 memset(&gm2
, 0xab, sizeof(gm2
));
4449 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4450 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4455 SelectObject(hdc
, old_hfont
);
4456 DeleteObject(hfont
);
4458 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
4460 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4463 lf
.lfFaceName
[0] = '\0';
4464 lf
.lfCharSet
= c
[i
].cs
;
4465 lf
.lfPitchAndFamily
= 0;
4466 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4468 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4472 old_hfont
= SelectObject(hdc
, hfont
);
4474 /* expected to ignore superfluous bytes (sigle-byte character) */
4475 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4476 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4477 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4479 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4480 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4481 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4483 /* expected to ignore superfluous bytes (double-byte character) */
4484 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4485 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4486 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4487 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4489 /* expected to match wide-char version results */
4490 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4491 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4493 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4495 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4498 DeleteObject(SelectObject(hdc
, hfont
));
4501 DeleteObject(SelectObject(hdc
, old_hfont
));
4505 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4506 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4508 ret
= GetTextMetricsA(hdc
, &tm
);
4509 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4510 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4511 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4512 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4513 -lf
.lfHeight
, tm
.tmAveCharWidth
, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4514 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4515 "expected %d, got %d (%s:%d)\n",
4516 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4518 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4519 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4520 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4521 "expected %d, got %d (%s:%d)\n",
4522 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4525 hfont
= CreateFontIndirectA(&lf
);
4526 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4527 DeleteObject(SelectObject(hdc
, hfont
));
4528 ret
= GetTextMetricsA(hdc
, &tm
);
4529 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4530 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4531 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4532 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4533 "expected %d, got %d (%s:%d)\n",
4534 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4536 lf
.lfItalic
= FALSE
;
4537 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4538 hfont
= CreateFontIndirectA(&lf
);
4539 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4540 DeleteObject(SelectObject(hdc
, hfont
));
4541 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4542 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4543 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4544 "expected %d, got %d (%s:%d)\n",
4545 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4547 hfont
= SelectObject(hdc
, old_hfont
);
4548 DeleteObject(hfont
);
4554 /* bug #9995: there is a limit to the character width that can be specified */
4555 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4561 int ave_width
, height
, width
, ratio
, scale
;
4563 if (!is_truetype_font_installed( fontname
)) {
4564 skip("%s is not installed\n", fontname
);
4567 hdc
= CreateCompatibleDC(0);
4568 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4569 /* select width = 0 */
4570 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4571 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4572 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4574 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4575 of
= SelectObject( hdc
, hf
);
4576 ret
= GetTextMetricsA( hdc
, &tm
);
4577 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4578 height
= tm
.tmHeight
;
4579 ave_width
= tm
.tmAveCharWidth
;
4580 SelectObject( hdc
, of
);
4583 trace("height %d, ave width %d\n", height
, ave_width
);
4585 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4587 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4588 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4589 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4590 ok(hf
!= 0, "CreateFont failed\n");
4591 of
= SelectObject(hdc
, hf
);
4592 ret
= GetTextMetricsA(hdc
, &tm
);
4593 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4594 SelectObject(hdc
, of
);
4597 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4603 ratio
= width
/ height
;
4604 scale
= width
/ ave_width
;
4606 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4607 width
, height
, ratio
, width
, ave_width
, scale
);
4609 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4612 static void test_CreateFontIndirect(void)
4614 LOGFONTA lf
, getobj_lf
;
4617 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4619 memset(&lf
, 0, sizeof(lf
));
4620 lf
.lfCharSet
= ANSI_CHARSET
;
4621 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4624 lf
.lfQuality
= DEFAULT_QUALITY
;
4625 lf
.lfItalic
= FALSE
;
4626 lf
.lfWeight
= FW_DONTCARE
;
4628 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
4630 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4631 hfont
= CreateFontIndirectA(&lf
);
4632 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4633 SetLastError(0xdeadbeef);
4634 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
4635 ok(ret
, "GetObject failed: %d\n", GetLastError());
4636 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
4637 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
4638 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
4639 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
4640 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
4641 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
4642 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
4643 DeleteObject(hfont
);
4647 static void test_CreateFontIndirectEx(void)
4649 ENUMLOGFONTEXDVA lfex
;
4652 if (!pCreateFontIndirectExA
)
4654 win_skip("CreateFontIndirectExA is not available\n");
4658 if (!is_truetype_font_installed("Arial"))
4660 skip("Arial is not installed\n");
4664 SetLastError(0xdeadbeef);
4665 hfont
= pCreateFontIndirectExA(NULL
);
4666 ok(hfont
== NULL
, "got %p\n", hfont
);
4667 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4669 memset(&lfex
, 0, sizeof(lfex
));
4670 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
4671 hfont
= pCreateFontIndirectExA(&lfex
);
4672 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
4674 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
4675 DeleteObject(hfont
);
4678 static void free_font(void *font
)
4680 UnmapViewOfFile(font
);
4683 static void *load_font(const char *font_name
, DWORD
*font_size
)
4685 char file_name
[MAX_PATH
];
4686 HANDLE file
, mapping
;
4689 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
4690 strcat(file_name
, "\\fonts\\");
4691 strcat(file_name
, font_name
);
4693 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
4694 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
4696 *font_size
= GetFileSize(file
, NULL
);
4698 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4705 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
4708 CloseHandle(mapping
);
4712 static void test_AddFontMemResource(void)
4715 DWORD font_size
, num_fonts
;
4719 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
4721 win_skip("AddFontMemResourceEx is not available on this platform\n");
4725 font
= load_font("sserife.fon", &font_size
);
4728 skip("Unable to locate and load font sserife.fon\n");
4732 SetLastError(0xdeadbeef);
4733 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
4734 ok(!ret
, "AddFontMemResourceEx should fail\n");
4735 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4736 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4739 SetLastError(0xdeadbeef);
4740 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
4741 ok(!ret
, "AddFontMemResourceEx should fail\n");
4742 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4743 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4746 SetLastError(0xdeadbeef);
4747 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
4748 ok(!ret
, "AddFontMemResourceEx should fail\n");
4749 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4750 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4753 SetLastError(0xdeadbeef);
4754 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
4755 ok(!ret
, "AddFontMemResourceEx should fail\n");
4756 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4757 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4760 SetLastError(0xdeadbeef);
4761 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
4762 ok(!ret
, "AddFontMemResourceEx should fail\n");
4763 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4764 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4767 SetLastError(0xdeadbeef);
4768 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
4769 ok(!ret
, "AddFontMemResourceEx should fail\n");
4770 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4771 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4774 num_fonts
= 0xdeadbeef;
4775 SetLastError(0xdeadbeef);
4776 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
4777 ok(!ret
, "AddFontMemResourceEx should fail\n");
4778 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4779 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4781 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4783 if (0) /* hangs under windows 2000 */
4785 num_fonts
= 0xdeadbeef;
4786 SetLastError(0xdeadbeef);
4787 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
4788 ok(!ret
, "AddFontMemResourceEx should fail\n");
4789 ok(GetLastError() == 0xdeadbeef,
4790 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4792 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4795 num_fonts
= 0xdeadbeef;
4796 SetLastError(0xdeadbeef);
4797 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
4798 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
4799 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4800 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
4804 SetLastError(0xdeadbeef);
4805 bRet
= pRemoveFontMemResourceEx(ret
);
4806 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
4808 /* test invalid pointer to number of loaded fonts */
4809 font
= load_font("sserife.fon", &font_size
);
4810 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
4812 SetLastError(0xdeadbeef);
4813 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
4814 ok(!ret
, "AddFontMemResourceEx should fail\n");
4815 ok(GetLastError() == 0xdeadbeef,
4816 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4819 SetLastError(0xdeadbeef);
4820 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
4821 ok(!ret
, "AddFontMemResourceEx should fail\n");
4822 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4823 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4829 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4833 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4835 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4837 lf
= (LOGFONTA
*)lparam
;
4842 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4847 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4849 lf
= (LOGFONTA
*)lparam
;
4850 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
4853 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4860 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4865 static void test_EnumFonts(void)
4870 struct enum_fullname_data efnd
;
4872 if (!is_truetype_font_installed("Arial"))
4874 skip("Arial is not installed\n");
4878 /* Windows uses localized font face names, so Arial Bold won't be found */
4879 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
4881 skip("User locale is not English, skipping the test\n");
4885 hdc
= CreateCompatibleDC(0);
4887 /* check that the enumproc's retval is returned */
4888 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
4889 ok(ret
== 0xcafe, "got %08x\n", ret
);
4891 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
4892 ok(!ret
, "font Arial is not enumerated\n");
4893 ret
= strcmp(lf
.lfFaceName
, "Arial");
4894 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4895 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4897 strcpy(lf
.lfFaceName
, "Arial");
4898 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4899 ok(!ret
, "font Arial is not enumerated\n");
4900 ret
= strcmp(lf
.lfFaceName
, "Arial");
4901 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4902 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4904 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4905 ok(!ret
, "font Arial Bold is not enumerated\n");
4906 ret
= strcmp(lf
.lfFaceName
, "Arial");
4907 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4908 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4910 strcpy(lf
.lfFaceName
, "Arial Bold");
4911 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4912 ok(ret
, "font Arial Bold should not be enumerated\n");
4914 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
4915 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
4916 ret
= strcmp(lf
.lfFaceName
, "Arial");
4917 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4918 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4920 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
4921 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4922 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
4924 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4925 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4927 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
4928 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4929 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4931 /* MS Shell Dlg and MS Shell Dlg 2 must exist */
4932 memset(&lf
, 0, sizeof(lf
));
4933 lf
.lfCharSet
= DEFAULT_CHARSET
;
4935 memset(&efnd
, 0, sizeof(efnd
));
4936 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
4937 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4938 ok(ret
, "font MS Shell Dlg is not enumerated\n");
4939 ret
= strcmp((char*)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
4940 todo_wine
ok(!ret
, "expected MS Shell Dlg got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
4941 ret
= strcmp((char*)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
4942 ok(ret
, "did not expect MS Shell Dlg\n");
4944 memset(&efnd
, 0, sizeof(efnd
));
4945 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
4946 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4947 ok(ret
, "font MS Shell Dlg 2 is not enumerated\n");
4948 ret
= strcmp((char*)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
4949 todo_wine
ok(!ret
, "expected MS Shell Dlg 2 got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
4950 ret
= strcmp((char*)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
4951 ok(ret
, "did not expect MS Shell Dlg 2\n");
4956 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4958 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
4959 const char *fullname
= (const char *)lParam
;
4961 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
4966 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
4971 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
4978 static void test_fullname(void)
4980 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4981 WCHAR bufW
[LF_FULLFACESIZE
];
4982 char bufA
[LF_FULLFACESIZE
];
4989 hdc
= CreateCompatibleDC(0);
4990 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4992 memset(&lf
, 0, sizeof(lf
));
4993 lf
.lfCharSet
= ANSI_CHARSET
;
4994 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4997 lf
.lfQuality
= DEFAULT_QUALITY
;
4998 lf
.lfItalic
= FALSE
;
4999 lf
.lfWeight
= FW_DONTCARE
;
5001 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
5003 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
5005 skip("%s is not installed\n", TestName
[i
]);
5009 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5010 hfont
= CreateFontIndirectA(&lf
);
5011 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5013 of
= SelectObject(hdc
, hfont
);
5016 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5017 ok(ret
, "face full name could not be read\n");
5018 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
5019 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
5020 SelectObject(hdc
, of
);
5021 DeleteObject(hfont
);
5026 static WCHAR
*prepend_at(WCHAR
*family
)
5031 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
5036 static void test_fullname2_helper(const char *Family
)
5038 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
5039 struct enum_fullname_data efnd
;
5046 DWORD otm_size
, ret
, buf_size
;
5047 OUTLINETEXTMETRICA
*otm
;
5048 BOOL want_vertical
, get_vertical
;
5049 want_vertical
= ( Family
[0] == '@' );
5051 hdc
= CreateCompatibleDC(0);
5052 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5054 memset(&lf
, 0, sizeof(lf
));
5055 lf
.lfCharSet
= DEFAULT_CHARSET
;
5056 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5059 lf
.lfQuality
= DEFAULT_QUALITY
;
5060 lf
.lfItalic
= FALSE
;
5061 lf
.lfWeight
= FW_DONTCARE
;
5062 strcpy(lf
.lfFaceName
, Family
);
5064 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
5065 if (efnd
.total
== 0)
5066 skip("%s is not installed\n", lf
.lfFaceName
);
5068 for (i
= 0; i
< efnd
.total
; i
++)
5070 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
5071 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
5072 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
5074 get_vertical
= ( FamilyName
[0] == '@' );
5075 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
5077 lstrcpyA(lf
.lfFaceName
, FaceName
);
5078 hfont
= CreateFontIndirectA(&lf
);
5079 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5081 of
= SelectObject(hdc
, hfont
);
5082 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
5083 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
5084 if (buf_size
== GDI_ERROR
) continue;
5086 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5087 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5089 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5090 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5091 memset(otm
, 0, otm_size
);
5092 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
5093 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
5094 if (ret
== 0) continue;
5098 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5099 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5100 ok(ret
, "%s: FAMILY (family name) could not be read\n", FamilyName
);
5101 if (want_vertical
) bufW
= prepend_at(bufW
);
5102 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5103 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
5104 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
5105 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
5109 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
5110 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5111 ok(ret
, "FULL_NAME (face name) could not be read\n");
5112 if (want_vertical
) bufW
= prepend_at(bufW
);
5113 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5114 ok(!lstrcmpA(FaceName
, bufA
), "%s: font face names don't match: returned %s, expect %s\n", FamilyName
, FaceName
, bufA
);
5115 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
5116 ok(!lstrcmpA(FaceName
, otmStr
), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName
, FaceName
, otmStr
);
5120 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5121 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5122 ok(ret
, "%s: SUBFAMILY (style name) could not be read\n", FamilyName
);
5123 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5124 ok(!lstrcmpA(StyleName
, bufA
), "%s: style names don't match: returned %s, expect %s\n", FamilyName
, StyleName
, bufA
);
5125 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
5126 ok(!lstrcmpA(StyleName
, otmStr
), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName
, StyleName
, otmStr
);
5130 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
5131 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5132 ok(ret
, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName
);
5133 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5134 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
5135 ok(!lstrcmpA(otmStr
, bufA
), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName
, otmStr
, bufA
);
5137 SelectObject(hdc
, of
);
5138 DeleteObject(hfont
);
5140 HeapFree(GetProcessHeap(), 0, otm
);
5141 HeapFree(GetProcessHeap(), 0, bufW
);
5142 HeapFree(GetProcessHeap(), 0, bufA
);
5147 static void test_fullname2(void)
5149 test_fullname2_helper("Arial");
5150 test_fullname2_helper("DejaVu Sans");
5151 test_fullname2_helper("Lucida Sans");
5152 test_fullname2_helper("Tahoma");
5153 test_fullname2_helper("Webdings");
5154 test_fullname2_helper("Wingdings");
5155 test_fullname2_helper("SimSun");
5156 test_fullname2_helper("NSimSun");
5157 test_fullname2_helper("MingLiu");
5158 test_fullname2_helper("PMingLiu");
5159 test_fullname2_helper("WenQuanYi Micro Hei");
5160 test_fullname2_helper("MS UI Gothic");
5161 test_fullname2_helper("Ume UI Gothic");
5162 test_fullname2_helper("MS Gothic");
5163 test_fullname2_helper("Ume Gothic");
5164 test_fullname2_helper("MS PGothic");
5165 test_fullname2_helper("Ume P Gothic");
5166 test_fullname2_helper("Gulim");
5167 test_fullname2_helper("Batang");
5168 test_fullname2_helper("UnBatang");
5169 test_fullname2_helper("UnDotum");
5170 test_fullname2_helper("@SimSun");
5171 test_fullname2_helper("@NSimSun");
5172 test_fullname2_helper("@MingLiu");
5173 test_fullname2_helper("@PMingLiu");
5174 test_fullname2_helper("@WenQuanYi Micro Hei");
5175 test_fullname2_helper("@MS UI Gothic");
5176 test_fullname2_helper("@Ume UI Gothic");
5177 test_fullname2_helper("@MS Gothic");
5178 test_fullname2_helper("@Ume Gothic");
5179 test_fullname2_helper("@MS PGothic");
5180 test_fullname2_helper("@Ume P Gothic");
5181 test_fullname2_helper("@Gulim");
5182 test_fullname2_helper("@Batang");
5183 test_fullname2_helper("@UnBatang");
5184 test_fullname2_helper("@UnDotum");
5188 static void test_GetGlyphOutline_empty_contour(void)
5192 HFONT hfont
, hfont_prev
;
5193 TTPOLYGONHEADER
*header
;
5198 memset(&lf
, 0, sizeof(lf
));
5200 lstrcpyA(lf
.lfFaceName
, "wine_test");
5202 hfont
= CreateFontIndirectA(&lf
);
5203 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5207 hfont_prev
= SelectObject(hdc
, hfont
);
5208 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5210 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5211 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5213 header
= (TTPOLYGONHEADER
*)buf
;
5214 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5215 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5216 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5217 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5218 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5219 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5220 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5221 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5223 SelectObject(hdc
, hfont_prev
);
5224 DeleteObject(hfont
);
5225 ReleaseDC(NULL
, hdc
);
5228 static void test_GetGlyphOutline_metric_clipping(void)
5232 HFONT hfont
, hfont_prev
;
5238 memset(&lf
, 0, sizeof(lf
));
5240 lstrcpyA(lf
.lfFaceName
, "wine_test");
5242 SetLastError(0xdeadbeef);
5243 hfont
= CreateFontIndirectA(&lf
);
5244 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5248 hfont_prev
= SelectObject(hdc
, hfont
);
5249 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5251 SetLastError(0xdeadbeef);
5252 ret
= GetTextMetricsA(hdc
, &tm
);
5253 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5255 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5256 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5257 "Glyph top(%d) exceeds ascent(%d)\n",
5258 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5259 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5260 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5261 "Glyph bottom(%d) exceeds descent(%d)\n",
5262 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5264 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5265 GetTextMetricsW(hdc
, &tmW
);
5267 ok( tmW
.tmLastChar
== 0xfffe, "got %04x\n", tmW
.tmLastChar
);
5269 SelectObject(hdc
, hfont_prev
);
5270 DeleteObject(hfont
);
5271 ReleaseDC(NULL
, hdc
);
5274 static void test_CreateScalableFontResource(void)
5276 char ttf_name
[MAX_PATH
];
5277 char tmp_path
[MAX_PATH
];
5278 char fot_name
[MAX_PATH
];
5283 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
5285 win_skip("AddFontResourceExA is not available on this platform\n");
5289 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5291 skip("Failed to create ttf file for testing\n");
5295 trace("created %s\n", ttf_name
);
5297 ret
= is_truetype_font_installed("wine_test");
5298 ok(!ret
, "font wine_test should not be enumerated\n");
5300 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
5301 ok(ret
, "GetTempPath() error %d\n", GetLastError());
5302 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
5303 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
5305 ret
= GetFileAttributesA(fot_name
);
5306 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
5308 SetLastError(0xdeadbeef);
5309 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5310 ok(!ret
, "CreateScalableFontResource() should fail\n");
5311 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5313 SetLastError(0xdeadbeef);
5314 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
5315 ok(!ret
, "CreateScalableFontResource() should fail\n");
5316 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5318 file_part
= strrchr(ttf_name
, '\\');
5319 SetLastError(0xdeadbeef);
5320 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
5321 ok(!ret
, "CreateScalableFontResource() should fail\n");
5322 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5324 SetLastError(0xdeadbeef);
5325 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
5326 ok(!ret
, "CreateScalableFontResource() should fail\n");
5327 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5329 SetLastError(0xdeadbeef);
5330 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
5331 ok(!ret
, "CreateScalableFontResource() should fail\n");
5332 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5334 ret
= DeleteFileA(fot_name
);
5335 ok(ret
, "DeleteFile() error %d\n", GetLastError());
5337 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5338 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5340 /* test public font resource */
5341 SetLastError(0xdeadbeef);
5342 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5343 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5345 ret
= is_truetype_font_installed("wine_test");
5346 ok(!ret
, "font wine_test should not be enumerated\n");
5348 SetLastError(0xdeadbeef);
5349 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5350 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5352 ret
= is_truetype_font_installed("wine_test");
5353 ok(ret
, "font wine_test should be enumerated\n");
5355 test_GetGlyphOutline_empty_contour();
5356 test_GetGlyphOutline_metric_clipping();
5358 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5359 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
5361 SetLastError(0xdeadbeef);
5362 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5363 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5365 ret
= is_truetype_font_installed("wine_test");
5366 ok(!ret
, "font wine_test should not be enumerated\n");
5368 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5369 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5371 /* test refcounting */
5372 for (i
= 0; i
< 5; i
++)
5374 SetLastError(0xdeadbeef);
5375 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5376 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5378 for (i
= 0; i
< 5; i
++)
5380 SetLastError(0xdeadbeef);
5381 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5382 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5384 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5385 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5387 DeleteFileA(fot_name
);
5389 /* test hidden font resource */
5390 SetLastError(0xdeadbeef);
5391 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
5392 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5394 ret
= is_truetype_font_installed("wine_test");
5395 ok(!ret
, "font wine_test should not be enumerated\n");
5397 SetLastError(0xdeadbeef);
5398 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5399 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5401 ret
= is_truetype_font_installed("wine_test");
5403 ok(!ret
, "font wine_test should not be enumerated\n");
5405 /* XP allows removing a private font added with 0 flags */
5406 SetLastError(0xdeadbeef);
5407 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5408 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5410 ret
= is_truetype_font_installed("wine_test");
5411 ok(!ret
, "font wine_test should not be enumerated\n");
5413 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5414 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5416 DeleteFileA(fot_name
);
5417 DeleteFileA(ttf_name
);
5420 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
5423 HFONT hfont
, hfont_prev
;
5427 static const WCHAR str
[] = { 0x2025 };
5429 *installed
= is_truetype_font_installed(name
);
5433 lf
.lfEscapement
= 0;
5434 lf
.lfOrientation
= 0;
5435 lf
.lfWeight
= FW_DONTCARE
;
5439 lf
.lfCharSet
= DEFAULT_CHARSET
;
5440 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
5441 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5442 lf
.lfQuality
= DEFAULT_QUALITY
;
5443 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
5444 strcpy(lf
.lfFaceName
, name
);
5446 hfont
= CreateFontIndirectA(&lf
);
5447 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
5451 hfont_prev
= SelectObject(hdc
, hfont
);
5452 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5454 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
5455 ok(ret
, "GetTextFaceA failed\n");
5456 *selected
= !strcmp(facename
, name
);
5458 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
5459 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5461 memset(gm
, 0, sizeof *gm
);
5463 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
5464 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
5466 SelectObject(hdc
, hfont_prev
);
5467 DeleteObject(hfont
);
5468 ReleaseDC(NULL
, hdc
);
5471 static void check_vertical_metrics(const char *face
)
5474 HFONT hfont
, hfont_prev
;
5477 GLYPHMETRICS rgm
, vgm
;
5478 const UINT code
= 0x5EAD, height
= 1000;
5481 OUTLINETEXTMETRICA otm
;
5482 USHORT numOfLongVerMetrics
;
5486 memset(&lf
, 0, sizeof(lf
));
5487 strcpy(lf
.lfFaceName
, face
);
5488 lf
.lfHeight
= -height
;
5489 lf
.lfCharSet
= DEFAULT_CHARSET
;
5490 lf
.lfEscapement
= lf
.lfOrientation
= 900;
5491 hfont
= CreateFontIndirectA(&lf
);
5492 hfont_prev
= SelectObject(hdc
, hfont
);
5493 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
5494 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5495 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
5496 ok(ret
, "GetCharABCWidthsW failed\n");
5497 DeleteObject(SelectObject(hdc
, hfont_prev
));
5499 memset(&lf
, 0, sizeof(lf
));
5500 strcpy(lf
.lfFaceName
, "@");
5501 strcat(lf
.lfFaceName
, face
);
5502 lf
.lfHeight
= -height
;
5503 lf
.lfCharSet
= DEFAULT_CHARSET
;
5504 hfont
= CreateFontIndirectA(&lf
);
5505 hfont_prev
= SelectObject(hdc
, hfont
);
5506 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
5507 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5509 memset(&otm
, 0, sizeof(otm
));
5510 otm
.otmSize
= sizeof(otm
);
5511 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
5512 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
5514 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
5515 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
5517 SHORT topSideBearing
;
5519 if (!pGetGlyphIndicesW
) {
5520 win_skip("GetGlyphIndices is not available on this platform\n");
5523 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
5524 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
5525 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
5526 if (numOfLongVerMetrics
> idx
)
5527 offset
= idx
* 2 + 1;
5529 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
5530 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
5531 &topSideBearing
, sizeof(SHORT
));
5532 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
5533 topSideBearing
= GET_BE_WORD(topSideBearing
);
5534 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
5535 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
5536 "expected %d, got %d\n",
5537 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
5542 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
5543 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5544 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
5547 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
5548 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
5549 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5550 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
5552 DeleteObject(SelectObject(hdc
, hfont_prev
));
5553 ReleaseDC(NULL
, hdc
);
5556 static void test_vertical_font(void)
5558 char ttf_name
[MAX_PATH
];
5560 BOOL ret
, installed
, selected
;
5563 const char* face_list
[] = {
5564 "@WineTestVertical", /* has vmtx table */
5565 "@Ume Gothic", /* doesn't have vmtx table */
5566 "@MS UI Gothic", /* has vmtx table, available on native */
5569 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
5571 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5575 if (!write_ttf_file("vertical.ttf", ttf_name
))
5577 skip("Failed to create ttf file for testing\n");
5581 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5582 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5584 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
5585 ok(installed
, "WineTestVertical is not installed\n");
5586 ok(selected
, "WineTestVertical is not selected\n");
5587 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5588 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5589 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5591 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
5592 ok(installed
, "@WineTestVertical is not installed\n");
5593 ok(selected
, "@WineTestVertical is not selected\n");
5594 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5595 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5596 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5598 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
5600 for (i
= 0; i
< sizeof(face_list
)/sizeof(face_list
[0]); i
++) {
5601 const char* face
= face_list
[i
];
5602 if (!is_truetype_font_installed(face
)) {
5603 skip("%s is not installed\n", face
);
5606 trace("Testing %s...\n", face
);
5607 check_vertical_metrics(&face
[1]);
5610 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5611 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5613 DeleteFileA(ttf_name
);
5616 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
5617 DWORD type
, LPARAM lParam
)
5619 if (lf
->lfFaceName
[0] == '@') {
5625 static void test_east_asian_font_selection(void)
5628 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
5629 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
5634 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
5638 char face_name
[LF_FACESIZE
];
5641 memset(&lf
, 0, sizeof lf
);
5642 lf
.lfFaceName
[0] = '\0';
5643 lf
.lfCharSet
= charset
[i
];
5645 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
5647 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
5651 hfont
= CreateFontIndirectA(&lf
);
5652 hfont
= SelectObject(hdc
, hfont
);
5653 memset(face_name
, 0, sizeof face_name
);
5654 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5655 ok(ret
&& face_name
[0] != '@',
5656 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5657 DeleteObject(SelectObject(hdc
, hfont
));
5659 memset(&lf
, 0, sizeof lf
);
5660 strcpy(lf
.lfFaceName
, "@");
5661 lf
.lfCharSet
= charset
[i
];
5662 hfont
= CreateFontIndirectA(&lf
);
5663 hfont
= SelectObject(hdc
, hfont
);
5664 memset(face_name
, 0, sizeof face_name
);
5665 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5666 ok(ret
&& face_name
[0] == '@',
5667 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5668 DeleteObject(SelectObject(hdc
, hfont
));
5670 ReleaseDC(NULL
, hdc
);
5673 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
5675 HDC hdc
= CreateCompatibleDC(0);
5680 hfont
= CreateFontIndirectA(lf
);
5681 ok(hfont
!= 0, "CreateFontIndirect failed\n");
5683 SelectObject(hdc
, hfont
);
5684 ret
= GetTextMetricsA(hdc
, &tm
);
5685 ok(ret
, "GetTextMetrics failed\n");
5686 ret
= tm
.tmDigitizedAspectX
;
5687 if (height
) *height
= tm
.tmHeight
;
5690 DeleteObject(hfont
);
5695 static void test_stock_fonts(void)
5697 static const int font
[] =
5699 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
5700 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5702 static const struct test_data
5704 int charset
, weight
, height
, height_pixels
, dpi
;
5705 const char face_name
[LF_FACESIZE
];
5708 { /* ANSI_FIXED_FONT */
5709 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
5710 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
5713 { /* ANSI_VAR_FONT */
5714 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
5715 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
5719 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5720 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5721 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5722 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5723 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5724 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5727 { /* DEVICE_DEFAULT_FONT */
5728 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5729 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5730 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5731 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5732 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5733 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5736 { /* DEFAULT_GUI_FONT */
5737 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
5738 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
5739 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
5740 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
5741 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
5742 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
5743 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
5744 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
5745 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
5746 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
5752 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
5758 hfont
= GetStockObject(font
[i
]);
5759 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
5761 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
5762 if (ret
!= sizeof(lf
))
5765 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
5769 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
5771 if (lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
)
5776 ret
= get_font_dpi(&lf
, &height
);
5777 if (ret
!= td
[i
][j
].dpi
)
5779 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5780 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
5784 /* FIXME: Remove once Wine is fixed */
5785 if (td
[i
][j
].dpi
!= 96 &&
5786 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5787 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
5788 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5789 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
5791 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5793 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5795 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
5796 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
5797 if (td
[i
][j
].face_name
[0] == '?')
5799 /* Wine doesn't have this font, skip this case for now.
5800 Actually, the face name is localized on Windows and varies
5801 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5802 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
5806 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
);
5813 static void test_max_height(void)
5817 HFONT hfont
, hfont_old
;
5818 TEXTMETRICA tm1
, tm
;
5820 LONG invalid_height
[] = { -65536, -123456, 123456 };
5823 memset(&tm1
, 0, sizeof(tm1
));
5824 memset(&lf
, 0, sizeof(lf
));
5825 strcpy(lf
.lfFaceName
, "Tahoma");
5830 /* get 1 ppem value */
5831 hfont
= CreateFontIndirectA(&lf
);
5832 hfont_old
= SelectObject(hdc
, hfont
);
5833 r
= GetTextMetricsA(hdc
, &tm1
);
5834 ok(r
, "GetTextMetrics failed\n");
5835 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5836 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5837 DeleteObject(SelectObject(hdc
, hfont_old
));
5839 /* test the largest value */
5840 lf
.lfHeight
= -((1 << 16) - 1);
5841 hfont
= CreateFontIndirectA(&lf
);
5842 hfont_old
= SelectObject(hdc
, hfont
);
5843 memset(&tm
, 0, sizeof(tm
));
5844 r
= GetTextMetricsA(hdc
, &tm
);
5845 ok(r
, "GetTextMetrics failed\n");
5846 ok(tm
.tmHeight
> tm1
.tmHeight
,
5847 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5848 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
5849 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5850 DeleteObject(SelectObject(hdc
, hfont_old
));
5852 /* test an invalid value */
5853 for (i
= 0; i
< sizeof(invalid_height
)/sizeof(invalid_height
[0]); i
++) {
5854 lf
.lfHeight
= invalid_height
[i
];
5855 hfont
= CreateFontIndirectA(&lf
);
5856 hfont_old
= SelectObject(hdc
, hfont
);
5857 memset(&tm
, 0, sizeof(tm
));
5858 r
= GetTextMetricsA(hdc
, &tm
);
5859 ok(r
, "GetTextMetrics failed\n");
5860 ok(tm
.tmHeight
== tm1
.tmHeight
,
5861 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5862 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
5863 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5864 DeleteObject(SelectObject(hdc
, hfont_old
));
5867 ReleaseDC(NULL
, hdc
);
5871 static void test_vertical_order(void)
5873 struct enum_font_data efd
;
5878 hdc
= CreateCompatibleDC(0);
5879 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5881 memset(&lf
, 0, sizeof(lf
));
5882 lf
.lfCharSet
= DEFAULT_CHARSET
;
5883 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5886 lf
.lfQuality
= DEFAULT_QUALITY
;
5887 lf
.lfItalic
= FALSE
;
5888 lf
.lfWeight
= FW_DONTCARE
;
5890 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
5891 for (i
= 0; i
< efd
.total
; i
++)
5893 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
5894 for (j
= 0; j
< efd
.total
; j
++)
5896 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
5898 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
5906 static void test_GetCharWidth32(void)
5916 if (!pGetCharWidth32A
|| !pGetCharWidth32W
)
5918 win_skip("GetCharWidth32A/W not available on this platform\n");
5922 memset(&lf
, 0, sizeof(lf
));
5923 strcpy(lf
.lfFaceName
, "System");
5926 hfont
= CreateFontIndirectA(&lf
);
5928 hfont
= SelectObject(hdc
, hfont
);
5930 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5931 ok(ret
, "GetCharWidth32W should have succeeded\n");
5932 ret
= pGetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
5933 ok(ret
, "GetCharWidth32A should have succeeded\n");
5934 ok (bufferA
== bufferW
, "Widths should be the same\n");
5935 ok (bufferA
> 0," Width should be greater than zero\n");
5937 hfont
= SelectObject(hdc
, hfont
);
5938 DeleteObject(hfont
);
5939 ReleaseDC(NULL
, hdc
);
5941 memset(&lf
, 0, sizeof(lf
));
5942 strcpy(lf
.lfFaceName
, "Tahoma");
5945 hfont
= CreateFontIndirectA(&lf
);
5946 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
5949 SetMapMode( hdc
, MM_ANISOTROPIC
);
5950 SelectObject(hdc
, hfont
);
5952 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5953 ok(ret
, "GetCharWidth32W should have succeeded\n");
5954 ok (bufferW
> 0," Width should be greater than zero\n");
5955 SetWindowExtEx(hdc
, -1,-1,NULL
);
5956 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5957 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5958 ok(ret
, "GetCharWidth32W should have succeeded\n");
5959 ok (bufferW
> 0," Width should be greater than zero\n");
5960 SetGraphicsMode(hdc
, GM_ADVANCED
);
5961 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5962 ok(ret
, "GetCharWidth32W should have succeeded\n");
5963 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
5964 SetWindowExtEx(hdc
, 1,1,NULL
);
5965 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5966 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5967 ok(ret
, "GetCharWidth32W should have succeeded\n");
5968 ok (bufferW
> 0," Width should be greater than zero\n");
5969 SetGraphicsMode(hdc
, GM_ADVANCED
);
5970 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5971 ok(ret
, "GetCharWidth32W should have succeeded\n");
5972 ok (bufferW
> 0," Width should be greater than zero\n");
5974 ReleaseDC(hwnd
, hdc
);
5975 DestroyWindow(hwnd
);
5977 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
5980 SetMapMode( hdc
, MM_ANISOTROPIC
);
5981 SelectObject(hdc
, hfont
);
5983 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5984 ok(ret
, "GetCharWidth32W should have succeeded\n");
5985 ok (bufferW
> 0," Width should be greater than zero\n");
5986 SetWindowExtEx(hdc
, -1,-1,NULL
);
5987 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5988 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5989 ok(ret
, "GetCharWidth32W should have succeeded\n");
5990 ok (bufferW
> 0," Width should be greater than zero\n");
5991 SetGraphicsMode(hdc
, GM_ADVANCED
);
5992 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5993 ok(ret
, "GetCharWidth32W should have succeeded\n");
5994 ok (bufferW
> 0," Width should be greater than zero\n");
5995 SetWindowExtEx(hdc
, 1,1,NULL
);
5996 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5997 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5998 ok(ret
, "GetCharWidth32W should have succeeded\n");
5999 ok (bufferW
> 0," Width should be greater than zero\n");
6000 SetGraphicsMode(hdc
, GM_ADVANCED
);
6001 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6002 ok(ret
, "GetCharWidth32W should have succeeded\n");
6003 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
6005 ReleaseDC(hwnd
, hdc
);
6006 DestroyWindow(hwnd
);
6007 DeleteObject(hfont
);
6010 static void test_fake_bold_font(void)
6013 HFONT hfont
, hfont_old
;
6020 if (!pGetCharWidth32A
|| !pGetCharABCWidthsA
) {
6021 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6025 /* Test outline font */
6026 memset(&lf
, 0, sizeof(lf
));
6027 strcpy(lf
.lfFaceName
, "Wingdings");
6028 lf
.lfWeight
= FW_NORMAL
;
6029 lf
.lfCharSet
= SYMBOL_CHARSET
;
6030 hfont
= CreateFontIndirectA(&lf
);
6033 hfont_old
= SelectObject(hdc
, hfont
);
6036 ret
= GetTextMetricsA(hdc
, &tm
[0]);
6037 ok(ret
, "got %d\n", ret
);
6038 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[0]);
6039 ok(ret
, "got %d\n", ret
);
6041 lf
.lfWeight
= FW_BOLD
;
6042 hfont
= CreateFontIndirectA(&lf
);
6043 DeleteObject(SelectObject(hdc
, hfont
));
6046 ret
= GetTextMetricsA(hdc
, &tm
[1]);
6047 ok(ret
, "got %d\n", ret
);
6048 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[1]);
6049 ok(ret
, "got %d\n", ret
);
6051 DeleteObject(SelectObject(hdc
, hfont_old
));
6052 ReleaseDC(NULL
, hdc
);
6054 /* compare results (outline) */
6055 ok(tm
[0].tmHeight
== tm
[1].tmHeight
, "expected %d, got %d\n", tm
[0].tmHeight
, tm
[1].tmHeight
);
6056 ok(tm
[0].tmAscent
== tm
[1].tmAscent
, "expected %d, got %d\n", tm
[0].tmAscent
, tm
[1].tmAscent
);
6057 ok(tm
[0].tmDescent
== tm
[1].tmDescent
, "expected %d, got %d\n", tm
[0].tmDescent
, tm
[1].tmDescent
);
6058 ok((tm
[0].tmAveCharWidth
+ 1) == tm
[1].tmAveCharWidth
,
6059 "expected %d, got %d\n", tm
[0].tmAveCharWidth
+ 1, tm
[1].tmAveCharWidth
);
6060 ok((tm
[0].tmMaxCharWidth
+ 1) == tm
[1].tmMaxCharWidth
,
6061 "expected %d, got %d\n", tm
[0].tmMaxCharWidth
+ 1, tm
[1].tmMaxCharWidth
);
6062 ok(tm
[0].tmOverhang
== tm
[1].tmOverhang
, "expected %d, got %d\n", tm
[0].tmOverhang
, tm
[1].tmOverhang
);
6063 w
[0] = abc
[0].abcA
+ abc
[0].abcB
+ abc
[0].abcC
;
6064 w
[1] = abc
[1].abcA
+ abc
[1].abcB
+ abc
[1].abcC
;
6065 ok((w
[0] + 1) == w
[1], "expected %d, got %d\n", w
[0] + 1, w
[1]);
6069 static void test_bitmap_font_glyph_index(void)
6071 const WCHAR text
[] = {'#','!','/','b','i','n','/','s','h',0};
6075 } bitmap_font_list
[] = {
6076 { "Courier", ANSI_CHARSET
},
6077 { "Small Fonts", ANSI_CHARSET
},
6078 { "Fixedsys", DEFAULT_CHARSET
},
6079 { "System", DEFAULT_CHARSET
}
6084 CHAR facename
[LF_FACESIZE
];
6095 if (!pGetGlyphIndicesW
|| !pGetGlyphIndicesA
) {
6096 win_skip("GetGlyphIndices is unavailable\n");
6100 hdc
= CreateCompatibleDC(0);
6101 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6103 memset(&bmi
, 0, sizeof(bmi
));
6104 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
6105 bmi
.bmiHeader
.biBitCount
= 32;
6106 bmi
.bmiHeader
.biPlanes
= 1;
6107 bmi
.bmiHeader
.biWidth
= 128;
6108 bmi
.bmiHeader
.biHeight
= 32;
6109 bmi
.bmiHeader
.biCompression
= BI_RGB
;
6111 for (i
= 0; i
< sizeof(bitmap_font_list
)/sizeof(bitmap_font_list
[0]); i
++) {
6112 memset(&lf
, 0, sizeof(lf
));
6113 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
6114 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
6115 hFont
= CreateFontIndirectA(&lf
);
6116 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
6117 hFont
= SelectObject(hdc
, hFont
);
6118 ret
= GetTextMetricsA(hdc
, &tm
);
6119 ok(ret
, "GetTextMetric failed\n");
6120 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
6121 ok(ret
, "GetTextFace failed\n");
6122 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
6123 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
6126 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
6127 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
6131 for (j
= 0; j
< 2; j
++) {
6133 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
6134 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
6135 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6138 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
6142 int len
= lstrlenW(text
);
6143 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
6144 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
6145 ok(ret
, "GetGlyphIndices failed\n");
6146 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
6147 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
6148 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
6149 HeapFree(GetProcessHeap(), 0, indices
);
6153 ok(ret
, "ExtTextOutW failed\n");
6154 SelectObject(hdc
, hBmpPrev
);
6157 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
6158 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6159 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6161 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
6163 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6166 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
6167 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
6171 for (j
= 0; j
< 2; j
++) {
6174 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6177 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6180 ret
= pGetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6181 ok(ret
, "GetGlyphIndices failed\n");
6182 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6183 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6186 ok(ret
, "ExtTextOutA failed\n");
6187 SelectObject(hdc
, hBmpPrev
);
6190 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6191 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6193 for (j
= 0; j
< 2; j
++)
6194 DeleteObject(hBmp
[j
]);
6195 hFont
= SelectObject(hdc
, hFont
);
6196 DeleteObject(hFont
);
6209 test_outline_font();
6210 test_bitmap_font_metrics();
6211 test_GdiGetCharDimensions();
6212 test_GetCharABCWidths();
6213 test_text_extents();
6214 test_GetGlyphIndices();
6215 test_GetKerningPairs();
6216 test_GetOutlineTextMetrics();
6217 test_SetTextJustification();
6218 test_font_charset();
6219 test_GdiGetCodePage();
6220 test_GetFontUnicodeRanges();
6221 test_nonexistent_font();
6223 test_height_selection();
6224 test_AddFontMemResource();
6227 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6228 * I'd like to avoid them in this test.
6230 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
6231 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
6232 if (is_truetype_font_installed("Arial Black") &&
6233 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6235 test_EnumFontFamilies("", ANSI_CHARSET
);
6236 test_EnumFontFamilies("", SYMBOL_CHARSET
);
6237 test_EnumFontFamilies("", DEFAULT_CHARSET
);
6240 skip("Arial Black or Symbol/Wingdings is not installed\n");
6241 test_EnumFontFamiliesEx_default_charset();
6242 test_GetTextMetrics();
6243 test_GdiRealizationInfo();
6245 test_GetGlyphOutline();
6246 test_GetTextMetrics2("Tahoma", -11);
6247 test_GetTextMetrics2("Tahoma", -55);
6248 test_GetTextMetrics2("Tahoma", -110);
6249 test_GetTextMetrics2("Arial", -11);
6250 test_GetTextMetrics2("Arial", -55);
6251 test_GetTextMetrics2("Arial", -110);
6252 test_CreateFontIndirect();
6253 test_CreateFontIndirectEx();
6257 test_east_asian_font_selection();
6259 test_vertical_order();
6260 test_GetCharWidth32();
6261 test_fake_bold_font();
6262 test_bitmap_font_glyph_index();
6264 /* These tests should be last test until RemoveFontResource
6265 * is properly implemented.
6267 test_vertical_font();
6268 test_CreateScalableFontResource();