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 static inline BOOL
match_off_by_n(int a
, int b
, unsigned int n
)
35 return abs(a
- b
) <= n
;
37 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
38 #define near_match(a, b) match_off_by_n((a), (b), 6)
39 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
41 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
42 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
43 static BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
44 static BOOL (WINAPI
*pGetCharABCWidthsA
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
45 static BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
46 static BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
47 static BOOL (WINAPI
*pGetCharWidth32A
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
48 static BOOL (WINAPI
*pGetCharWidth32W
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
49 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
50 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
51 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
52 static BOOL (WINAPI
*pGetTextExtentExPointI
)(HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
53 LPINT nfit
, LPINT dxs
, LPSIZE size
);
54 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
55 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDVA
*);
56 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
57 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
58 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
59 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
60 static BOOL (WINAPI
*pGetFontRealizationInfo
)(HDC hdc
, DWORD
*);
61 static BOOL (WINAPI
*pGetFontFileInfo
)(DWORD
, DWORD
, void *, DWORD
, DWORD
*);
62 static BOOL (WINAPI
*pGetFontFileData
)(DWORD
, DWORD
, ULONGLONG
, void *, DWORD
);
64 static HMODULE hgdi32
= 0;
65 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
66 static WORD system_lang_id
;
68 #ifdef WORDS_BIGENDIAN
69 #define GET_BE_WORD(x) (x)
70 #define GET_BE_DWORD(x) (x)
72 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
73 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
76 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
77 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
78 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
79 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
80 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
81 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
83 static void init(void)
85 hgdi32
= GetModuleHandleA("gdi32.dll");
87 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
88 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
89 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
90 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
91 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
92 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
93 pGetCharWidth32A
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32A");
94 pGetCharWidth32W
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32W");
95 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
96 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
97 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
98 pGetTextExtentExPointI
= (void *)GetProcAddress(hgdi32
, "GetTextExtentExPointI");
99 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
100 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
101 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
102 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
103 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
104 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
105 pGetFontRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GetFontRealizationInfo");
106 pGetFontFileInfo
= (void *)GetProcAddress(hgdi32
, "GetFontFileInfo");
107 pGetFontFileData
= (void *)GetProcAddress(hgdi32
, "GetFontFileData");
109 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
112 static inline void* __WINE_ALLOC_SIZE(1) heap_alloc(size_t size
)
114 return HeapAlloc(GetProcessHeap(), 0, size
);
117 static inline void* __WINE_ALLOC_SIZE(2) heap_realloc(void *mem
, size_t size
)
119 if (!mem
) return heap_alloc(size
);
120 return HeapReAlloc(GetProcessHeap(), 0, mem
, size
);
123 static inline BOOL
heap_free(void *mem
)
125 return HeapFree(GetProcessHeap(), 0, mem
);
128 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
130 if (type
!= TRUETYPE_FONTTYPE
) return 1;
135 static BOOL
is_truetype_font_installed(const char *name
)
140 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
147 static INT CALLBACK
is_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
152 static BOOL
is_font_installed(const char *name
)
157 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
164 static void *get_res_data(const char *fontname
, DWORD
*rsrc_size
)
169 rsrc
= FindResourceA(GetModuleHandleA(NULL
), fontname
, (LPCSTR
)RT_RCDATA
);
170 if (!rsrc
) return NULL
;
172 rsrc_data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
173 if (!rsrc_data
) return NULL
;
175 *rsrc_size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
176 if (!*rsrc_size
) return NULL
;
181 static BOOL
write_tmp_file( const void *data
, DWORD
*size
, char *tmp_name
)
183 char tmp_path
[MAX_PATH
];
187 GetTempPathA(MAX_PATH
, tmp_path
);
188 GetTempFileNameA(tmp_path
, "ttf", 0, tmp_name
);
190 hfile
= CreateFileA(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
191 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
193 ret
= WriteFile(hfile
, data
, *size
, size
, NULL
);
199 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
204 rsrc_data
= get_res_data( fontname
, &rsrc_size
);
205 if (!rsrc_data
) return FALSE
;
207 return write_tmp_file( rsrc_data
, &rsrc_size
, tmp_name
);
210 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
218 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
219 /* NT4 tries to be clever and only returns the minimum length */
220 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
222 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
223 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
224 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
225 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
226 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
227 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
228 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
229 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
230 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
231 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
232 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
233 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
234 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
235 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
236 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
237 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
238 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
239 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
240 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
241 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
242 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
243 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
244 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
245 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
246 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
247 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
248 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
249 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
252 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
254 HFONT hfont
= CreateFontIndirectA(lf
);
255 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
257 check_font(test
, lf
, hfont
);
261 static void test_logfont(void)
266 memset(&lf
, 0, sizeof lf
);
268 lf
.lfCharSet
= ANSI_CHARSET
;
269 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
270 lf
.lfWeight
= FW_DONTCARE
;
273 lf
.lfQuality
= DEFAULT_QUALITY
;
275 lstrcpyA(lf
.lfFaceName
, "Arial");
276 hfont
= create_font("Arial", &lf
);
279 memset(&lf
, 'A', sizeof(lf
));
280 hfont
= CreateFontIndirectA(&lf
);
281 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
283 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
284 check_font("AAA...", &lf
, hfont
);
288 static INT CALLBACK
font_enum_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
290 if (type
& RASTER_FONTTYPE
)
292 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
294 return 0; /* stop enumeration */
297 return 1; /* continue enumeration */
300 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
302 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
303 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
304 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
305 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
306 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
307 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
308 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
309 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
310 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
311 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
312 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
313 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
314 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
315 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
316 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
317 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
318 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
319 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
320 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
321 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
324 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
325 LONG lfWidth
, const char *test_str
,
326 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
327 const SIZE
*size_orig
, INT width_of_A_orig
,
328 INT scale_x
, INT scale_y
)
331 OUTLINETEXTMETRICA otm
;
334 INT width_of_A
, cx
, cy
;
340 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
342 GetObjectA(hfont
, sizeof(lf
), &lf
);
344 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
346 otm
.otmSize
= sizeof(otm
) / 2;
347 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
348 ok(ret
== sizeof(otm
)/2 /* XP */ ||
349 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
351 memset(&otm
, 0x1, sizeof(otm
));
352 otm
.otmSize
= sizeof(otm
);
353 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
354 ok(ret
== sizeof(otm
) /* XP */ ||
355 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
357 memset(&tm
, 0x2, sizeof(tm
));
358 ret
= GetTextMetricsA(hdc
, &tm
);
359 ok(ret
, "GetTextMetricsA failed\n");
360 /* the structure size is aligned */
361 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
363 ok(0, "tm != otm\n");
364 compare_tm(&tm
, &otm
.otmTextMetrics
);
367 tm
= otm
.otmTextMetrics
;
368 if (0) /* these metrics are scaled too, but with rounding errors */
370 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
371 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
373 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
374 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
375 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
376 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
377 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
378 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
382 ret
= GetTextMetricsA(hdc
, &tm
);
383 ok(ret
, "GetTextMetricsA failed\n");
386 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
387 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
388 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
389 lfHeight
, scale_x
, scale_y
, cx
, cy
);
390 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
391 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
392 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
393 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
394 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
396 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
400 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
403 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
405 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
407 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
408 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
410 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
412 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
);
415 /* Test how GDI scales bitmap font metrics */
416 static void test_bitmap_font(void)
418 static const char test_str
[11] = "Test String";
421 HFONT hfont
, old_hfont
;
424 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
426 hdc
= CreateCompatibleDC(0);
428 /* "System" has only 1 pixel size defined, otherwise the test breaks */
429 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
433 trace("no bitmap fonts were found, skipping the test\n");
437 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
439 height_orig
= bitmap_lf
.lfHeight
;
440 lfWidth
= bitmap_lf
.lfWidth
;
442 hfont
= create_font("bitmap", &bitmap_lf
);
443 old_hfont
= SelectObject(hdc
, hfont
);
444 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
445 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
446 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
447 SelectObject(hdc
, old_hfont
);
450 bitmap_lf
.lfHeight
= 0;
451 bitmap_lf
.lfWidth
= 4;
452 hfont
= create_font("bitmap", &bitmap_lf
);
453 old_hfont
= SelectObject(hdc
, hfont
);
454 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
455 SelectObject(hdc
, old_hfont
);
458 bitmap_lf
.lfHeight
= height_orig
;
459 bitmap_lf
.lfWidth
= lfWidth
;
461 /* test fractional scaling */
462 for (i
= 1; i
<= height_orig
* 6; i
++)
466 bitmap_lf
.lfHeight
= i
;
467 hfont
= create_font("fractional", &bitmap_lf
);
468 scale
= (i
+ height_orig
- 1) / height_orig
;
469 nearest_height
= scale
* height_orig
;
470 /* Only jump to the next height if the difference <= 25% original height */
471 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
472 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
473 so we'll not test this particular height. */
474 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
475 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
476 old_hfont
= SelectObject(hdc
, hfont
);
477 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
478 SelectObject(hdc
, old_hfont
);
482 /* test integer scaling 3x2 */
483 bitmap_lf
.lfHeight
= height_orig
* 2;
484 bitmap_lf
.lfWidth
*= 3;
485 hfont
= create_font("3x2", &bitmap_lf
);
486 old_hfont
= SelectObject(hdc
, hfont
);
487 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
488 SelectObject(hdc
, old_hfont
);
491 /* test integer scaling 3x3 */
492 bitmap_lf
.lfHeight
= height_orig
* 3;
493 bitmap_lf
.lfWidth
= 0;
494 hfont
= create_font("3x3", &bitmap_lf
);
495 old_hfont
= SelectObject(hdc
, hfont
);
496 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
497 SelectObject(hdc
, old_hfont
);
503 /* Test how GDI scales outline font metrics */
504 static void test_outline_font(void)
506 static const char test_str
[11] = "Test String";
509 HFONT hfont
, old_hfont
, old_hfont_2
;
510 OUTLINETEXTMETRICA otm
;
512 INT width_orig
, height_orig
, lfWidth
;
515 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
519 if (!is_truetype_font_installed("Arial"))
521 skip("Arial is not installed\n");
525 hdc
= CreateCompatibleDC(0);
527 memset(&lf
, 0, sizeof(lf
));
528 strcpy(lf
.lfFaceName
, "Arial");
530 hfont
= create_font("outline", &lf
);
531 old_hfont
= SelectObject(hdc
, hfont
);
532 otm
.otmSize
= sizeof(otm
);
533 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
534 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
535 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
537 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
538 SelectObject(hdc
, old_hfont
);
541 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
542 lf
.lfHeight
= otm
.otmEMSquare
;
543 lf
.lfHeight
= -lf
.lfHeight
;
544 hfont
= create_font("outline", &lf
);
545 old_hfont
= SelectObject(hdc
, hfont
);
546 otm
.otmSize
= sizeof(otm
);
547 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
548 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
549 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
550 SelectObject(hdc
, old_hfont
);
553 height_orig
= otm
.otmTextMetrics
.tmHeight
;
554 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
556 /* test integer scaling 3x2 */
557 lf
.lfHeight
= height_orig
* 2;
558 lf
.lfWidth
= lfWidth
* 3;
559 hfont
= create_font("3x2", &lf
);
560 old_hfont
= SelectObject(hdc
, hfont
);
561 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
562 SelectObject(hdc
, old_hfont
);
565 /* test integer scaling 3x3 */
566 lf
.lfHeight
= height_orig
* 3;
567 lf
.lfWidth
= lfWidth
* 3;
568 hfont
= create_font("3x3", &lf
);
569 old_hfont
= SelectObject(hdc
, hfont
);
570 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
571 SelectObject(hdc
, old_hfont
);
574 /* test integer scaling 1x1 */
575 lf
.lfHeight
= height_orig
* 1;
576 lf
.lfWidth
= lfWidth
* 1;
577 hfont
= create_font("1x1", &lf
);
578 old_hfont
= SelectObject(hdc
, hfont
);
579 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
580 SelectObject(hdc
, old_hfont
);
583 /* test integer scaling 1x1 */
584 lf
.lfHeight
= height_orig
;
586 hfont
= create_font("1x1", &lf
);
587 old_hfont
= SelectObject(hdc
, hfont
);
588 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
590 /* with an identity matrix */
591 memset(&gm
, 0, sizeof(gm
));
592 SetLastError(0xdeadbeef);
593 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
594 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
595 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
596 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
597 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
598 /* with a custom matrix */
599 memset(&gm
, 0, sizeof(gm
));
600 SetLastError(0xdeadbeef);
601 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
602 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
604 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
605 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
607 /* Test that changing the DC transformation affects only the font
608 * selected on this DC and doesn't affect the same font selected on
611 hdc_2
= CreateCompatibleDC(0);
612 old_hfont_2
= SelectObject(hdc_2
, hfont
);
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 SetMapMode(hdc
, MM_ANISOTROPIC
);
617 /* font metrics on another DC should be unchanged */
618 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
620 /* test restrictions of compatibility mode GM_COMPATIBLE */
621 /* part 1: rescaling only X should not change font scaling on screen.
622 So compressing the X axis by 2 is not done, and this
623 appears as X scaling of 2 that no one requested. */
624 SetWindowExtEx(hdc
, 100, 100, NULL
);
625 SetViewportExtEx(hdc
, 50, 100, NULL
);
626 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
627 /* font metrics on another DC should be unchanged */
628 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
630 /* part 2: rescaling only Y should change font scaling.
631 As also X is scaled by a factor of 2, but this is not
632 requested by the DC transformation, we get a scaling factor
633 of 2 in the X coordinate. */
634 SetViewportExtEx(hdc
, 100, 200, NULL
);
635 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
636 /* font metrics on another DC should be unchanged */
637 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
639 /* restore scaling */
640 SetMapMode(hdc
, MM_TEXT
);
642 /* font metrics on another DC should be unchanged */
643 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
645 SelectObject(hdc_2
, old_hfont_2
);
648 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
650 SelectObject(hdc
, old_hfont
);
653 skip("GM_ADVANCED is not supported on this platform\n");
664 SetLastError(0xdeadbeef);
665 ret
= SetWorldTransform(hdc
, &xform
);
666 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
668 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
670 /* with an identity matrix */
671 memset(&gm
, 0, sizeof(gm
));
672 SetLastError(0xdeadbeef);
673 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
674 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
675 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
676 pt
.x
= width_orig
; pt
.y
= 0;
678 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
679 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
680 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
681 /* with a custom matrix */
682 memset(&gm
, 0, sizeof(gm
));
683 SetLastError(0xdeadbeef);
684 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
685 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
686 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
687 pt
.x
= width_orig
; pt
.y
= 0;
689 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
690 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
691 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
693 SetLastError(0xdeadbeef);
694 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
695 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
697 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
699 /* with an identity matrix */
700 memset(&gm
, 0, sizeof(gm
));
701 SetLastError(0xdeadbeef);
702 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
703 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
704 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
705 pt
.x
= width_orig
; pt
.y
= 0;
707 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
708 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
709 /* with a custom matrix */
710 memset(&gm
, 0, sizeof(gm
));
711 SetLastError(0xdeadbeef);
712 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
713 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
714 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
715 pt
.x
= width_orig
; pt
.y
= 0;
717 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
718 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
720 SetLastError(0xdeadbeef);
721 ret
= SetMapMode(hdc
, MM_TEXT
);
722 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
724 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
726 /* with an identity matrix */
727 memset(&gm
, 0, sizeof(gm
));
728 SetLastError(0xdeadbeef);
729 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
730 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
731 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
732 pt
.x
= width_orig
; pt
.y
= 0;
734 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
735 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
736 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
737 /* with a custom matrix */
738 memset(&gm
, 0, sizeof(gm
));
739 SetLastError(0xdeadbeef);
740 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
741 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
742 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
743 pt
.x
= width_orig
; pt
.y
= 0;
745 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
746 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
747 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
749 SelectObject(hdc
, old_hfont
);
754 static INT CALLBACK
find_font_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
756 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
758 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
761 return 0; /* stop enumeration */
763 return 1; /* continue enumeration */
766 static BOOL
is_CJK(void)
768 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
771 #define FH_SCALE 0x80000000
772 static void test_bitmap_font_metrics(void)
774 static const WORD skip_rtl
[] = {LANG_ARABIC
, LANG_HEBREW
, 0};
775 static const struct font_data
777 const char face_name
[LF_FACESIZE
];
778 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
779 int ave_char_width
, max_char_width
, dpi
;
780 BYTE first_char
, last_char
, def_char
, break_char
;
782 const WORD
*skip_lang_id
;
786 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
787 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
788 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
789 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
790 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
791 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
792 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
793 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
794 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 16 },
795 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
797 { "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 },
798 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
799 { "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 },
800 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
801 { "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 },
802 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
803 { "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 },
804 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
805 { "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 },
806 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
808 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
809 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
810 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
811 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
812 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
813 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
814 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
815 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
816 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
817 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
818 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
819 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
820 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
821 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
822 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
823 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
825 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
826 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
827 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
828 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
829 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
830 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
831 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
832 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
833 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
834 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
835 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
836 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
838 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
839 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
840 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
841 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
842 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
843 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
844 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
845 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
846 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
847 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
848 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
849 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
850 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
851 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
852 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
853 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
854 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
856 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
857 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
858 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
859 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
860 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
861 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
862 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
863 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
864 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
865 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
866 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
868 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
869 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
870 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
872 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
873 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
874 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
876 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
877 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
878 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
880 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
881 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
883 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
884 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
885 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
886 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
887 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
888 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
889 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
890 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
891 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
892 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
893 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
894 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
895 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
896 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
897 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
},
898 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
899 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
900 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
901 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, skip_rtl
},
902 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
903 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
905 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
906 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
907 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
908 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
909 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
910 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
911 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
912 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
913 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
914 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
915 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
916 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
918 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
919 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
920 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
922 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
924 /* FIXME: add "Terminal" */
926 static const int font_log_pixels
[] = { 96, 120 };
929 HFONT hfont
, old_hfont
;
931 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
932 char face_name
[LF_FACESIZE
];
935 trace("system language id %04x\n", system_lang_id
);
937 expected_cs
= GetACP();
938 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
940 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
943 expected_cs
= csi
.ciCharset
;
944 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
946 hdc
= CreateCompatibleDC(0);
947 ok(hdc
!= NULL
, "failed to create hdc\n");
949 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
950 GetDeviceCaps(hdc
, LOGPIXELSY
));
952 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
955 for (i
= 0; i
< sizeof(font_log_pixels
)/sizeof(font_log_pixels
[0]); i
++)
957 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
961 font_res
= font_log_pixels
[i
];
964 trace("best font resolution is %d\n", font_res
);
966 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
970 memset(&lf
, 0, sizeof(lf
));
972 height
= fd
[i
].height
& ~FH_SCALE
;
973 lf
.lfHeight
= height
;
974 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
976 for(bit
= 0; bit
< 32; bit
++)
984 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
985 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
987 lf
.lfCharSet
= csi
.ciCharset
;
988 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
989 if (fd
[i
].height
& FH_SCALE
)
990 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
993 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
995 todo_wine_if (ret
) /* FIXME: Remove once Wine is fixed */
996 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
999 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
1002 hfont
= create_font(lf
.lfFaceName
, &lf
);
1003 old_hfont
= SelectObject(hdc
, hfont
);
1005 SetLastError(0xdeadbeef);
1006 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
1007 ok(ret
, "GetTextFace error %u\n", GetLastError());
1009 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
1011 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
1012 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
1013 SelectObject(hdc
, old_hfont
);
1014 DeleteObject(hfont
);
1018 memset(&gm
, 0, sizeof(gm
));
1019 SetLastError(0xdeadbeef);
1020 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1022 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
1023 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1026 bRet
= GetTextMetricsA(hdc
, &tm
);
1027 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
1029 SetLastError(0xdeadbeef);
1030 ret
= GetTextCharset(hdc
);
1031 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1032 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1034 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1036 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
1037 trace("expected %s, height %d scaled_height %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
1039 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1042 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1043 if (fd
[i
].skip_lang_id
)
1047 while(!skipme
&& fd
[i
].skip_lang_id
[si
])
1048 if (fd
[i
].skip_lang_id
[si
++] == system_lang_id
)
1053 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1054 if (fd
[i
].height
& FH_SCALE
)
1055 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
);
1057 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
);
1058 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1059 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1060 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
);
1061 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
);
1062 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
);
1063 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1064 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1065 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1066 make default char test fail */
1067 if (tm
.tmCharSet
== lf
.lfCharSet
)
1068 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1069 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1070 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
);
1072 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1073 that make the max width bigger */
1074 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1075 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
);
1078 skip("Skipping font metrics test for system langid 0x%x\n",
1081 SelectObject(hdc
, old_hfont
);
1082 DeleteObject(hfont
);
1089 static void test_GdiGetCharDimensions(void)
1095 LONG avgwidth
, height
;
1096 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1098 if (!pGdiGetCharDimensions
)
1100 win_skip("GdiGetCharDimensions not available on this platform\n");
1104 hdc
= CreateCompatibleDC(NULL
);
1106 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1107 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1109 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1110 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1111 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1113 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1114 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1116 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1117 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1120 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1121 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1122 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1127 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1128 const TEXTMETRICA
*lpntme
,
1129 DWORD FontType
, LPARAM lParam
)
1131 if (FontType
& TRUETYPE_FONTTYPE
)
1135 hfont
= CreateFontIndirectA(lpelfe
);
1138 *(HFONT
*)lParam
= hfont
;
1146 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, ABC
*base_abci
, ABC
*base_abcw
, ABCFLOAT
*base_abcf
, INT todo
)
1152 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1153 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1154 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1156 ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1158 ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1160 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1161 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1162 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1164 ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1166 ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1168 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1169 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1170 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1172 ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1174 ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1177 static void test_GetCharABCWidths(void)
1179 static const WCHAR str
[] = {'i',0};
1203 {0xffffff, 0xffffff},
1204 {0x1000000, 0x1000000},
1205 {0xffffff, 0x1000000},
1206 {0xffffffff, 0xffffffff},
1214 BOOL r
[sizeof range
/ sizeof range
[0]];
1217 {ANSI_CHARSET
, 0x30, 0x30,
1218 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1219 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1220 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1221 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1222 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1223 {GB2312_CHARSET
, 0x8141, 0x4e04,
1224 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1225 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1226 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1230 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1232 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1236 memset(&lf
, 0, sizeof(lf
));
1237 strcpy(lf
.lfFaceName
, "System");
1240 hfont
= CreateFontIndirectA(&lf
);
1242 hfont
= SelectObject(hdc
, hfont
);
1244 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1245 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1247 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1248 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1250 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1251 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1253 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1254 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1256 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1257 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1259 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1260 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1262 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1263 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1265 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1266 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1268 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1269 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1271 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1272 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1274 hfont
= SelectObject(hdc
, hfont
);
1275 DeleteObject(hfont
);
1277 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1281 UINT code
= 0x41, j
;
1283 lf
.lfFaceName
[0] = '\0';
1284 lf
.lfCharSet
= c
[i
].cs
;
1285 lf
.lfPitchAndFamily
= 0;
1286 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1288 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1292 memset(a
, 0, sizeof a
);
1293 memset(w
, 0, sizeof w
);
1294 hfont
= SelectObject(hdc
, hfont
);
1295 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1296 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1297 memcmp(a
, w
, sizeof a
) == 0,
1298 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1300 memset(a
, 0xbb, sizeof a
);
1301 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1302 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1303 memset(full
, 0xcc, sizeof full
);
1304 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1305 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1306 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1307 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1309 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1311 memset(full
, 0xdd, sizeof full
);
1312 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1313 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1314 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1317 UINT last
= range
[j
].last
- range
[j
].first
;
1318 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1319 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1320 "GetCharABCWidthsA %x should match. codepage = %u\n",
1321 range
[j
].last
, c
[i
].cs
);
1325 hfont
= SelectObject(hdc
, hfont
);
1326 DeleteObject(hfont
);
1329 memset(&lf
, 0, sizeof(lf
));
1330 strcpy(lf
.lfFaceName
, "Tahoma");
1332 hfont
= CreateFontIndirectA(&lf
);
1334 /* test empty glyph's metrics */
1335 hfont
= SelectObject(hdc
, hfont
);
1336 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1337 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1338 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1339 ret
= pGetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1340 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1341 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1343 /* 1) prepare unrotated font metrics */
1344 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1345 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1346 DeleteObject(SelectObject(hdc
, hfont
));
1348 /* 2) get rotated font metrics */
1349 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1350 hfont
= CreateFontIndirectA(&lf
);
1351 hfont
= SelectObject(hdc
, hfont
);
1352 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1353 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1355 /* 3) compare ABC results */
1356 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1357 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1358 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1359 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1360 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1361 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1363 DeleteObject(SelectObject(hdc
, hfont
));
1364 ReleaseDC(NULL
, hdc
);
1366 trace("ABC sign test for a variety of transforms:\n");
1367 memset(&lf
, 0, sizeof(lf
));
1368 strcpy(lf
.lfFaceName
, "Tahoma");
1370 hfont
= CreateFontIndirectA(&lf
);
1371 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1374 SetMapMode(hdc
, MM_ANISOTROPIC
);
1375 SelectObject(hdc
, hfont
);
1377 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1378 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1380 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1381 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1382 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1383 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1384 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1385 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1387 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1388 SetWindowExtEx(hdc
, -1, -1, NULL
);
1389 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1390 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1391 SetGraphicsMode(hdc
, GM_ADVANCED
);
1392 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1393 SetWindowExtEx(hdc
, 1, 1, NULL
);
1394 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1395 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1396 SetGraphicsMode(hdc
, GM_ADVANCED
);
1397 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1399 ReleaseDC(hwnd
, hdc
);
1400 DestroyWindow(hwnd
);
1402 trace("RTL layout\n");
1403 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1406 SetMapMode(hdc
, MM_ANISOTROPIC
);
1407 SelectObject(hdc
, hfont
);
1409 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1410 SetWindowExtEx(hdc
, -1, -1, NULL
);
1411 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1412 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1413 SetGraphicsMode(hdc
, GM_ADVANCED
);
1414 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1415 SetWindowExtEx(hdc
, 1, 1, NULL
);
1416 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1417 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1418 SetGraphicsMode(hdc
, GM_ADVANCED
);
1419 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1421 ReleaseDC(hwnd
, hdc
);
1422 DestroyWindow(hwnd
);
1423 DeleteObject(hfont
);
1426 static void test_text_extents(void)
1428 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1429 static const WCHAR emptyW
[] = {0};
1431 INT i
, len
, fit1
, fit2
, extents2
[3];
1440 memset(&lf
, 0, sizeof(lf
));
1441 strcpy(lf
.lfFaceName
, "Arial");
1444 hfont
= CreateFontIndirectA(&lf
);
1446 hfont
= SelectObject(hdc
, hfont
);
1447 GetTextMetricsA(hdc
, &tm
);
1448 ret
= GetTextExtentPointA(hdc
, "o", 1, &sz
);
1449 ok(ret
, "got %d\n", ret
);
1450 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1452 memset(&sz
, 0xcc, sizeof(sz
));
1453 ret
= GetTextExtentPointA(hdc
, "o", 0, &sz
);
1454 ok(ret
, "got %d\n", ret
);
1455 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1457 memset(&sz
, 0xcc, sizeof(sz
));
1458 ret
= GetTextExtentPointA(hdc
, "", 0, &sz
);
1459 ok(ret
, "got %d\n", ret
);
1460 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1462 SetLastError(0xdeadbeef);
1463 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1464 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1466 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1467 hfont
= SelectObject(hdc
, hfont
);
1468 DeleteObject(hfont
);
1473 memset(&sz
, 0xcc, sizeof(sz
));
1474 ret
= GetTextExtentPointW(hdc
, wt
, 0, &sz
);
1475 ok(ret
, "got %d\n", ret
);
1476 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1478 memset(&sz
, 0xcc, sizeof(sz
));
1479 ret
= GetTextExtentPointW(hdc
, emptyW
, 0, &sz
);
1480 ok(ret
, "got %d\n", ret
);
1481 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1484 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1485 extents
[0] = 1; /* So that the increasing sequence test will fail
1486 if the extents array is untouched. */
1487 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1488 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1489 ok(sz1
.cy
== sz2
.cy
,
1490 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1491 /* Because of the '\n' in the string GetTextExtentExPoint and
1492 GetTextExtentPoint return different widths under Win2k, but
1493 under WinXP they return the same width. So we don't test that
1496 for (i
= 1; i
< len
; ++i
)
1497 ok(extents
[i
-1] <= extents
[i
],
1498 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1500 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1501 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1502 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1503 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1504 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1505 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1506 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1507 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1508 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1509 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1510 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1511 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1512 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1513 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1515 /* extents functions fail with -ve counts (the interesting case being -1) */
1516 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1517 ok(ret
== FALSE
, "got %d\n", ret
);
1518 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1519 ok(ret
== FALSE
, "got %d\n", ret
);
1520 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1521 ok(ret
== FALSE
, "got %d\n", ret
);
1523 /* max_extent = 0 succeeds and returns zero */
1525 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1527 broken(ret
== FALSE
), /* NT4, 2k */
1530 broken(fit1
== -215), /* NT4, 2k */
1531 "fit = %d\n", fit1
);
1532 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1533 ok(ret
== TRUE
, "got %d\n", ret
);
1534 ok(fit2
== 0, "fit = %d\n", fit2
);
1536 /* max_extent = -1 is interpreted as a very large width that will
1537 * definitely fit our three characters */
1539 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1540 ok(ret
== TRUE
, "got %d\n", ret
);
1541 ok(fit1
== 3, "fit = %d\n", fit1
);
1542 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1543 ok(ret
== TRUE
, "got %d\n", ret
);
1544 ok(fit2
== 3, "fit = %d\n", fit2
);
1546 /* max_extent = -2 is interpreted similarly, but the Ansi version
1547 * rejects it while the Unicode one accepts it */
1549 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1550 ok(ret
== FALSE
, "got %d\n", ret
);
1551 ok(fit1
== -215, "fit = %d\n", fit1
);
1552 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1553 ok(ret
== TRUE
, "got %d\n", ret
);
1554 ok(fit2
== 3, "fit = %d\n", fit2
);
1556 hfont
= SelectObject(hdc
, hfont
);
1557 DeleteObject(hfont
);
1559 /* non-MM_TEXT mapping mode */
1561 hfont
= CreateFontIndirectA(&lf
);
1562 hfont
= SelectObject(hdc
, hfont
);
1564 SetMapMode( hdc
, MM_HIMETRIC
);
1565 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1566 ok(ret
, "got %d\n", ret
);
1567 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1569 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1570 ok(ret
, "got %d\n", ret
);
1571 ok(fit1
== 2, "got %d\n", fit1
);
1572 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1573 for(i
= 0; i
< 2; i
++)
1574 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1576 hfont
= SelectObject(hdc
, hfont
);
1577 DeleteObject(hfont
);
1578 HeapFree(GetProcessHeap(), 0, extents
);
1579 ReleaseDC(NULL
, hdc
);
1582 static void test_GetGlyphIndices(void)
1589 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1590 WORD glyphs
[(sizeof(testtext
)/2)-1];
1594 if (!pGetGlyphIndicesW
) {
1595 win_skip("GetGlyphIndicesW not available on platform\n");
1601 memset(&lf
, 0, sizeof(lf
));
1602 strcpy(lf
.lfFaceName
, "System");
1604 lf
.lfCharSet
= ANSI_CHARSET
;
1606 hfont
= CreateFontIndirectA(&lf
);
1607 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1608 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1609 if (textm
.tmCharSet
== ANSI_CHARSET
)
1611 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1612 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1613 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1614 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1616 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1617 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1618 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1619 textm
.tmDefaultChar
, glyphs
[4]);
1622 /* FIXME: Write tests for non-ANSI charsets. */
1623 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1625 if(!is_font_installed("Tahoma"))
1627 skip("Tahoma is not installed so skipping this test\n");
1630 memset(&lf
, 0, sizeof(lf
));
1631 strcpy(lf
.lfFaceName
, "Tahoma");
1634 hfont
= CreateFontIndirectA(&lf
);
1635 hOldFont
= SelectObject(hdc
, hfont
);
1636 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1637 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1638 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1639 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1640 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1642 testtext
[0] = textm
.tmDefaultChar
;
1643 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1644 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1645 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1646 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1647 DeleteObject(SelectObject(hdc
, hOldFont
));
1650 static void test_GetKerningPairs(void)
1652 static const struct kerning_data
1654 const char face_name
[LF_FACESIZE
];
1656 /* some interesting fields from OUTLINETEXTMETRIC */
1657 LONG tmHeight
, tmAscent
, tmDescent
;
1662 UINT otmsCapEmHeight
;
1667 UINT otmusMinimumPPEM
;
1668 /* small subset of kerning pairs to test */
1669 DWORD total_kern_pairs
;
1670 const KERNINGPAIR kern_pair
[26];
1673 {"Arial", 12, 12, 9, 3,
1674 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1677 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1678 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1679 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1680 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1681 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1682 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1683 {933,970,+1},{933,972,-1}
1686 {"Arial", -34, 39, 32, 7,
1687 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1690 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1691 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1692 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1693 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1694 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1695 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1696 {933,970,+2},{933,972,-3}
1699 { "Arial", 120, 120, 97, 23,
1700 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1703 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1704 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1705 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1706 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1707 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1708 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1709 {933,970,+6},{933,972,-10}
1712 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1713 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1714 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1717 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1718 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1719 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1720 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1721 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1722 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1723 {933,970,+54},{933,972,-83}
1729 HFONT hfont
, hfont_old
;
1730 KERNINGPAIR
*kern_pair
;
1732 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1736 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1737 * which may render this test unusable, so we're trying to avoid that.
1739 SetLastError(0xdeadbeef);
1740 GetKerningPairsW(hdc
, 0, NULL
);
1741 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1743 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1748 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1750 OUTLINETEXTMETRICW otm
;
1753 if (!is_font_installed(kd
[i
].face_name
))
1755 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1759 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1761 memset(&lf
, 0, sizeof(lf
));
1762 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1763 lf
.lfHeight
= kd
[i
].height
;
1764 hfont
= CreateFontIndirectA(&lf
);
1765 ok(hfont
!= NULL
, "failed to create a font, name %s\n", kd
[i
].face_name
);
1767 hfont_old
= SelectObject(hdc
, hfont
);
1769 SetLastError(0xdeadbeef);
1770 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1771 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1772 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1774 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1775 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1776 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1777 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1778 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1779 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1781 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1782 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1783 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1784 kd
[i
].otmAscent
, otm
.otmAscent
);
1785 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1786 kd
[i
].otmDescent
, otm
.otmDescent
);
1787 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1788 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1789 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1790 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1791 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1792 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1794 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1795 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1796 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1797 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1798 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1799 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1800 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1801 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1802 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1805 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1806 trace("total_kern_pairs %u\n", total_kern_pairs
);
1807 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1809 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1812 SetLastError(0xdeadbeef);
1813 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1814 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1815 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1816 ok(ret
== 0, "got %u, expected 0\n", ret
);
1818 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1819 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1821 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1822 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1824 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1825 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1829 for (n
= 0; n
< ret
; n
++)
1832 /* Disabled to limit console spam */
1833 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1834 trace("{'%c','%c',%d},\n",
1835 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1836 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1838 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1839 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1841 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1842 "pair %d:%d got %d, expected %d\n",
1843 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1844 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1850 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1851 matches
, kd
[i
].total_kern_pairs
);
1853 HeapFree(GetProcessHeap(), 0, kern_pair
);
1855 SelectObject(hdc
, hfont_old
);
1856 DeleteObject(hfont
);
1864 const char face_name
[LF_FACESIZE
];
1865 int requested_height
;
1866 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1870 static void test_height( HDC hdc
, const struct font_data
*fd
)
1873 HFONT hfont
, old_hfont
;
1877 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1879 if (!is_truetype_font_installed(fd
[i
].face_name
))
1881 skip("%s is not installed\n", fd
[i
].face_name
);
1885 memset(&lf
, 0, sizeof(lf
));
1886 lf
.lfHeight
= fd
[i
].requested_height
;
1887 lf
.lfWeight
= fd
[i
].weight
;
1888 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1890 hfont
= CreateFontIndirectA(&lf
);
1891 ok(hfont
!= NULL
, "failed to create a font, name %s\n", fd
[i
].face_name
);
1893 old_hfont
= SelectObject(hdc
, hfont
);
1894 ret
= GetTextMetricsA(hdc
, &tm
);
1895 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1896 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1898 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
);
1899 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
);
1900 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
);
1901 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
);
1902 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
);
1903 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
);
1906 SelectObject(hdc
, old_hfont
);
1907 /* force GDI to use new font, otherwise Windows leaks the font reference */
1908 GetTextMetricsA(hdc
, &tm
);
1909 DeleteObject(hfont
);
1913 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1915 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1916 DWORD
*table
= (DWORD
*)ttf
+ 3;
1918 for (i
= 0; i
< num_tables
; i
++)
1920 if (table
[0] == tag
)
1921 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
1927 static void test_height_selection_vdmx( HDC hdc
)
1929 static const struct font_data charset_0
[] = /* doesn't use VDMX */
1931 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1932 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1933 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1934 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1935 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1936 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
1937 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1938 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1939 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1940 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1941 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
1942 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1943 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1944 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1945 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1946 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1947 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
1948 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1949 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1950 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1951 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1952 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1953 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
1954 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
1955 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
1956 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
1957 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1958 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1959 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1960 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1961 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1962 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1963 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1964 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1965 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1966 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1967 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1968 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1969 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1970 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1971 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1972 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1973 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1974 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
1975 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
1976 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
1977 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
1978 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
1979 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
1980 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
1981 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
1982 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
1983 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1986 static const struct font_data charset_1
[] = /* Uses VDMX */
1988 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1989 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1990 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1991 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1992 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1993 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1994 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1995 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1996 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1997 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1998 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1999 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2000 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2001 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2002 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2003 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2004 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2005 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2006 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2007 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2008 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2009 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2010 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2011 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
2012 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
2013 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
2014 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2015 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2016 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2017 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2018 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2019 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2020 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2021 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2022 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2023 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2024 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2025 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2026 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2027 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2028 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2029 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
2030 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
2031 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
2032 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
2033 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
2034 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
2035 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
2036 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
2037 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
2038 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
2039 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
2040 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2043 static const struct vdmx_data
2047 const struct font_data
*fd
;
2050 { 0, 0, charset_0
},
2051 { 0, 1, charset_1
},
2052 { 1, 0, charset_0
},
2059 char ttf_name
[MAX_PATH
];
2063 if (!pAddFontResourceExA
)
2065 win_skip("AddFontResourceExA unavailable\n");
2069 for (i
= 0; i
< sizeof(data
) / sizeof(data
[0]); i
++)
2071 res
= get_res_data( "wine_vdmx.ttf", &size
);
2073 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2074 memcpy( copy
, res
, size
);
2075 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2076 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2077 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2078 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2079 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2080 ratio_rec
[0] = data
[i
].bCharSet
;
2082 write_tmp_file( copy
, &size
, ttf_name
);
2083 HeapFree( GetProcessHeap(), 0, copy
);
2085 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2086 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2087 if (!num
) win_skip("Unable to add ttf font resource\n");
2090 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2091 test_height( hdc
, data
[i
].fd
);
2092 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2094 ret
= DeleteFileA( ttf_name
);
2095 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
),
2096 "DeleteFile error %d\n", GetLastError());
2100 static void test_height_selection(void)
2102 static const struct font_data tahoma
[] =
2104 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2105 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2106 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2107 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2108 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2109 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2110 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2111 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2112 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2113 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2114 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2116 HDC hdc
= CreateCompatibleDC(0);
2117 ok(hdc
!= NULL
, "failed to create hdc\n");
2119 test_height( hdc
, tahoma
);
2120 test_height_selection_vdmx( hdc
);
2125 static UINT
get_font_fsselection(LOGFONTA
*lf
)
2127 OUTLINETEXTMETRICA
*otm
;
2128 HFONT hfont
, hfont_old
;
2129 DWORD ret
, otm_size
;
2134 hfont
= CreateFontIndirectA(lf
);
2135 ok(hfont
!= NULL
, "failed to create a font\n");
2137 hfont_old
= SelectObject(hdc
, hfont
);
2139 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2140 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2141 otm
->otmSize
= sizeof(*otm
);
2142 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2143 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2144 fsSelection
= otm
->otmfsSelection
;
2145 HeapFree(GetProcessHeap(), 0, otm
);
2146 SelectObject(hdc
, hfont_old
);
2147 DeleteObject(hfont
);
2153 static void test_GetOutlineTextMetrics(void)
2155 OUTLINETEXTMETRICA
*otm
;
2157 HFONT hfont
, hfont_old
;
2159 DWORD ret
, otm_size
;
2163 /* check fsSelection field with bold simulation */
2164 memset(&lf
, 0, sizeof(lf
));
2165 strcpy(lf
.lfFaceName
, "Wingdings");
2166 lf
.lfCharSet
= SYMBOL_CHARSET
;
2169 fsSelection
= get_font_fsselection(&lf
);
2170 ok((fsSelection
& (1 << 5)) == 0, "got 0x%x\n", fsSelection
);
2172 /* face with bold simulation */
2173 lf
.lfWeight
= FW_BOLD
;
2174 fsSelection
= get_font_fsselection(&lf
);
2175 ok((fsSelection
& (1 << 5)) != 0, "got 0x%x\n", fsSelection
);
2177 /* check fsSelection field with oblique simulation */
2178 memset(&lf
, 0, sizeof(lf
));
2179 strcpy(lf
.lfFaceName
, "Tahoma");
2181 lf
.lfWeight
= FW_NORMAL
;
2182 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2183 lf
.lfQuality
= PROOF_QUALITY
;
2186 fsSelection
= get_font_fsselection(&lf
);
2187 ok((fsSelection
& 1) == 0, "got 0x%x\n", fsSelection
);
2190 /* face with oblique simulation */
2191 fsSelection
= get_font_fsselection(&lf
);
2192 ok((fsSelection
& 1) == 1, "got 0x%x\n", fsSelection
);
2194 if (!is_font_installed("Arial"))
2196 skip("Arial is not installed\n");
2202 memset(&lf
, 0, sizeof(lf
));
2203 strcpy(lf
.lfFaceName
, "Arial");
2205 lf
.lfWeight
= FW_NORMAL
;
2206 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2207 lf
.lfQuality
= PROOF_QUALITY
;
2208 hfont
= CreateFontIndirectA(&lf
);
2209 ok(hfont
!= NULL
, "failed to create a font\n");
2211 hfont_old
= SelectObject(hdc
, hfont
);
2212 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2213 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
2215 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2217 memset(otm
, 0xAA, otm_size
);
2218 SetLastError(0xdeadbeef);
2219 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2220 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2221 ok(ret
== 1 /* Win9x */ ||
2222 ret
== otm
->otmSize
/* XP*/,
2223 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2224 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2226 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2227 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2228 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2229 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2232 memset(otm
, 0xAA, otm_size
);
2233 SetLastError(0xdeadbeef);
2234 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2235 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2236 ok(ret
== 1 /* Win9x */ ||
2237 ret
== otm
->otmSize
/* XP*/,
2238 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2239 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2241 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2242 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2243 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2244 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2247 /* ask about truncated data */
2248 memset(otm
, 0xAA, otm_size
);
2249 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2250 SetLastError(0xdeadbeef);
2251 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2252 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2253 ok(ret
== 1 /* Win9x */ ||
2254 ret
== otm
->otmSize
/* XP*/,
2255 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2256 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2258 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2259 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2260 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2262 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2264 /* check handling of NULL pointer */
2265 SetLastError(0xdeadbeef);
2266 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, NULL
);
2267 ok(ret
== otm_size
, "expected %u, got %u, error %d\n", otm_size
, ret
, GetLastError());
2269 HeapFree(GetProcessHeap(), 0, otm
);
2271 SelectObject(hdc
, hfont_old
);
2272 DeleteObject(hfont
);
2277 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2281 areaWidth
= clientArea
->right
- clientArea
->left
,
2283 const char *pFirstChar
, *pLastChar
;
2290 int GetTextExtentExPointWWidth
;
2293 GetTextMetricsA(hdc
, &tm
);
2294 y
= clientArea
->top
;
2297 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2303 /* if not at the end of the string, ... */
2304 if (*str
== '\0') break;
2305 /* ... add the next word to the current extent */
2306 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2308 SetTextJustification(hdc
, 0, 0);
2309 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2310 } while ((int) size
.cx
< areaWidth
);
2312 /* ignore trailing break chars */
2314 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2320 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2322 SetTextJustification(hdc
, 0, 0);
2323 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2325 /* do not justify the last extent */
2326 if (*str
!= '\0' && breakCount
> 0)
2328 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2329 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2330 if (size
.cx
!= areaWidth
&& nErrors
< sizeof(error
)/sizeof(error
[0]) - 1)
2332 error
[nErrors
].start
= pFirstChar
;
2333 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2334 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2341 } while (*str
&& y
< clientArea
->bottom
);
2343 for (e
= 0; e
< nErrors
; e
++)
2345 /* The width returned by GetTextExtentPoint32() is exactly the same
2346 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2347 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2348 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2349 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2353 static void test_SetTextJustification(void)
2363 static const char testText
[] =
2364 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2365 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2366 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2367 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2368 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2369 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2370 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2372 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2373 GetClientRect( hwnd
, &clientArea
);
2374 hdc
= GetDC( hwnd
);
2376 if (!is_font_installed("Times New Roman"))
2378 skip("Times New Roman is not installed\n");
2382 memset(&lf
, 0, sizeof lf
);
2383 lf
.lfCharSet
= ANSI_CHARSET
;
2384 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2385 lf
.lfWeight
= FW_DONTCARE
;
2387 lf
.lfQuality
= DEFAULT_QUALITY
;
2388 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2389 hfont
= create_font("Times New Roman", &lf
);
2390 SelectObject(hdc
, hfont
);
2392 testJustification(hdc
, testText
, &clientArea
);
2394 if (!pGetGlyphIndicesA
|| !pGetTextExtentExPointI
) goto done
;
2395 pGetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2397 SetTextJustification(hdc
, 0, 0);
2398 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2399 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2400 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2401 SetTextJustification(hdc
, 4, 1);
2402 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2403 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2404 SetTextJustification(hdc
, 9, 2);
2405 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2406 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2407 SetTextJustification(hdc
, 7, 3);
2408 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2409 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2410 SetTextJustification(hdc
, 7, 3);
2411 SetTextCharacterExtra(hdc
, 2 );
2412 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2413 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2414 SetTextJustification(hdc
, 0, 0);
2415 SetTextCharacterExtra(hdc
, 0);
2416 size
.cx
= size
.cy
= 1234;
2417 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2418 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
2419 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2420 SetTextJustification(hdc
, 5, 1);
2421 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2422 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2423 SetTextJustification(hdc
, 0, 0);
2425 SetMapMode( hdc
, MM_ANISOTROPIC
);
2426 SetWindowExtEx( hdc
, 2, 2, NULL
);
2427 GetClientRect( hwnd
, &clientArea
);
2428 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2429 testJustification(hdc
, testText
, &clientArea
);
2431 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2432 for (i
= 0; i
< 10; i
++)
2434 SetTextCharacterExtra(hdc
, i
);
2435 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2436 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2438 SetTextCharacterExtra(hdc
, 0);
2439 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2440 for (i
= 0; i
< 10; i
++)
2442 SetTextCharacterExtra(hdc
, i
);
2443 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2444 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2446 SetTextCharacterExtra(hdc
, 0);
2448 SetViewportExtEx( hdc
, 3, 3, NULL
);
2449 GetClientRect( hwnd
, &clientArea
);
2450 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2451 testJustification(hdc
, testText
, &clientArea
);
2453 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2454 for (i
= 0; i
< 10; i
++)
2456 SetTextCharacterExtra(hdc
, i
);
2457 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2458 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2462 DeleteObject(hfont
);
2463 ReleaseDC(hwnd
, hdc
);
2464 DestroyWindow(hwnd
);
2467 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2471 HFONT hfont
, hfont_old
;
2478 assert(count
<= 128);
2480 memset(&lf
, 0, sizeof(lf
));
2482 lf
.lfCharSet
= charset
;
2484 lstrcpyA(lf
.lfFaceName
, "Arial");
2485 SetLastError(0xdeadbeef);
2486 hfont
= CreateFontIndirectA(&lf
);
2487 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2490 hfont_old
= SelectObject(hdc
, hfont
);
2492 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2493 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2495 SetLastError(0xdeadbeef);
2496 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2497 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
2499 if (charset
== SYMBOL_CHARSET
)
2501 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2502 ok(fs
.fsCsb
[0] & (1u << 31), "symbol encoding should be available\n");
2506 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2507 ok(!(fs
.fsCsb
[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2510 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2512 trace("Can't find codepage for charset %d\n", cs
);
2516 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2518 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2520 skip("Font code page %d, looking for code page %d\n",
2521 pGdiGetCodePage(hdc
), code_page
);
2529 WCHAR unicode_buf
[128];
2531 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2533 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2535 SetLastError(0xdeadbeef);
2536 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2537 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2538 count
, ret
, GetLastError());
2544 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2546 SetLastError(0xdeadbeef);
2547 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2548 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2549 count
, ret
, GetLastError());
2552 SelectObject(hdc
, hfont_old
);
2553 DeleteObject(hfont
);
2560 static void test_font_charset(void)
2562 static struct charset_data
2566 WORD font_idxA
[128], font_idxW
[128];
2569 { ANSI_CHARSET
, 1252 },
2570 { RUSSIAN_CHARSET
, 1251 },
2571 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2575 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
2577 win_skip("Skipping the font charset test on a Win9x platform\n");
2581 if (!is_font_installed("Arial"))
2583 skip("Arial is not installed\n");
2587 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
2589 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2591 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2593 skip("Symbol or Wingdings is not installed\n");
2597 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2598 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2599 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2602 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2605 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2606 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2609 skip("Symbol or Wingdings is not installed\n");
2612 static void test_GdiGetCodePage(void)
2614 static const struct _matching_data
2616 UINT current_codepage
;
2619 UINT expected_codepage
;
2620 } matching_data
[] = {
2621 {1251, "Arial", ANSI_CHARSET
, 1252},
2622 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2624 {1252, "Arial", ANSI_CHARSET
, 1252},
2625 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2627 {1253, "Arial", ANSI_CHARSET
, 1252},
2628 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2630 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2631 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2632 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2634 { 936, "Arial", ANSI_CHARSET
, 936},
2635 { 936, "Tahoma", ANSI_CHARSET
, 936},
2636 { 936, "Simsun", ANSI_CHARSET
, 936},
2638 { 949, "Arial", ANSI_CHARSET
, 949},
2639 { 949, "Tahoma", ANSI_CHARSET
, 949},
2640 { 949, "Gulim", ANSI_CHARSET
, 949},
2642 { 950, "Arial", ANSI_CHARSET
, 950},
2643 { 950, "Tahoma", ANSI_CHARSET
, 950},
2644 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2653 if (!pGdiGetCodePage
)
2655 skip("GdiGetCodePage not available on this platform\n");
2661 for (i
= 0; i
< sizeof(matching_data
) / sizeof(struct _matching_data
); i
++)
2663 /* only test data matched current locale codepage */
2664 if (matching_data
[i
].current_codepage
!= acp
)
2667 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2669 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2675 memset(&lf
, 0, sizeof(lf
));
2677 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2678 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2679 hfont
= CreateFontIndirectA(&lf
);
2680 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2682 hfont
= SelectObject(hdc
, hfont
);
2683 charset
= GetTextCharset(hdc
);
2684 codepage
= pGdiGetCodePage(hdc
);
2685 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2686 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
, matching_data
[i
].expected_codepage
);
2687 ok(codepage
== matching_data
[i
].expected_codepage
,
2688 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2690 hfont
= SelectObject(hdc
, hfont
);
2691 DeleteObject(hfont
);
2693 /* CLIP_DFA_DISABLE turns off the font association */
2694 lf
.lfClipPrecision
= CLIP_DFA_DISABLE
;
2695 hfont
= CreateFontIndirectA(&lf
);
2696 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2698 hfont
= SelectObject(hdc
, hfont
);
2699 charset
= GetTextCharset(hdc
);
2700 codepage
= pGdiGetCodePage(hdc
);
2701 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2702 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
);
2703 ok(codepage
== 1252, "GdiGetCodePage returned %d\n", codepage
);
2705 hfont
= SelectObject(hdc
, hfont
);
2706 DeleteObject(hfont
);
2708 ReleaseDC(NULL
, hdc
);
2712 static void test_GetFontUnicodeRanges(void)
2716 HFONT hfont
, hfont_old
;
2721 if (!pGetFontUnicodeRanges
)
2723 win_skip("GetFontUnicodeRanges not available before W2K\n");
2727 memset(&lf
, 0, sizeof(lf
));
2728 lstrcpyA(lf
.lfFaceName
, "Arial");
2729 hfont
= create_font("Arial", &lf
);
2732 hfont_old
= SelectObject(hdc
, hfont
);
2734 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2735 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2737 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2738 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2740 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2742 size
= pGetFontUnicodeRanges(hdc
, gs
);
2743 ok(size
, "GetFontUnicodeRanges failed\n");
2745 if (0) /* Disabled to limit console spam */
2746 for (i
= 0; i
< gs
->cRanges
; i
++)
2747 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2748 trace("found %u ranges\n", gs
->cRanges
);
2750 HeapFree(GetProcessHeap(), 0, gs
);
2752 SelectObject(hdc
, hfont_old
);
2753 DeleteObject(hfont
);
2754 ReleaseDC(NULL
, hdc
);
2757 struct enum_font_data
2763 struct enum_fullname_data
2769 struct enum_font_dataW
2775 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2777 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2778 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2780 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2781 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2783 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2785 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2787 if (0) /* Disabled to limit console spam */
2788 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2789 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2790 if (efd
->total
>= efd
->size
)
2792 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2793 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2794 if (!efd
->lf
) return 0;
2796 efd
->lf
[efd
->total
++] = *lf
;
2801 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2803 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2804 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2806 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2807 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2809 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2811 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2813 if (0) /* Disabled to limit console spam */
2814 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2815 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2816 if (efd
->total
>= efd
->size
)
2818 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2819 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2820 if (!efd
->lf
) return 0;
2822 efd
->lf
[efd
->total
++] = *lf
;
2827 static void get_charset_stats(struct enum_font_data
*efd
,
2828 int *ansi_charset
, int *symbol_charset
,
2829 int *russian_charset
)
2834 *symbol_charset
= 0;
2835 *russian_charset
= 0;
2837 for (i
= 0; i
< efd
->total
; i
++)
2839 switch (efd
->lf
[i
].lfCharSet
)
2844 case SYMBOL_CHARSET
:
2845 (*symbol_charset
)++;
2847 case RUSSIAN_CHARSET
:
2848 (*russian_charset
)++;
2854 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2855 int *ansi_charset
, int *symbol_charset
,
2856 int *russian_charset
)
2861 *symbol_charset
= 0;
2862 *russian_charset
= 0;
2864 for (i
= 0; i
< efd
->total
; i
++)
2866 switch (efd
->lf
[i
].lfCharSet
)
2871 case SYMBOL_CHARSET
:
2872 (*symbol_charset
)++;
2874 case RUSSIAN_CHARSET
:
2875 (*russian_charset
)++;
2881 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2883 struct enum_font_data efd
;
2884 struct enum_font_dataW efdw
;
2887 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2889 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2891 if (*font_name
&& !is_truetype_font_installed(font_name
))
2893 skip("%s is not installed\n", font_name
);
2896 memset( &efd
, 0, sizeof(efd
) );
2897 memset( &efdw
, 0, sizeof(efdw
) );
2901 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2902 * while EnumFontFamiliesEx doesn't.
2904 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2907 * Use EnumFontFamiliesW since win98 crashes when the
2908 * second parameter is NULL using EnumFontFamilies
2911 SetLastError(0xdeadbeef);
2912 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2913 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2916 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2917 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2918 ansi_charset
, symbol_charset
, russian_charset
);
2919 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2920 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2921 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2922 ok(russian_charset
> 0 ||
2923 broken(russian_charset
== 0), /* NT4 */
2924 "NULL family should enumerate RUSSIAN_CHARSET\n");
2928 SetLastError(0xdeadbeef);
2929 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2930 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2933 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2934 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2935 ansi_charset
, symbol_charset
, russian_charset
);
2936 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2937 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2938 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2939 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2944 SetLastError(0xdeadbeef);
2945 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2946 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2947 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2948 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2949 ansi_charset
, symbol_charset
, russian_charset
,
2950 *font_name
? font_name
: "<empty>");
2952 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2954 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2955 for (i
= 0; i
< efd
.total
; i
++)
2957 /* FIXME: remove completely once Wine is fixed */
2958 todo_wine_if(efd
.lf
[i
].lfCharSet
!= font_charset
)
2959 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2960 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2961 font_name
, efd
.lf
[i
].lfFaceName
);
2964 memset(&lf
, 0, sizeof(lf
));
2965 lf
.lfCharSet
= ANSI_CHARSET
;
2966 strcpy(lf
.lfFaceName
, font_name
);
2968 SetLastError(0xdeadbeef);
2969 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2970 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2971 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2972 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2973 ansi_charset
, symbol_charset
, russian_charset
,
2974 *font_name
? font_name
: "<empty>");
2975 if (font_charset
== SYMBOL_CHARSET
)
2978 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2980 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2984 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2985 for (i
= 0; i
< efd
.total
; i
++)
2987 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2989 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2990 font_name
, efd
.lf
[i
].lfFaceName
);
2994 /* DEFAULT_CHARSET should enumerate all available charsets */
2995 memset(&lf
, 0, sizeof(lf
));
2996 lf
.lfCharSet
= DEFAULT_CHARSET
;
2997 strcpy(lf
.lfFaceName
, font_name
);
2999 SetLastError(0xdeadbeef);
3000 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3001 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3002 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3003 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
3004 ansi_charset
, symbol_charset
, russian_charset
,
3005 *font_name
? font_name
: "<empty>");
3006 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
3007 for (i
= 0; i
< efd
.total
; i
++)
3010 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3011 font_name
, efd
.lf
[i
].lfFaceName
);
3015 switch (font_charset
)
3018 ok(ansi_charset
> 0,
3019 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3021 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
3022 ok(russian_charset
> 0,
3023 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3025 case SYMBOL_CHARSET
:
3027 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
3029 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3030 ok(!russian_charset
,
3031 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3033 case DEFAULT_CHARSET
:
3034 ok(ansi_charset
> 0,
3035 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3036 ok(symbol_charset
> 0,
3037 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3038 ok(russian_charset
> 0,
3039 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3045 ok(ansi_charset
> 0,
3046 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3047 ok(symbol_charset
> 0,
3048 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3049 ok(russian_charset
> 0,
3050 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3053 memset(&lf
, 0, sizeof(lf
));
3054 lf
.lfCharSet
= SYMBOL_CHARSET
;
3055 strcpy(lf
.lfFaceName
, font_name
);
3057 SetLastError(0xdeadbeef);
3058 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3059 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3060 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3061 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
3062 ansi_charset
, symbol_charset
, russian_charset
,
3063 *font_name
? font_name
: "<empty>");
3064 if (*font_name
&& font_charset
== ANSI_CHARSET
)
3065 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
3068 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
3069 for (i
= 0; i
< efd
.total
; i
++)
3071 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3073 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3074 font_name
, efd
.lf
[i
].lfFaceName
);
3078 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3079 ok(symbol_charset
> 0,
3080 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3081 ok(!russian_charset
,
3082 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3087 heap_free( efd
.lf
);
3088 heap_free( efdw
.lf
);
3091 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
3093 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
3094 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
3095 const DWORD valid_bits
= 0x003f01ff;
3099 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
3101 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
3102 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
3103 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
3112 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3114 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
3116 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3118 if (efd
->total
>= efd
->size
)
3120 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
3121 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
3122 if (!efd
->lf
) return 0;
3124 efd
->lf
[efd
->total
++] = *lf
;
3129 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3131 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
3133 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3135 if (efnd
->total
>= efnd
->size
)
3137 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3138 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3139 if (!efnd
->elf
) return 0;
3141 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
3146 static void test_EnumFontFamiliesEx_default_charset(void)
3148 struct enum_font_data efd
;
3149 LOGFONTA target
, enum_font
;
3155 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3156 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3161 memset(&enum_font
, 0, sizeof(enum_font
));
3162 enum_font
.lfCharSet
= csi
.ciCharset
;
3163 target
.lfFaceName
[0] = '\0';
3164 target
.lfCharSet
= csi
.ciCharset
;
3165 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3166 if (target
.lfFaceName
[0] == '\0') {
3167 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3170 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3171 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3172 target
.lfCharSet
= ANSI_CHARSET
;
3175 memset(&efd
, 0, sizeof(efd
));
3176 memset(&enum_font
, 0, sizeof(enum_font
));
3177 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3178 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3179 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3182 trace("'%s' has %d charsets.\n", target
.lfFaceName
, efd
.total
);
3184 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3186 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3187 "(%s) got charset %d expected %d\n",
3188 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3194 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3196 HFONT hfont
, hfont_prev
;
3198 GLYPHMETRICS gm1
, gm2
;
3202 if(!pGetGlyphIndicesA
)
3205 /* negative widths are handled just as positive ones */
3206 lf2
.lfWidth
= -lf
->lfWidth
;
3208 SetLastError(0xdeadbeef);
3209 hfont
= CreateFontIndirectA(lf
);
3210 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3211 check_font("original", lf
, hfont
);
3213 hfont_prev
= SelectObject(hdc
, hfont
);
3215 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3216 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3218 SelectObject(hdc
, hfont_prev
);
3219 DeleteObject(hfont
);
3220 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3224 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3225 memset(&gm1
, 0xab, sizeof(gm1
));
3226 SetLastError(0xdeadbeef);
3227 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3228 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3230 SelectObject(hdc
, hfont_prev
);
3231 DeleteObject(hfont
);
3233 SetLastError(0xdeadbeef);
3234 hfont
= CreateFontIndirectA(&lf2
);
3235 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3236 check_font("negative width", &lf2
, hfont
);
3238 hfont_prev
= SelectObject(hdc
, hfont
);
3240 memset(&gm2
, 0xbb, sizeof(gm2
));
3241 SetLastError(0xdeadbeef);
3242 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3243 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3245 SelectObject(hdc
, hfont_prev
);
3246 DeleteObject(hfont
);
3248 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3249 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3250 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3251 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3252 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3253 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3254 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3255 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3256 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3257 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3258 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3261 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3262 #include "pshpack2.h"
3266 SHORT xAvgCharWidth
;
3267 USHORT usWeightClass
;
3268 USHORT usWidthClass
;
3270 SHORT ySubscriptXSize
;
3271 SHORT ySubscriptYSize
;
3272 SHORT ySubscriptXOffset
;
3273 SHORT ySubscriptYOffset
;
3274 SHORT ySuperscriptXSize
;
3275 SHORT ySuperscriptYSize
;
3276 SHORT ySuperscriptXOffset
;
3277 SHORT ySuperscriptYOffset
;
3278 SHORT yStrikeoutSize
;
3279 SHORT yStrikeoutPosition
;
3282 ULONG ulUnicodeRange1
;
3283 ULONG ulUnicodeRange2
;
3284 ULONG ulUnicodeRange3
;
3285 ULONG ulUnicodeRange4
;
3288 USHORT usFirstCharIndex
;
3289 USHORT usLastCharIndex
;
3290 /* According to the Apple spec, original version didn't have the below fields,
3291 * version numbers were taken from the OpenType spec.
3293 /* version 0 (TrueType 1.5) */
3294 USHORT sTypoAscender
;
3295 USHORT sTypoDescender
;
3296 USHORT sTypoLineGap
;
3298 USHORT usWinDescent
;
3299 /* version 1 (TrueType 1.66) */
3300 ULONG ulCodePageRange1
;
3301 ULONG ulCodePageRange2
;
3302 /* version 2 (OpenType 1.2) */
3305 USHORT usDefaultChar
;
3307 USHORT usMaxContext
;
3308 /* version 4 (OpenType 1.6) */
3309 USHORT usLowerOpticalPointSize
;
3310 USHORT usUpperOpticalPointSize
;
3312 #include "poppack.h"
3314 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3327 } cmap_encoding_record
;
3335 BYTE glyph_ids
[256];
3345 USHORT search_range
;
3346 USHORT entry_selector
;
3349 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3352 USHORT start_count[seg_countx2 / 2];
3353 USHORT id_delta[seg_countx2 / 2];
3354 USHORT id_range_offset[seg_countx2 / 2];
3364 USHORT id_range_offset
;
3365 } cmap_format_4_seg
;
3367 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V4
*os2
, WORD family
, const char *name
)
3369 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3370 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3371 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3372 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3373 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3376 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3379 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3383 for(i
= 0; i
< 256; i
++)
3385 if(cmap
->glyph_ids
[i
] == 0) continue;
3387 if(*first
== 256) *first
= i
;
3389 if(*first
== 256) return FALSE
;
3393 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3395 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3396 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3397 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3398 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3399 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3402 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3405 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3406 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3410 for(i
= 0; i
< seg_count
; i
++)
3412 cmap_format_4_seg seg
;
3414 get_seg4(cmap
, i
, &seg
);
3416 if(seg
.start_count
> 0xfffe) break;
3418 if(*first
== 0x10000) *first
= seg
.start_count
;
3420 *last
= min(seg
.end_count
, 0xfffe);
3423 if(*first
== 0x10000) return FALSE
;
3427 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3430 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3432 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3434 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3435 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3448 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3451 cmap_header
*header
;
3456 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3457 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3458 if(size
== GDI_ERROR
) return FALSE
;
3460 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3461 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3462 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3463 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3465 cmap
= get_cmap(header
, 3, 1);
3467 *cmap_type
= cmap_ms_unicode
;
3470 cmap
= get_cmap(header
, 3, 0);
3471 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3475 *cmap_type
= cmap_none
;
3479 format
= GET_BE_WORD(*(WORD
*)cmap
);
3483 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3486 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3489 trace("unhandled cmap format %d\n", format
);
3494 HeapFree(GetProcessHeap(), 0, header
);
3498 #define TT_PLATFORM_APPLE_UNICODE 0
3499 #define TT_PLATFORM_MACINTOSH 1
3500 #define TT_PLATFORM_MICROSOFT 3
3501 #define TT_APPLE_ID_DEFAULT 0
3502 #define TT_APPLE_ID_ISO_10646 2
3503 #define TT_APPLE_ID_UNICODE_2_0 3
3504 #define TT_MS_ID_SYMBOL_CS 0
3505 #define TT_MS_ID_UNICODE_CS 1
3506 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3507 #define TT_NAME_ID_FONT_FAMILY 1
3508 #define TT_NAME_ID_FONT_SUBFAMILY 2
3509 #define TT_NAME_ID_UNIQUE_ID 3
3510 #define TT_NAME_ID_FULL_NAME 4
3511 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3513 typedef struct sfnt_name
3523 static const LANGID mac_langid_table
[] =
3525 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
3526 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
3527 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
3528 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
3529 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
3530 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
3531 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
3532 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
3533 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
3534 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
3535 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
3536 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
3537 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
3538 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
3539 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
3540 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
3541 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
3542 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
3543 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
3544 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3545 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
3546 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
3547 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
3548 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
3549 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
3550 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
3551 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
3552 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
3553 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
3554 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
3555 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
3556 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
3557 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
3558 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3559 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
3560 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
3561 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
3562 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
3563 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
3564 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
3565 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
3566 0, /* TT_MAC_LANGID_YIDDISH */
3567 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
3568 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
3569 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
3570 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
3571 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
3572 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
3573 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
3574 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
3575 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3576 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
3577 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
3578 0, /* TT_MAC_LANGID_MOLDAVIAN */
3579 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
3580 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
3581 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
3582 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
3583 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3584 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
3585 0, /* TT_MAC_LANGID_KURDISH */
3586 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
3587 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
3588 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
3589 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
3590 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
3591 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
3592 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
3593 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
3594 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
3595 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
3596 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
3597 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
3598 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
3599 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
3600 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
3601 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
3602 0, /* TT_MAC_LANGID_BURMESE */
3603 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
3604 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
3605 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
3606 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
3607 0, /* TT_MAC_LANGID_TAGALOG */
3608 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3609 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3610 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
3611 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
3612 0, /* TT_MAC_LANGID_GALLA */
3613 0, /* TT_MAC_LANGID_SOMALI */
3614 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
3615 0, /* TT_MAC_LANGID_RUANDA */
3616 0, /* TT_MAC_LANGID_RUNDI */
3617 0, /* TT_MAC_LANGID_CHEWA */
3618 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
3619 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
3620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3621 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3622 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
3623 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
3624 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
3625 0, /* TT_MAC_LANGID_LATIN */
3626 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
3627 0, /* TT_MAC_LANGID_GUARANI */
3628 0, /* TT_MAC_LANGID_AYMARA */
3629 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
3630 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
3631 0, /* TT_MAC_LANGID_DZONGKHA */
3632 0, /* TT_MAC_LANGID_JAVANESE */
3633 0, /* TT_MAC_LANGID_SUNDANESE */
3634 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
3635 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
3636 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
3637 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
3638 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3639 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
3640 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
3641 0, /* TT_MAC_LANGID_TONGAN */
3642 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3643 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
3644 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3647 static inline WORD
get_mac_code_page( const sfnt_name
*name
)
3649 if (GET_BE_WORD(name
->encoding_id
) == TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
3650 return 10000 + GET_BE_WORD(name
->encoding_id
);
3653 static int match_name_table_language( const sfnt_name
*name
, LANGID lang
)
3658 switch (GET_BE_WORD(name
->platform_id
))
3660 case TT_PLATFORM_MICROSOFT
:
3661 res
+= 5; /* prefer the Microsoft name */
3662 switch (GET_BE_WORD(name
->encoding_id
))
3664 case TT_MS_ID_UNICODE_CS
:
3665 case TT_MS_ID_SYMBOL_CS
:
3666 name_lang
= GET_BE_WORD(name
->language_id
);
3672 case TT_PLATFORM_MACINTOSH
:
3673 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
3674 if (GET_BE_WORD(name
->language_id
) >= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
3675 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3677 case TT_PLATFORM_APPLE_UNICODE
:
3678 res
+= 2; /* prefer Unicode encodings */
3679 switch (GET_BE_WORD(name
->encoding_id
))
3681 case TT_APPLE_ID_DEFAULT
:
3682 case TT_APPLE_ID_ISO_10646
:
3683 case TT_APPLE_ID_UNICODE_2_0
:
3684 if (GET_BE_WORD(name
->language_id
) >= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
3685 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3694 if (name_lang
== lang
) res
+= 30;
3695 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
3696 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
3700 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3702 struct sfnt_name_header
3705 USHORT number_of_record
;
3706 USHORT storage_offset
;
3710 LONG size
, offset
, length
;
3715 int res
, best_lang
= 0, best_index
= -1;
3717 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3718 ok(size
!= GDI_ERROR
, "no name table found\n");
3719 if(size
== GDI_ERROR
) return FALSE
;
3721 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3722 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3723 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3725 header
= (void *)data
;
3726 header
->format
= GET_BE_WORD(header
->format
);
3727 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3728 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3729 if (header
->format
!= 0)
3731 trace("got format %u\n", header
->format
);
3734 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3736 trace("number records out of range: %d\n", header
->number_of_record
);
3739 if (header
->storage_offset
>= size
)
3741 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3745 entry
= (void *)&header
[1];
3746 for (i
= 0; i
< header
->number_of_record
; i
++)
3748 if (GET_BE_WORD(entry
[i
].name_id
) != name_id
) continue;
3749 res
= match_name_table_language( &entry
[i
], language_id
);
3750 if (res
> best_lang
)
3757 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[best_index
].offset
);
3758 length
= GET_BE_WORD(entry
[best_index
].length
);
3759 if (offset
+ length
> size
)
3761 trace("entry %d is out of range\n", best_index
);
3764 if (length
>= out_size
)
3766 trace("buffer too small for entry %d\n", best_index
);
3770 name
= (WCHAR
*)(data
+ offset
);
3771 for (c
= 0; c
< length
/ 2; c
++)
3772 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3778 HeapFree(GetProcessHeap(), 0, data
);
3782 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3785 HFONT hfont
, hfont_old
;
3789 const char *font_name
= lf
->lfFaceName
;
3790 DWORD cmap_first
= 0, cmap_last
= 0;
3791 UINT ascent
, descent
, cell_height
;
3792 cmap_type cmap_type
;
3793 BOOL sys_lang_non_english
;
3795 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3798 SetLastError(0xdeadbeef);
3799 hfont
= CreateFontIndirectA(lf
);
3800 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3802 hfont_old
= SelectObject(hdc
, hfont
);
3804 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3805 if (size
== GDI_ERROR
)
3807 trace("OS/2 chunk was not found\n");
3810 if (size
> sizeof(tt_os2
))
3812 trace("got too large OS/2 chunk of size %u\n", size
);
3813 size
= sizeof(tt_os2
);
3816 memset(&tt_os2
, 0, sizeof(tt_os2
));
3817 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3818 ok(ret
>= TT_OS2_V0_SIZE
&& ret
<= size
, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE
,
3821 SetLastError(0xdeadbeef);
3822 ret
= GetTextMetricsA(hdc
, &tmA
);
3823 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3825 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3827 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3831 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3832 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3833 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3837 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3838 descent
= abs((SHORT
)GET_BE_WORD(tt_os2
.usWinDescent
));
3839 cell_height
= ascent
+ descent
;
3840 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3841 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3843 version
= GET_BE_WORD(tt_os2
.version
);
3845 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3846 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3847 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3848 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3850 if (winetest_debug
> 1)
3851 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3852 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3853 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3855 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3860 case 1255: /* Hebrew */
3861 expect_last_W
= 0xf896;
3863 case 1257: /* Baltic */
3864 expect_last_W
= 0xf8fd;
3867 expect_last_W
= 0xf0ff;
3869 expect_break_W
= 0x20;
3870 expect_default_W
= expect_break_W
- 1;
3871 expect_first_A
= 0x1e;
3872 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3876 expect_first_W
= cmap_first
;
3877 expect_last_W
= cmap_last
;
3878 if(os2_first_char
<= 1)
3879 expect_break_W
= os2_first_char
+ 2;
3880 else if(os2_first_char
> 0xff)
3881 expect_break_W
= 0x20;
3883 expect_break_W
= os2_first_char
;
3884 expect_default_W
= expect_break_W
- 1;
3885 expect_first_A
= expect_default_W
- 1;
3886 expect_last_A
= min(expect_last_W
, 0xff);
3888 expect_break_A
= expect_break_W
;
3889 expect_default_A
= expect_default_W
;
3891 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3892 todo_wine_if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3893 ok(tmA
.tmFirstChar
== expect_first_A
||
3894 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3895 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3896 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3897 ok(tmA
.tmLastChar
== expect_last_A
||
3898 tmA
.tmLastChar
== 0xff /* win9x */,
3899 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3901 skip("tmLastChar is DBCS lead byte\n");
3902 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3903 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3904 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3905 "A: tmDefaultChar for %s got %02x expected %02x\n",
3906 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3909 SetLastError(0xdeadbeef);
3910 ret
= GetTextMetricsW(hdc
, &tmW
);
3911 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3912 "GetTextMetricsW error %u\n", GetLastError());
3915 /* Wine uses the os2 first char */
3916 todo_wine_if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3917 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3918 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3920 /* Wine uses the os2 last char */
3921 todo_wine_if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3922 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3923 font_name
, tmW
.tmLastChar
, expect_last_W
);
3924 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3925 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3926 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3927 "W: tmDefaultChar for %s got %02x expected %02x\n",
3928 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3930 /* Test the aspect ratio while we have tmW */
3931 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3932 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3933 tmW
.tmDigitizedAspectX
, ret
);
3934 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3935 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3936 tmW
.tmDigitizedAspectX
, ret
);
3940 /* test FF_ values */
3941 switch(tt_os2
.panose
.bFamilyType
)
3945 case PAN_FAMILY_TEXT_DISPLAY
:
3946 case PAN_FAMILY_PICTORIAL
:
3948 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3949 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3951 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3954 switch(tt_os2
.panose
.bSerifStyle
)
3959 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3962 case PAN_SERIF_COVE
:
3963 case PAN_SERIF_OBTUSE_COVE
:
3964 case PAN_SERIF_SQUARE_COVE
:
3965 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3966 case PAN_SERIF_SQUARE
:
3967 case PAN_SERIF_THIN
:
3968 case PAN_SERIF_BONE
:
3969 case PAN_SERIF_EXAGGERATED
:
3970 case PAN_SERIF_TRIANGLE
:
3971 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3974 case PAN_SERIF_NORMAL_SANS
:
3975 case PAN_SERIF_OBTUSE_SANS
:
3976 case PAN_SERIF_PERP_SANS
:
3977 case PAN_SERIF_FLARED
:
3978 case PAN_SERIF_ROUNDED
:
3979 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3984 case PAN_FAMILY_SCRIPT
:
3985 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3988 case PAN_FAMILY_DECORATIVE
:
3989 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3993 test_negative_width(hdc
, lf
);
3996 SelectObject(hdc
, hfont_old
);
3997 DeleteObject(hfont
);
4002 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4004 INT
*enumed
= (INT
*)lParam
;
4006 if (type
== TRUETYPE_FONTTYPE
)
4009 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
4014 static void test_GetTextMetrics(void)
4020 /* Report only once */
4021 if(!pGetGlyphIndicesA
)
4022 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
4026 memset(&lf
, 0, sizeof(lf
));
4027 lf
.lfCharSet
= DEFAULT_CHARSET
;
4029 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
4030 trace("Tested metrics of %d truetype fonts\n", enumed
);
4035 static void test_nonexistent_font(void)
4043 { "Times New Roman Baltic", 186 },
4044 { "Times New Roman CE", 238 },
4045 { "Times New Roman CYR", 204 },
4046 { "Times New Roman Greek", 161 },
4047 { "Times New Roman TUR", 162 }
4055 { "MS Shell Dlg", 186 },
4056 { "MS Shell Dlg", 238 },
4057 { "MS Shell Dlg", 204 },
4058 { "MS Shell Dlg", 161 },
4059 { "MS Shell Dlg", 162 }
4065 INT cs
, expected_cs
, i
, ret
;
4066 char buf
[LF_FACESIZE
];
4068 expected_cs
= GetACP();
4069 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
4071 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
4074 expected_cs
= csi
.ciCharset
;
4075 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
4077 hdc
= CreateCompatibleDC(0);
4079 for (i
= 0; i
< sizeof(shell_subst
)/sizeof(shell_subst
[0]); i
++)
4081 ret
= is_font_installed(shell_subst
[i
].name
);
4082 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4083 ret
= is_truetype_font_installed(shell_subst
[i
].name
);
4084 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4086 memset(&lf
, 0, sizeof(lf
));
4088 lf
.lfWeight
= FW_REGULAR
;
4089 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4090 hfont
= CreateFontIndirectA(&lf
);
4091 hfont
= SelectObject(hdc
, hfont
);
4092 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4093 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4094 cs
= GetTextCharset(hdc
);
4095 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, shell_subst
[i
].name
);
4097 DeleteObject(SelectObject(hdc
, hfont
));
4099 memset(&lf
, 0, sizeof(lf
));
4101 lf
.lfWeight
= FW_DONTCARE
;
4102 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4103 hfont
= CreateFontIndirectA(&lf
);
4104 hfont
= SelectObject(hdc
, hfont
);
4105 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4106 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4107 cs
= GetTextCharset(hdc
);
4108 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, shell_subst
[i
].name
);
4109 DeleteObject(SelectObject(hdc
, hfont
));
4112 if (!is_truetype_font_installed("Arial") ||
4113 !is_truetype_font_installed("Times New Roman"))
4116 skip("Arial or Times New Roman not installed\n");
4120 memset(&lf
, 0, sizeof(lf
));
4122 lf
.lfWeight
= FW_REGULAR
;
4123 lf
.lfCharSet
= ANSI_CHARSET
;
4124 lf
.lfPitchAndFamily
= FF_SWISS
;
4125 strcpy(lf
.lfFaceName
, "Nonexistent font");
4126 hfont
= CreateFontIndirectA(&lf
);
4127 hfont
= SelectObject(hdc
, hfont
);
4128 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4129 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
4130 cs
= GetTextCharset(hdc
);
4131 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4132 DeleteObject(SelectObject(hdc
, hfont
));
4134 memset(&lf
, 0, sizeof(lf
));
4136 lf
.lfWeight
= FW_DONTCARE
;
4137 strcpy(lf
.lfFaceName
, "Nonexistent font");
4138 hfont
= CreateFontIndirectA(&lf
);
4139 hfont
= SelectObject(hdc
, hfont
);
4140 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4141 todo_wine
/* Wine uses Arial for all substitutions */
4142 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
4143 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
4144 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4146 cs
= GetTextCharset(hdc
);
4147 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
4148 DeleteObject(SelectObject(hdc
, hfont
));
4150 memset(&lf
, 0, sizeof(lf
));
4152 lf
.lfWeight
= FW_REGULAR
;
4153 strcpy(lf
.lfFaceName
, "Nonexistent font");
4154 hfont
= CreateFontIndirectA(&lf
);
4155 hfont
= SelectObject(hdc
, hfont
);
4156 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4157 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4158 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
4159 cs
= GetTextCharset(hdc
);
4160 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4161 DeleteObject(SelectObject(hdc
, hfont
));
4163 memset(&lf
, 0, sizeof(lf
));
4165 lf
.lfWeight
= FW_DONTCARE
;
4166 strcpy(lf
.lfFaceName
, "Times New Roman");
4167 hfont
= CreateFontIndirectA(&lf
);
4168 hfont
= SelectObject(hdc
, hfont
);
4169 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4170 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
4171 cs
= GetTextCharset(hdc
);
4172 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4173 DeleteObject(SelectObject(hdc
, hfont
));
4175 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
4177 ret
= is_font_installed(font_subst
[i
].name
);
4179 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4180 "%s should be enumerated\n", font_subst
[i
].name
);
4181 ret
= is_truetype_font_installed(font_subst
[i
].name
);
4183 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4184 "%s should be enumerated\n", font_subst
[i
].name
);
4186 memset(&lf
, 0, sizeof(lf
));
4188 lf
.lfWeight
= FW_REGULAR
;
4189 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4190 hfont
= CreateFontIndirectA(&lf
);
4191 hfont
= SelectObject(hdc
, hfont
);
4192 cs
= GetTextCharset(hdc
);
4193 if (font_subst
[i
].charset
== expected_cs
)
4195 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4196 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4197 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
4201 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
4202 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4203 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4204 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
4206 DeleteObject(SelectObject(hdc
, hfont
));
4208 memset(&lf
, 0, sizeof(lf
));
4210 lf
.lfWeight
= FW_DONTCARE
;
4211 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4212 hfont
= CreateFontIndirectA(&lf
);
4213 hfont
= SelectObject(hdc
, hfont
);
4214 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4215 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
4216 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
4217 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
4218 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4219 "got %s for font %s\n", buf
, font_subst
[i
].name
);
4220 cs
= GetTextCharset(hdc
);
4221 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4222 DeleteObject(SelectObject(hdc
, hfont
));
4228 static void test_RealizationInfo(void)
4230 struct font_realization_info
{
4240 struct realization_info_t
4248 DWORD info
[4], info2
[10];
4249 BOOL r
, have_file
= FALSE
;
4250 HFONT hfont
, hfont_old
;
4254 BYTE file
[16], data
[14];
4259 WCHAR path
[MAX_PATH
];
4264 if(!pGdiRealizationInfo
)
4266 win_skip("GdiRealizationInfo not available\n");
4272 memset(info
, 0xcc, sizeof(info
));
4273 r
= pGdiRealizationInfo(hdc
, info
);
4274 ok(r
!= 0, "ret 0\n");
4275 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
4276 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4278 if (!is_truetype_font_installed("Tahoma"))
4280 skip("skipping GdiRealizationInfo with truetype font\n");
4284 memset(&lf
, 0, sizeof(lf
));
4285 strcpy(lf
.lfFaceName
, "Tahoma");
4287 lf
.lfWeight
= FW_BOLD
;
4289 hfont
= CreateFontIndirectA(&lf
);
4290 hfont_old
= SelectObject(hdc
, hfont
);
4292 memset(info
, 0xcc, sizeof(info
));
4293 r
= pGdiRealizationInfo(hdc
, info
);
4294 ok(r
!= 0, "ret 0\n");
4295 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
4296 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4298 if (pGetFontRealizationInfo
)
4300 struct font_realization_info
*fri
= (struct font_realization_info
*)info2
;
4301 struct realization_info_t
*ri
= (struct realization_info_t
*)info
;
4303 /* The first DWORD represents a struct size. On a
4304 newly rebooted system setting this to < 16 results
4305 in GetFontRealizationInfo failing. However there
4306 appears to be some caching going on which results
4307 in calls after a successful call also succeeding even
4308 if the size < 16. This means we can't reliably test
4311 memset(info2
, 0xcc, sizeof(info2
));
4313 r
= pGetFontRealizationInfo(hdc
, info2
);
4314 ok(r
!= 0, "ret 0\n");
4315 /* We may get the '24' version here if that has been previously
4317 ok(fri
->size
== 16 || fri
->size
== 24, "got %d\n", info2
[0]);
4318 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4319 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4320 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4321 ok(info2
[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2
[6]);
4323 memset(info2
, 0xcc, sizeof(info2
));
4325 r
= pGetFontRealizationInfo(hdc
, info2
);
4326 ok(r
== FALSE
, "got %d\n", r
);
4328 memset(info2
, 0xcc, sizeof(info2
));
4330 r
= pGetFontRealizationInfo(hdc
, info2
);
4331 ok(r
!= 0, "ret 0\n");
4332 ok(fri
->size
== 24, "got %d\n", fri
->size
);
4333 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4334 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4335 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4336 ok(fri
->simulations
== 0x2, "got simulations flags 0x%04x\n", fri
->simulations
);
4337 ok(fri
->face_index
== 0, "got wrong face index %u\n", fri
->face_index
);
4338 ok(info2
[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4340 /* Test GetFontFileInfo() */
4341 /* invalid font id */
4342 SetLastError(0xdeadbeef);
4343 r
= pGetFontFileInfo(0xabababab, 0, &file_info
, sizeof(file_info
), &needed
);
4344 ok(r
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "ret %d gle %d\n", r
, GetLastError());
4347 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, sizeof(file_info
), &needed
);
4348 ok(r
!= 0 || GetLastError() == ERROR_NOACCESS
, "ret %d gle %d\n", r
, GetLastError());
4352 ok(needed
> 0 && needed
< sizeof(file_info
), "got needed size %u\n", needed
);
4354 h
= CreateFileW(file_info
.path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
4355 ok(h
!= INVALID_HANDLE_VALUE
, "Unable to open file %d\n", GetLastError());
4357 GetFileTime(h
, NULL
, NULL
, &time
);
4358 ok(!CompareFileTime(&file_info
.time
, &time
), "time mismatch\n");
4359 GetFileSizeEx(h
, &size
);
4360 ok(file_info
.size
.QuadPart
== size
.QuadPart
, "size mismatch\n");
4362 /* Read first 16 bytes from the file */
4363 ReadFile(h
, file
, sizeof(file
), &read
, NULL
);
4367 /* shorter buffer */
4368 SetLastError(0xdeadbeef);
4369 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, needed
- 1, &needed
);
4370 ok(r
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "ret %d gle %d\n", r
, GetLastError());
4373 if (pGetFontFileData
) {
4374 /* Get bytes 2 - 16 using GetFontFileData */
4375 r
= pGetFontFileData(fri
->instance_id
, 0, 2, data
, sizeof(data
));
4376 ok(r
!= 0, "ret 0 gle %d\n", GetLastError());
4379 ok(!memcmp(data
, file
+ 2, sizeof(data
)), "mismatch\n");
4381 win_skip("GetFontFileInfo() failed, skipping\n");
4385 DeleteObject(SelectObject(hdc
, hfont_old
));
4391 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4392 the nul in the count of characters copied when the face name buffer is not
4393 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4394 always includes it. */
4395 static void test_GetTextFace(void)
4397 static const char faceA
[] = "Tahoma";
4398 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
4401 char bufA
[LF_FACESIZE
];
4402 WCHAR bufW
[LF_FACESIZE
];
4407 if(!is_font_installed("Tahoma"))
4409 skip("Tahoma is not installed so skipping this test\n");
4414 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
4415 f
= CreateFontIndirectA(&fA
);
4416 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
4419 g
= SelectObject(dc
, f
);
4420 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
4421 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
4422 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
4424 /* Play with the count arg. */
4426 n
= GetTextFaceA(dc
, 0, bufA
);
4427 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4428 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4431 n
= GetTextFaceA(dc
, 1, bufA
);
4432 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4433 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4435 bufA
[0] = 'x'; bufA
[1] = 'y';
4436 n
= GetTextFaceA(dc
, 2, bufA
);
4437 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
4438 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
4440 n
= GetTextFaceA(dc
, 0, NULL
);
4441 ok(n
== sizeof faceA
||
4442 broken(n
== 0), /* win98, winMe */
4443 "GetTextFaceA returned %d\n", n
);
4445 DeleteObject(SelectObject(dc
, g
));
4446 ReleaseDC(NULL
, dc
);
4449 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
4450 SetLastError(0xdeadbeef);
4451 f
= CreateFontIndirectW(&fW
);
4452 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4454 win_skip("CreateFontIndirectW is not implemented\n");
4457 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
4460 g
= SelectObject(dc
, f
);
4461 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
4462 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4463 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
4465 /* Play with the count arg. */
4467 n
= GetTextFaceW(dc
, 0, bufW
);
4468 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
4469 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4472 n
= GetTextFaceW(dc
, 1, bufW
);
4473 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
4474 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4476 bufW
[0] = 'x'; bufW
[1] = 'y';
4477 n
= GetTextFaceW(dc
, 2, bufW
);
4478 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4479 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4481 n
= GetTextFaceW(dc
, 0, NULL
);
4482 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4484 DeleteObject(SelectObject(dc
, g
));
4485 ReleaseDC(NULL
, dc
);
4488 static void test_orientation(void)
4490 static const char test_str
[11] = "Test String";
4493 HFONT hfont
, old_hfont
;
4496 if (!is_truetype_font_installed("Arial"))
4498 skip("Arial is not installed\n");
4502 hdc
= CreateCompatibleDC(0);
4503 memset(&lf
, 0, sizeof(lf
));
4504 lstrcpyA(lf
.lfFaceName
, "Arial");
4506 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4507 hfont
= create_font("orientation", &lf
);
4508 old_hfont
= SelectObject(hdc
, hfont
);
4509 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4510 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4511 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4512 SelectObject(hdc
, old_hfont
);
4513 DeleteObject(hfont
);
4517 static void test_oemcharset(void)
4521 HFONT hfont
, old_hfont
;
4524 hdc
= CreateCompatibleDC(0);
4525 ZeroMemory(&lf
, sizeof(lf
));
4527 lf
.lfCharSet
= OEM_CHARSET
;
4528 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4529 lstrcpyA(lf
.lfFaceName
, "Terminal");
4530 hfont
= CreateFontIndirectA(&lf
);
4531 old_hfont
= SelectObject(hdc
, hfont
);
4532 charset
= GetTextCharset(hdc
);
4534 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4535 hfont
= SelectObject(hdc
, old_hfont
);
4536 GetObjectA(hfont
, sizeof(clf
), &clf
);
4537 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4538 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4539 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4540 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4541 DeleteObject(hfont
);
4545 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4546 const TEXTMETRICA
*lpntme
,
4547 DWORD FontType
, LPARAM lParam
)
4549 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4551 LOGFONTA lf
= *lpelfe
;
4555 /* skip bitmap, proportional or vertical font */
4556 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4557 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4558 lf
.lfFaceName
[0] == '@')
4561 /* skip linked font */
4562 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4563 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4566 /* skip linked font, like SimSun-ExtB */
4567 switch (lpelfe
->lfCharSet
) {
4568 case SHIFTJIS_CHARSET
:
4569 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4571 case GB2312_CHARSET
:
4572 case CHINESEBIG5_CHARSET
:
4573 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4575 case HANGEUL_CHARSET
:
4576 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4579 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4585 /* test with an odd height */
4588 hfont
= CreateFontIndirectA(&lf
);
4591 *(HFONT
*)lParam
= hfont
;
4597 static void test_GetGlyphOutline(void)
4600 GLYPHMETRICS gm
, gm2
;
4602 HFONT hfont
, old_hfont
;
4604 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4605 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4613 {ANSI_CHARSET
, 0x30, 0x30},
4614 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4615 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4616 {GB2312_CHARSET
, 0x8141, 0x4e04},
4617 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4621 if (!is_truetype_font_installed("Tahoma"))
4623 skip("Tahoma is not installed\n");
4627 hdc
= CreateCompatibleDC(0);
4628 memset(&lf
, 0, sizeof(lf
));
4630 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4631 SetLastError(0xdeadbeef);
4632 hfont
= CreateFontIndirectA(&lf
);
4633 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4634 old_hfont
= SelectObject(hdc
, hfont
);
4636 memset(&gm
, 0, sizeof(gm
));
4637 SetLastError(0xdeadbeef);
4638 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4639 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4641 memset(&gm
, 0, sizeof(gm
));
4642 SetLastError(0xdeadbeef);
4643 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4644 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4645 ok(GetLastError() == 0xdeadbeef ||
4646 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4647 "expected 0xdeadbeef, got %u\n", GetLastError());
4649 memset(&gm
, 0, sizeof(gm
));
4650 SetLastError(0xdeadbeef);
4651 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4652 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4653 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4655 memset(&gm
, 0, sizeof(gm
));
4656 SetLastError(0xdeadbeef);
4657 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4658 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4660 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4661 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4664 /* test for needed buffer size request on space char */
4665 memset(&gm
, 0, sizeof(gm
));
4666 SetLastError(0xdeadbeef);
4667 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4668 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4670 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4671 ok(gm
.gmBlackBoxX
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxX
);
4672 ok(gm
.gmBlackBoxY
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxY
);
4675 /* requesting buffer size for space char + error */
4676 memset(&gm
, 0, sizeof(gm
));
4677 SetLastError(0xdeadbeef);
4678 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4679 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4681 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4682 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4683 ok(gm
.gmBlackBoxX
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxX
);
4684 ok(gm
.gmBlackBoxY
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxY
);
4687 /* test GetGlyphOutline with a buffer too small */
4688 SetLastError(0xdeadbeef);
4689 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_NATIVE
, &gm
, sizeof(i
), &i
, &mat
);
4690 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4691 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4693 for (i
= 0; i
< sizeof(fmt
) / sizeof(fmt
[0]); ++i
)
4697 memset(&gm
, 0xab, sizeof(gm
));
4698 SetLastError(0xdeadbeef);
4699 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4700 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4702 if (fmt
[i
] == GGO_METRICS
)
4703 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4705 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4706 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4707 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4710 memset(&gm
, 0xab, sizeof(gm
));
4711 SetLastError(0xdeadbeef);
4712 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4713 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4715 if (fmt
[i
] == GGO_METRICS
)
4716 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4718 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4719 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4720 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4723 memset(&gm
, 0xab, sizeof(gm
));
4724 SetLastError(0xdeadbeef);
4725 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4726 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4728 if (fmt
[i
] == GGO_METRICS
)
4729 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4731 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4732 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4733 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4736 memset(&gm
, 0xab, sizeof(gm
));
4737 SetLastError(0xdeadbeef);
4738 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4739 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4741 if (fmt
[i
] == GGO_METRICS
) {
4742 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4743 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4744 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4748 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4749 memset(&gm2
, 0xab, sizeof(gm2
));
4750 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4751 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4756 SelectObject(hdc
, old_hfont
);
4757 DeleteObject(hfont
);
4759 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
4761 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4764 lf
.lfFaceName
[0] = '\0';
4765 lf
.lfCharSet
= c
[i
].cs
;
4766 lf
.lfPitchAndFamily
= 0;
4767 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4769 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4773 old_hfont
= SelectObject(hdc
, hfont
);
4775 /* expected to ignore superfluous bytes (sigle-byte character) */
4776 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4777 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4778 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4780 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4781 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4782 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4784 /* expected to ignore superfluous bytes (double-byte character) */
4785 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4786 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4787 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4788 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4790 /* expected to match wide-char version results */
4791 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4792 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4794 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4796 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4799 DeleteObject(SelectObject(hdc
, hfont
));
4802 DeleteObject(SelectObject(hdc
, old_hfont
));
4806 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4807 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4809 ret
= GetTextMetricsA(hdc
, &tm
);
4810 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4811 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4812 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4813 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4814 -lf
.lfHeight
, tm
.tmAveCharWidth
, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4815 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4816 "expected %d, got %d (%s:%d)\n",
4817 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4819 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4820 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4821 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4822 "expected %d, got %d (%s:%d)\n",
4823 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4826 hfont
= CreateFontIndirectA(&lf
);
4827 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4828 DeleteObject(SelectObject(hdc
, hfont
));
4829 ret
= GetTextMetricsA(hdc
, &tm
);
4830 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4831 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4832 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4833 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4834 "expected %d, got %d (%s:%d)\n",
4835 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4837 lf
.lfItalic
= FALSE
;
4838 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4839 hfont
= CreateFontIndirectA(&lf
);
4840 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4841 DeleteObject(SelectObject(hdc
, hfont
));
4842 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4843 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4844 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4845 "expected %d, got %d (%s:%d)\n",
4846 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4848 hfont
= SelectObject(hdc
, old_hfont
);
4849 DeleteObject(hfont
);
4855 /* bug #9995: there is a limit to the character width that can be specified */
4856 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4862 int ave_width
, height
, width
, ratio
, scale
;
4864 if (!is_truetype_font_installed( fontname
)) {
4865 skip("%s is not installed\n", fontname
);
4868 hdc
= CreateCompatibleDC(0);
4869 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4870 /* select width = 0 */
4871 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4872 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4873 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4875 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4876 of
= SelectObject( hdc
, hf
);
4877 ret
= GetTextMetricsA( hdc
, &tm
);
4878 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4879 height
= tm
.tmHeight
;
4880 ave_width
= tm
.tmAveCharWidth
;
4881 SelectObject( hdc
, of
);
4884 trace("height %d, ave width %d\n", height
, ave_width
);
4886 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4888 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4889 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4890 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4891 ok(hf
!= 0, "CreateFont failed\n");
4892 of
= SelectObject(hdc
, hf
);
4893 ret
= GetTextMetricsA(hdc
, &tm
);
4894 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4895 SelectObject(hdc
, of
);
4898 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4904 ratio
= width
/ height
;
4905 scale
= width
/ ave_width
;
4907 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4908 width
, height
, ratio
, width
, ave_width
, scale
);
4910 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4913 static void test_GetCharacterPlacement(void)
4915 GCP_RESULTSA result
;
4920 hdc
= CreateCompatibleDC(0);
4921 ok(!!hdc
, "CreateCompatibleDC failed\n");
4923 memset(&result
, 0, sizeof(result
));
4924 result
.lStructSize
= sizeof(result
);
4925 result
.lpGlyphs
= glyphs
;
4926 result
.nGlyphs
= 20;
4928 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, &result
, 0);
4929 ok(size
, "GetCharacterPlacementA failed!\n");
4931 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, NULL
, 0);
4932 ok(size2
, "GetCharacterPlacementA failed!\n");
4933 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
4935 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, NULL
, GCP_REORDER
);
4936 ok(size2
, "GetCharacterPlacementA failed!\n");
4937 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
4939 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, &result
, GCP_REORDER
);
4940 ok(size
, "GetCharacterPlacementA failed!\n");
4941 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
4944 static void test_CreateFontIndirect(void)
4946 LOGFONTA lf
, getobj_lf
;
4949 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4951 memset(&lf
, 0, sizeof(lf
));
4952 lf
.lfCharSet
= ANSI_CHARSET
;
4953 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4956 lf
.lfQuality
= DEFAULT_QUALITY
;
4957 lf
.lfItalic
= FALSE
;
4958 lf
.lfWeight
= FW_DONTCARE
;
4960 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
4962 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4963 hfont
= CreateFontIndirectA(&lf
);
4964 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4965 SetLastError(0xdeadbeef);
4966 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
4967 ok(ret
, "GetObject failed: %d\n", GetLastError());
4968 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
4969 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
4970 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
4971 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
4972 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
4973 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
4974 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
4975 DeleteObject(hfont
);
4979 static void test_CreateFontIndirectEx(void)
4981 ENUMLOGFONTEXDVA lfex
;
4984 if (!pCreateFontIndirectExA
)
4986 win_skip("CreateFontIndirectExA is not available\n");
4990 if (!is_truetype_font_installed("Arial"))
4992 skip("Arial is not installed\n");
4996 SetLastError(0xdeadbeef);
4997 hfont
= pCreateFontIndirectExA(NULL
);
4998 ok(hfont
== NULL
, "got %p\n", hfont
);
4999 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
5001 memset(&lfex
, 0, sizeof(lfex
));
5002 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
5003 hfont
= pCreateFontIndirectExA(&lfex
);
5004 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
5006 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
5007 DeleteObject(hfont
);
5010 static void free_font(void *font
)
5012 UnmapViewOfFile(font
);
5015 static void *load_font(const char *font_name
, DWORD
*font_size
)
5017 char file_name
[MAX_PATH
];
5018 HANDLE file
, mapping
;
5021 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
5022 strcat(file_name
, "\\fonts\\");
5023 strcat(file_name
, font_name
);
5025 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
5026 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
5028 *font_size
= GetFileSize(file
, NULL
);
5030 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
5037 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
5040 CloseHandle(mapping
);
5044 static void test_AddFontMemResource(void)
5047 DWORD font_size
, num_fonts
;
5051 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
5053 win_skip("AddFontMemResourceEx is not available on this platform\n");
5057 font
= load_font("sserife.fon", &font_size
);
5060 skip("Unable to locate and load font sserife.fon\n");
5064 SetLastError(0xdeadbeef);
5065 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
5066 ok(!ret
, "AddFontMemResourceEx should fail\n");
5067 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5068 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5071 SetLastError(0xdeadbeef);
5072 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
5073 ok(!ret
, "AddFontMemResourceEx should fail\n");
5074 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5075 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5078 SetLastError(0xdeadbeef);
5079 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
5080 ok(!ret
, "AddFontMemResourceEx should fail\n");
5081 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5082 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5085 SetLastError(0xdeadbeef);
5086 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
5087 ok(!ret
, "AddFontMemResourceEx should fail\n");
5088 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5089 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5092 SetLastError(0xdeadbeef);
5093 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
5094 ok(!ret
, "AddFontMemResourceEx should fail\n");
5095 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5096 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5099 SetLastError(0xdeadbeef);
5100 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
5101 ok(!ret
, "AddFontMemResourceEx should fail\n");
5102 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5103 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5106 num_fonts
= 0xdeadbeef;
5107 SetLastError(0xdeadbeef);
5108 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
5109 ok(!ret
, "AddFontMemResourceEx should fail\n");
5110 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5111 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5113 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5115 if (0) /* hangs under windows 2000 */
5117 num_fonts
= 0xdeadbeef;
5118 SetLastError(0xdeadbeef);
5119 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
5120 ok(!ret
, "AddFontMemResourceEx should fail\n");
5121 ok(GetLastError() == 0xdeadbeef,
5122 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5124 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5127 num_fonts
= 0xdeadbeef;
5128 SetLastError(0xdeadbeef);
5129 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5130 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
5131 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5132 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
5136 SetLastError(0xdeadbeef);
5137 bRet
= pRemoveFontMemResourceEx(ret
);
5138 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
5140 /* test invalid pointer to number of loaded fonts */
5141 font
= load_font("sserife.fon", &font_size
);
5142 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
5144 SetLastError(0xdeadbeef);
5145 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
5146 ok(!ret
, "AddFontMemResourceEx should fail\n");
5147 ok(GetLastError() == 0xdeadbeef,
5148 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5151 SetLastError(0xdeadbeef);
5152 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
5153 ok(!ret
, "AddFontMemResourceEx should fail\n");
5154 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5155 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5161 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5165 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5167 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5169 lf
= (LOGFONTA
*)lparam
;
5174 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5179 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5181 lf
= (LOGFONTA
*)lparam
;
5182 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
5185 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5192 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5197 static void test_EnumFonts(void)
5203 if (!is_truetype_font_installed("Arial"))
5205 skip("Arial is not installed\n");
5209 /* Windows uses localized font face names, so Arial Bold won't be found */
5210 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
5212 skip("User locale is not English, skipping the test\n");
5216 hdc
= CreateCompatibleDC(0);
5218 /* check that the enumproc's retval is returned */
5219 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
5220 ok(ret
== 0xcafe, "got %08x\n", ret
);
5222 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
5223 ok(!ret
, "font Arial is not enumerated\n");
5224 ret
= strcmp(lf
.lfFaceName
, "Arial");
5225 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5226 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5228 strcpy(lf
.lfFaceName
, "Arial");
5229 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5230 ok(!ret
, "font Arial is not enumerated\n");
5231 ret
= strcmp(lf
.lfFaceName
, "Arial");
5232 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5233 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5235 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5236 ok(!ret
, "font Arial Bold is not enumerated\n");
5237 ret
= strcmp(lf
.lfFaceName
, "Arial");
5238 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5239 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5241 strcpy(lf
.lfFaceName
, "Arial Bold");
5242 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5243 ok(ret
, "font Arial Bold should not be enumerated\n");
5245 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
5246 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
5247 ret
= strcmp(lf
.lfFaceName
, "Arial");
5248 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5249 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5251 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
5252 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5253 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
5255 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5256 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5258 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
5259 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5260 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5265 static INT CALLBACK
enum_ms_shell_dlg_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5267 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5269 if (0) /* Disabled to limit console spam */
5270 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5271 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5273 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5274 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg") != 0) return 1;
5276 if (efnd
->total
>= efnd
->size
)
5278 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5279 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5280 if (!efnd
->elf
) return 0;
5282 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5286 static INT CALLBACK
enum_ms_shell_dlg2_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5288 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5290 if (0) /* Disabled to limit console spam */
5291 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5292 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5294 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5295 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg 2") != 0) return 1;
5297 if (efnd
->total
>= efnd
->size
)
5299 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5300 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5301 if (!efnd
->elf
) return 0;
5303 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5307 static void test_EnumFonts_subst(void)
5312 struct enum_fullname_data efnd
;
5314 ret
= is_font_installed("MS Shell Dlg");
5315 ok(ret
, "MS Shell Dlg should be enumerated\n");
5316 ret
= is_truetype_font_installed("MS Shell Dlg");
5317 ok(ret
, "MS Shell Dlg should be enumerated as a TrueType font\n");
5319 ret
= is_font_installed("MS Shell Dlg 2");
5320 ok(ret
, "MS Shell Dlg 2 should be enumerated\n");
5321 ret
= is_truetype_font_installed("MS Shell Dlg 2");
5322 ok(ret
, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5324 hdc
= CreateCompatibleDC(0);
5326 memset(&efnd
, 0, sizeof(efnd
));
5327 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5328 ok(ret
, "MS Shell Dlg should not be enumerated\n");
5329 ok(!efnd
.total
, "MS Shell Dlg should not be enumerated\n");
5331 memset(&lf
, 0, sizeof(lf
));
5332 lf
.lfCharSet
= DEFAULT_CHARSET
;
5335 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
5336 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5337 ok(!ret
, "MS Shell Dlg should be enumerated\n");
5338 ok(efnd
.total
> 0, "MS Shell Dlg should be enumerated\n");
5341 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
5342 ok(!ret
, "expected MS Shell Dlg, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5343 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
5344 ok(ret
, "did not expect MS Shell Dlg\n");
5348 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5349 ok(ret
, "MS Shell Dlg 2 should not be enumerated\n");
5350 ok(!efnd
.total
, "MS Shell Dlg 2 should not be enumerated\n");
5353 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
5354 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5355 ok(!ret
, "MS Shell Dlg 2 should be enumerated\n");
5356 ok(efnd
.total
> 0, "MS Shell Dlg 2 should be enumerated\n");
5359 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
5360 ok(!ret
, "expected MS Shell Dlg 2, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5361 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
5362 ok(ret
, "did not expect MS Shell Dlg 2\n");
5365 heap_free(efnd
.elf
);
5369 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5371 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
5372 const char *fullname
= (const char *)lParam
;
5374 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
5379 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
5384 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
5391 static void test_fullname(void)
5393 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5394 WCHAR bufW
[LF_FULLFACESIZE
];
5395 char bufA
[LF_FULLFACESIZE
];
5402 hdc
= CreateCompatibleDC(0);
5403 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5405 memset(&lf
, 0, sizeof(lf
));
5406 lf
.lfCharSet
= ANSI_CHARSET
;
5407 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5410 lf
.lfQuality
= DEFAULT_QUALITY
;
5411 lf
.lfItalic
= FALSE
;
5412 lf
.lfWeight
= FW_DONTCARE
;
5414 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
5416 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
5418 skip("%s is not installed\n", TestName
[i
]);
5422 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5423 hfont
= CreateFontIndirectA(&lf
);
5424 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5426 of
= SelectObject(hdc
, hfont
);
5429 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5430 ok(ret
, "face full name could not be read\n");
5431 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
5432 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
5433 SelectObject(hdc
, of
);
5434 DeleteObject(hfont
);
5439 static WCHAR
*prepend_at(WCHAR
*family
)
5444 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
5449 static void test_fullname2_helper(const char *Family
)
5451 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
5452 struct enum_fullname_data efnd
;
5459 DWORD otm_size
, ret
, buf_size
;
5460 OUTLINETEXTMETRICA
*otm
;
5461 BOOL want_vertical
, get_vertical
;
5462 want_vertical
= ( Family
[0] == '@' );
5464 hdc
= CreateCompatibleDC(0);
5465 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5467 memset(&lf
, 0, sizeof(lf
));
5468 lf
.lfCharSet
= DEFAULT_CHARSET
;
5469 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5472 lf
.lfQuality
= DEFAULT_QUALITY
;
5473 lf
.lfItalic
= FALSE
;
5474 lf
.lfWeight
= FW_DONTCARE
;
5475 strcpy(lf
.lfFaceName
, Family
);
5476 memset(&efnd
, 0, sizeof(efnd
));
5477 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
5478 if (efnd
.total
== 0)
5479 skip("%s is not installed\n", lf
.lfFaceName
);
5481 for (i
= 0; i
< efnd
.total
; i
++)
5483 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
5484 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
5485 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
5487 get_vertical
= ( FamilyName
[0] == '@' );
5488 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
5490 lstrcpyA(lf
.lfFaceName
, FaceName
);
5491 hfont
= CreateFontIndirectA(&lf
);
5492 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5494 of
= SelectObject(hdc
, hfont
);
5495 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
5496 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
5497 if (buf_size
== GDI_ERROR
) continue;
5499 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5500 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5502 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5503 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5504 memset(otm
, 0, otm_size
);
5505 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
5506 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
5507 if (ret
== 0) continue;
5511 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5512 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5513 ok(ret
, "%s: FAMILY (family name) could not be read\n", FamilyName
);
5514 if (want_vertical
) bufW
= prepend_at(bufW
);
5515 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5516 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
5517 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
5518 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
5522 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
5523 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5524 ok(ret
, "FULL_NAME (face name) could not be read\n");
5525 if (want_vertical
) bufW
= prepend_at(bufW
);
5526 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5527 ok(!lstrcmpA(FaceName
, bufA
), "%s: font face names don't match: returned %s, expect %s\n", FamilyName
, FaceName
, bufA
);
5528 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
5529 ok(!lstrcmpA(FaceName
, otmStr
), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName
, FaceName
, otmStr
);
5533 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5534 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5535 ok(ret
, "%s: SUBFAMILY (style name) could not be read\n", FamilyName
);
5536 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5537 ok(!lstrcmpA(StyleName
, bufA
), "%s: style names don't match: returned %s, expect %s\n", FamilyName
, StyleName
, bufA
);
5538 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
5539 ok(!lstrcmpA(StyleName
, otmStr
), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName
, StyleName
, otmStr
);
5543 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
5544 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5545 ok(ret
, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName
);
5546 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5547 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
5548 ok(!lstrcmpA(otmStr
, bufA
), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName
, otmStr
, bufA
);
5550 SelectObject(hdc
, of
);
5551 DeleteObject(hfont
);
5553 HeapFree(GetProcessHeap(), 0, otm
);
5554 HeapFree(GetProcessHeap(), 0, bufW
);
5555 HeapFree(GetProcessHeap(), 0, bufA
);
5557 heap_free(efnd
.elf
);
5561 static void test_fullname2(void)
5563 test_fullname2_helper("Arial");
5564 test_fullname2_helper("DejaVu Sans");
5565 test_fullname2_helper("Lucida Sans");
5566 test_fullname2_helper("Tahoma");
5567 test_fullname2_helper("Webdings");
5568 test_fullname2_helper("Wingdings");
5569 test_fullname2_helper("SimSun");
5570 test_fullname2_helper("NSimSun");
5571 test_fullname2_helper("MingLiu");
5572 test_fullname2_helper("PMingLiu");
5573 test_fullname2_helper("WenQuanYi Micro Hei");
5574 test_fullname2_helper("MS UI Gothic");
5575 test_fullname2_helper("Ume UI Gothic");
5576 test_fullname2_helper("MS Gothic");
5577 test_fullname2_helper("Ume Gothic");
5578 test_fullname2_helper("MS PGothic");
5579 test_fullname2_helper("Ume P Gothic");
5580 test_fullname2_helper("Gulim");
5581 test_fullname2_helper("Batang");
5582 test_fullname2_helper("UnBatang");
5583 test_fullname2_helper("UnDotum");
5584 test_fullname2_helper("@SimSun");
5585 test_fullname2_helper("@NSimSun");
5586 test_fullname2_helper("@MingLiu");
5587 test_fullname2_helper("@PMingLiu");
5588 test_fullname2_helper("@WenQuanYi Micro Hei");
5589 test_fullname2_helper("@MS UI Gothic");
5590 test_fullname2_helper("@Ume UI Gothic");
5591 test_fullname2_helper("@MS Gothic");
5592 test_fullname2_helper("@Ume Gothic");
5593 test_fullname2_helper("@MS PGothic");
5594 test_fullname2_helper("@Ume P Gothic");
5595 test_fullname2_helper("@Gulim");
5596 test_fullname2_helper("@Batang");
5597 test_fullname2_helper("@UnBatang");
5598 test_fullname2_helper("@UnDotum");
5602 static void test_GetGlyphOutline_empty_contour(void)
5606 HFONT hfont
, hfont_prev
;
5607 TTPOLYGONHEADER
*header
;
5612 memset(&lf
, 0, sizeof(lf
));
5614 lstrcpyA(lf
.lfFaceName
, "wine_test");
5616 hfont
= CreateFontIndirectA(&lf
);
5617 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5621 hfont_prev
= SelectObject(hdc
, hfont
);
5622 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5624 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5625 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5627 header
= (TTPOLYGONHEADER
*)buf
;
5628 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5629 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5630 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5631 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5632 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5633 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5634 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5635 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5637 SelectObject(hdc
, hfont_prev
);
5638 DeleteObject(hfont
);
5639 ReleaseDC(NULL
, hdc
);
5642 static void test_GetGlyphOutline_metric_clipping(void)
5646 HFONT hfont
, hfont_prev
;
5652 memset(&lf
, 0, sizeof(lf
));
5654 lstrcpyA(lf
.lfFaceName
, "wine_test");
5656 SetLastError(0xdeadbeef);
5657 hfont
= CreateFontIndirectA(&lf
);
5658 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5662 hfont_prev
= SelectObject(hdc
, hfont
);
5663 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5665 SetLastError(0xdeadbeef);
5666 ret
= GetTextMetricsA(hdc
, &tm
);
5667 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5669 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5670 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5671 "Glyph top(%d) exceeds ascent(%d)\n",
5672 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5673 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5674 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5675 "Glyph bottom(%d) exceeds descent(%d)\n",
5676 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5678 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5679 GetTextMetricsW(hdc
, &tmW
);
5681 ok( tmW
.tmLastChar
== 0xfffe, "got %04x\n", tmW
.tmLastChar
);
5683 SelectObject(hdc
, hfont_prev
);
5684 DeleteObject(hfont
);
5685 ReleaseDC(NULL
, hdc
);
5688 static void test_fstype_fixup(void)
5692 HFONT hfont
, hfont_prev
;
5694 OUTLINETEXTMETRICA
*otm
;
5697 memset(&lf
, 0, sizeof(lf
));
5699 lstrcpyA(lf
.lfFaceName
, "wine_test");
5701 SetLastError(0xdeadbeef);
5702 hfont
= CreateFontIndirectA(&lf
);
5703 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5707 hfont_prev
= SelectObject(hdc
, hfont
);
5708 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5710 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5711 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5712 otm
->otmSize
= sizeof(*otm
);
5713 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
5714 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
5716 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5717 valid bits are 1, 2, 3, 8, 9. */
5718 ok((otm
->otmfsType
& ~0x30e) == 0, "fsType %#x\n", otm
->otmfsType
);
5720 HeapFree(GetProcessHeap(), 0, otm
);
5722 SelectObject(hdc
, hfont_prev
);
5723 DeleteObject(hfont
);
5724 ReleaseDC(NULL
, hdc
);
5727 static void test_CreateScalableFontResource(void)
5729 char ttf_name
[MAX_PATH
];
5730 char tmp_path
[MAX_PATH
];
5731 char fot_name
[MAX_PATH
];
5736 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
5738 win_skip("AddFontResourceExA is not available on this platform\n");
5742 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5744 skip("Failed to create ttf file for testing\n");
5748 trace("created %s\n", ttf_name
);
5750 ret
= is_truetype_font_installed("wine_test");
5751 ok(!ret
, "font wine_test should not be enumerated\n");
5753 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
5754 ok(ret
, "GetTempPath() error %d\n", GetLastError());
5755 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
5756 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
5758 ret
= GetFileAttributesA(fot_name
);
5759 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
5761 SetLastError(0xdeadbeef);
5762 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5763 ok(!ret
, "CreateScalableFontResource() should fail\n");
5764 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5766 SetLastError(0xdeadbeef);
5767 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
5768 ok(!ret
, "CreateScalableFontResource() should fail\n");
5769 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5771 file_part
= strrchr(ttf_name
, '\\');
5772 SetLastError(0xdeadbeef);
5773 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
5774 ok(!ret
, "CreateScalableFontResource() should fail\n");
5775 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5777 SetLastError(0xdeadbeef);
5778 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
5779 ok(!ret
, "CreateScalableFontResource() should fail\n");
5780 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5782 SetLastError(0xdeadbeef);
5783 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
5784 ok(!ret
, "CreateScalableFontResource() should fail\n");
5785 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5787 ret
= DeleteFileA(fot_name
);
5788 ok(ret
, "DeleteFile() error %d\n", GetLastError());
5790 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5791 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5793 /* test public font resource */
5794 SetLastError(0xdeadbeef);
5795 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5796 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5798 ret
= is_truetype_font_installed("wine_test");
5799 ok(!ret
, "font wine_test should not be enumerated\n");
5801 SetLastError(0xdeadbeef);
5802 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5803 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5805 ret
= is_truetype_font_installed("wine_test");
5806 ok(ret
, "font wine_test should be enumerated\n");
5808 test_GetGlyphOutline_empty_contour();
5809 test_GetGlyphOutline_metric_clipping();
5810 test_fstype_fixup();
5812 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5813 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
5815 SetLastError(0xdeadbeef);
5816 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5817 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5819 ret
= is_truetype_font_installed("wine_test");
5820 ok(!ret
, "font wine_test should not be enumerated\n");
5822 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5823 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5825 /* test refcounting */
5826 for (i
= 0; i
< 5; i
++)
5828 SetLastError(0xdeadbeef);
5829 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5830 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5832 for (i
= 0; i
< 5; i
++)
5834 SetLastError(0xdeadbeef);
5835 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5836 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5838 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5839 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5841 DeleteFileA(fot_name
);
5843 /* test hidden font resource */
5844 SetLastError(0xdeadbeef);
5845 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
5846 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5848 ret
= is_truetype_font_installed("wine_test");
5849 ok(!ret
, "font wine_test should not be enumerated\n");
5851 SetLastError(0xdeadbeef);
5852 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5853 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5855 ret
= is_truetype_font_installed("wine_test");
5857 ok(!ret
, "font wine_test should not be enumerated\n");
5859 /* XP allows removing a private font added with 0 flags */
5860 SetLastError(0xdeadbeef);
5861 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5862 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5864 ret
= is_truetype_font_installed("wine_test");
5865 ok(!ret
, "font wine_test should not be enumerated\n");
5867 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5868 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5870 DeleteFileA(fot_name
);
5871 DeleteFileA(ttf_name
);
5874 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
5877 HFONT hfont
, hfont_prev
;
5881 static const WCHAR str
[] = { 0x2025 };
5883 *installed
= is_truetype_font_installed(name
);
5887 lf
.lfEscapement
= 0;
5888 lf
.lfOrientation
= 0;
5889 lf
.lfWeight
= FW_DONTCARE
;
5893 lf
.lfCharSet
= DEFAULT_CHARSET
;
5894 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
5895 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5896 lf
.lfQuality
= DEFAULT_QUALITY
;
5897 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
5898 strcpy(lf
.lfFaceName
, name
);
5900 hfont
= CreateFontIndirectA(&lf
);
5901 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
5905 hfont_prev
= SelectObject(hdc
, hfont
);
5906 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5908 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
5909 ok(ret
, "GetTextFaceA failed\n");
5910 *selected
= !strcmp(facename
, name
);
5912 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
5913 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5915 memset(gm
, 0, sizeof *gm
);
5917 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
5918 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
5920 SelectObject(hdc
, hfont_prev
);
5921 DeleteObject(hfont
);
5922 ReleaseDC(NULL
, hdc
);
5925 static void check_vertical_metrics(const char *face
)
5928 HFONT hfont
, hfont_prev
;
5931 GLYPHMETRICS rgm
, vgm
;
5932 const UINT code
= 0x5EAD, height
= 1000;
5935 OUTLINETEXTMETRICA otm
;
5936 USHORT numOfLongVerMetrics
;
5940 memset(&lf
, 0, sizeof(lf
));
5941 strcpy(lf
.lfFaceName
, face
);
5942 lf
.lfHeight
= -height
;
5943 lf
.lfCharSet
= DEFAULT_CHARSET
;
5944 lf
.lfEscapement
= lf
.lfOrientation
= 900;
5945 hfont
= CreateFontIndirectA(&lf
);
5946 hfont_prev
= SelectObject(hdc
, hfont
);
5947 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
5948 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5949 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
5950 ok(ret
, "GetCharABCWidthsW failed\n");
5951 DeleteObject(SelectObject(hdc
, hfont_prev
));
5953 memset(&lf
, 0, sizeof(lf
));
5954 strcpy(lf
.lfFaceName
, "@");
5955 strcat(lf
.lfFaceName
, face
);
5956 lf
.lfHeight
= -height
;
5957 lf
.lfCharSet
= DEFAULT_CHARSET
;
5958 hfont
= CreateFontIndirectA(&lf
);
5959 hfont_prev
= SelectObject(hdc
, hfont
);
5960 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
5961 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5963 memset(&otm
, 0, sizeof(otm
));
5964 otm
.otmSize
= sizeof(otm
);
5965 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
5966 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
5968 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
5969 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
5971 SHORT topSideBearing
;
5973 if (!pGetGlyphIndicesW
) {
5974 win_skip("GetGlyphIndices is not available on this platform\n");
5977 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
5978 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
5979 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
5980 if (numOfLongVerMetrics
> idx
)
5981 offset
= idx
* 2 + 1;
5983 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
5984 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
5985 &topSideBearing
, sizeof(SHORT
));
5986 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
5987 topSideBearing
= GET_BE_WORD(topSideBearing
);
5988 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
5989 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
5990 "expected %d, got %d\n",
5991 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
5996 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
5997 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5998 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
6001 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
6002 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
6003 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6004 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
6006 DeleteObject(SelectObject(hdc
, hfont_prev
));
6007 ReleaseDC(NULL
, hdc
);
6010 static void test_vertical_font(void)
6012 char ttf_name
[MAX_PATH
];
6014 BOOL ret
, installed
, selected
;
6017 const char* face_list
[] = {
6018 "@WineTestVertical", /* has vmtx table */
6019 "@Ume Gothic", /* doesn't have vmtx table */
6020 "@MS UI Gothic", /* has vmtx table, available on native */
6023 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
6025 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
6029 if (!write_ttf_file("vertical.ttf", ttf_name
))
6031 skip("Failed to create ttf file for testing\n");
6035 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6036 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6038 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
6039 ok(installed
, "WineTestVertical is not installed\n");
6040 ok(selected
, "WineTestVertical is not selected\n");
6041 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6042 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6043 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6045 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
6046 ok(installed
, "@WineTestVertical is not installed\n");
6047 ok(selected
, "@WineTestVertical is not selected\n");
6048 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6049 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6050 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6052 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
6054 for (i
= 0; i
< sizeof(face_list
)/sizeof(face_list
[0]); i
++) {
6055 const char* face
= face_list
[i
];
6056 if (!is_truetype_font_installed(face
)) {
6057 skip("%s is not installed\n", face
);
6060 trace("Testing %s...\n", face
);
6061 check_vertical_metrics(&face
[1]);
6064 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6065 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6067 DeleteFileA(ttf_name
);
6070 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
6071 DWORD type
, LPARAM lParam
)
6073 if (lf
->lfFaceName
[0] == '@') {
6079 static void test_east_asian_font_selection(void)
6082 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
6083 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
6088 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
6092 char face_name
[LF_FACESIZE
];
6095 memset(&lf
, 0, sizeof lf
);
6096 lf
.lfFaceName
[0] = '\0';
6097 lf
.lfCharSet
= charset
[i
];
6099 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
6101 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
6105 hfont
= CreateFontIndirectA(&lf
);
6106 hfont
= SelectObject(hdc
, hfont
);
6107 memset(face_name
, 0, sizeof face_name
);
6108 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6109 ok(ret
&& face_name
[0] != '@',
6110 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6111 DeleteObject(SelectObject(hdc
, hfont
));
6113 memset(&lf
, 0, sizeof lf
);
6114 strcpy(lf
.lfFaceName
, "@");
6115 lf
.lfCharSet
= charset
[i
];
6116 hfont
= CreateFontIndirectA(&lf
);
6117 hfont
= SelectObject(hdc
, hfont
);
6118 memset(face_name
, 0, sizeof face_name
);
6119 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6120 ok(ret
&& face_name
[0] == '@',
6121 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6122 DeleteObject(SelectObject(hdc
, hfont
));
6124 ReleaseDC(NULL
, hdc
);
6127 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
6129 HDC hdc
= CreateCompatibleDC(0);
6134 hfont
= CreateFontIndirectA(lf
);
6135 ok(hfont
!= 0, "CreateFontIndirect failed\n");
6137 SelectObject(hdc
, hfont
);
6138 ret
= GetTextMetricsA(hdc
, &tm
);
6139 ok(ret
, "GetTextMetrics failed\n");
6140 ret
= tm
.tmDigitizedAspectX
;
6141 if (height
) *height
= tm
.tmHeight
;
6144 DeleteObject(hfont
);
6149 static void test_stock_fonts(void)
6151 static const int font
[] =
6153 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
6154 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6156 static const struct test_data
6158 int charset
, weight
, height
, height_pixels
, dpi
;
6159 const char face_name
[LF_FACESIZE
];
6163 { /* ANSI_FIXED_FONT */
6164 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_ARABIC
},
6165 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_HEBREW
},
6166 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
6167 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
6170 { /* ANSI_VAR_FONT */
6171 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
6172 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
6176 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6177 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6178 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6179 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6180 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6181 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6184 { /* DEVICE_DEFAULT_FONT */
6185 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6186 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6187 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6188 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6189 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6190 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6193 { /* DEFAULT_GUI_FONT */
6194 { SHIFTJIS_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6195 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
6196 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
6197 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
6198 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
6199 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
6200 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
6201 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
6202 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
6203 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6204 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6210 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
6216 hfont
= GetStockObject(font
[i
]);
6217 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
6219 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
6220 if (ret
!= sizeof(lf
))
6223 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
6227 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
6229 if ((lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
) ||
6230 (system_lang_id
!= td
[i
][j
].lang_id
&& td
[i
][j
].lang_id
!= LANG_NEUTRAL
) ||
6231 (td
[i
][j
].face_name
[0] != '?' && strcmp(lf
.lfFaceName
, td
[i
][j
].face_name
)))
6236 ret
= get_font_dpi(&lf
, &height
);
6237 if (ret
!= td
[i
][j
].dpi
)
6239 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6240 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
6244 /* FIXME: Remove once Wine is fixed */
6245 todo_wine_if (td
[i
][j
].dpi
!= 96 &&
6246 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6247 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
6248 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6249 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
6250 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
6252 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
6253 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
6254 if (td
[i
][j
].face_name
[0] == '?')
6256 /* Wine doesn't have this font, skip this case for now.
6257 Actually, the face name is localized on Windows and varies
6258 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6259 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
6263 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
);
6270 static void test_max_height(void)
6274 HFONT hfont
, hfont_old
;
6275 TEXTMETRICA tm1
, tm
;
6277 LONG invalid_height
[] = { -65536, -123456, 123456 };
6280 memset(&tm1
, 0, sizeof(tm1
));
6281 memset(&lf
, 0, sizeof(lf
));
6282 strcpy(lf
.lfFaceName
, "Tahoma");
6287 /* get 1 ppem value */
6288 hfont
= CreateFontIndirectA(&lf
);
6289 hfont_old
= SelectObject(hdc
, hfont
);
6290 r
= GetTextMetricsA(hdc
, &tm1
);
6291 ok(r
, "GetTextMetrics failed\n");
6292 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6293 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6294 DeleteObject(SelectObject(hdc
, hfont_old
));
6296 /* test the largest value */
6297 lf
.lfHeight
= -((1 << 16) - 1);
6298 hfont
= CreateFontIndirectA(&lf
);
6299 hfont_old
= SelectObject(hdc
, hfont
);
6300 memset(&tm
, 0, sizeof(tm
));
6301 r
= GetTextMetricsA(hdc
, &tm
);
6302 ok(r
, "GetTextMetrics failed\n");
6303 ok(tm
.tmHeight
> tm1
.tmHeight
,
6304 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6305 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
6306 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6307 DeleteObject(SelectObject(hdc
, hfont_old
));
6309 /* test an invalid value */
6310 for (i
= 0; i
< sizeof(invalid_height
)/sizeof(invalid_height
[0]); i
++) {
6311 lf
.lfHeight
= invalid_height
[i
];
6312 hfont
= CreateFontIndirectA(&lf
);
6313 hfont_old
= SelectObject(hdc
, hfont
);
6314 memset(&tm
, 0, sizeof(tm
));
6315 r
= GetTextMetricsA(hdc
, &tm
);
6316 ok(r
, "GetTextMetrics failed\n");
6317 ok(tm
.tmHeight
== tm1
.tmHeight
,
6318 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6319 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
6320 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6321 DeleteObject(SelectObject(hdc
, hfont_old
));
6324 ReleaseDC(NULL
, hdc
);
6328 static void test_vertical_order(void)
6330 struct enum_font_data efd
;
6335 hdc
= CreateCompatibleDC(0);
6336 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6338 memset(&lf
, 0, sizeof(lf
));
6339 lf
.lfCharSet
= DEFAULT_CHARSET
;
6340 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6343 lf
.lfQuality
= DEFAULT_QUALITY
;
6344 lf
.lfItalic
= FALSE
;
6345 lf
.lfWeight
= FW_DONTCARE
;
6346 memset( &efd
, 0, sizeof(efd
) );
6347 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
6348 for (i
= 0; i
< efd
.total
; i
++)
6350 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
6351 for (j
= 0; j
< efd
.total
; j
++)
6353 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
6355 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
6360 heap_free( efd
.lf
);
6364 static void test_GetCharWidth32(void)
6374 if (!pGetCharWidth32A
|| !pGetCharWidth32W
)
6376 win_skip("GetCharWidth32A/W not available on this platform\n");
6380 memset(&lf
, 0, sizeof(lf
));
6381 strcpy(lf
.lfFaceName
, "System");
6384 hfont
= CreateFontIndirectA(&lf
);
6386 hfont
= SelectObject(hdc
, hfont
);
6388 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6389 ok(ret
, "GetCharWidth32W should have succeeded\n");
6390 ret
= pGetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
6391 ok(ret
, "GetCharWidth32A should have succeeded\n");
6392 ok (bufferA
== bufferW
, "Widths should be the same\n");
6393 ok (bufferA
> 0," Width should be greater than zero\n");
6395 hfont
= SelectObject(hdc
, hfont
);
6396 DeleteObject(hfont
);
6397 ReleaseDC(NULL
, hdc
);
6399 memset(&lf
, 0, sizeof(lf
));
6400 strcpy(lf
.lfFaceName
, "Tahoma");
6403 hfont
= CreateFontIndirectA(&lf
);
6404 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
6407 SetMapMode( hdc
, MM_ANISOTROPIC
);
6408 SelectObject(hdc
, hfont
);
6410 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6411 ok(ret
, "GetCharWidth32W should have succeeded\n");
6412 ok (bufferW
> 0," Width should be greater than zero\n");
6413 SetWindowExtEx(hdc
, -1,-1,NULL
);
6414 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6415 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6416 ok(ret
, "GetCharWidth32W should have succeeded\n");
6417 ok (bufferW
> 0," Width should be greater than zero\n");
6418 SetGraphicsMode(hdc
, GM_ADVANCED
);
6419 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6420 ok(ret
, "GetCharWidth32W should have succeeded\n");
6421 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
6422 SetWindowExtEx(hdc
, 1,1,NULL
);
6423 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6424 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6425 ok(ret
, "GetCharWidth32W should have succeeded\n");
6426 ok (bufferW
> 0," Width should be greater than zero\n");
6427 SetGraphicsMode(hdc
, GM_ADVANCED
);
6428 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6429 ok(ret
, "GetCharWidth32W should have succeeded\n");
6430 ok (bufferW
> 0," Width should be greater than zero\n");
6432 ReleaseDC(hwnd
, hdc
);
6433 DestroyWindow(hwnd
);
6435 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
6438 SetMapMode( hdc
, MM_ANISOTROPIC
);
6439 SelectObject(hdc
, hfont
);
6441 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6442 ok(ret
, "GetCharWidth32W should have succeeded\n");
6443 ok (bufferW
> 0," Width should be greater than zero\n");
6444 SetWindowExtEx(hdc
, -1,-1,NULL
);
6445 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6446 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6447 ok(ret
, "GetCharWidth32W should have succeeded\n");
6448 ok (bufferW
> 0," Width should be greater than zero\n");
6449 SetGraphicsMode(hdc
, GM_ADVANCED
);
6450 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6451 ok(ret
, "GetCharWidth32W should have succeeded\n");
6452 ok (bufferW
> 0," Width should be greater than zero\n");
6453 SetWindowExtEx(hdc
, 1,1,NULL
);
6454 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6455 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6456 ok(ret
, "GetCharWidth32W should have succeeded\n");
6457 ok (bufferW
> 0," Width should be greater than zero\n");
6458 SetGraphicsMode(hdc
, GM_ADVANCED
);
6459 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6460 ok(ret
, "GetCharWidth32W should have succeeded\n");
6461 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
6463 ReleaseDC(hwnd
, hdc
);
6464 DestroyWindow(hwnd
);
6465 DeleteObject(hfont
);
6468 static void test_fake_bold_font(void)
6470 static const MAT2 x2_mat
= { {0,2}, {0,0}, {0,0}, {0,2} };
6483 if (!pGetCharWidth32A
|| !pGetCharABCWidthsA
) {
6484 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6488 /* Test outline font */
6489 memset(&lf
, 0, sizeof(lf
));
6490 strcpy(lf
.lfFaceName
, "Wingdings");
6491 lf
.lfCharSet
= SYMBOL_CHARSET
;
6495 for (i
= 0; i
<= 1; i
++)
6497 HFONT hfont
, hfont_old
;
6499 lf
.lfWeight
= i
? FW_BOLD
: FW_NORMAL
;
6500 hfont
= CreateFontIndirectA(&lf
);
6501 hfont_old
= SelectObject(hdc
, hfont
);
6503 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6504 ok(ret
, "got %d\n", ret
);
6505 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &data
[i
].abc
);
6506 ok(ret
, "got %d\n", ret
);
6507 data
[i
].w
= data
[i
].abc
.abcA
+ data
[i
].abc
.abcB
+ data
[i
].abc
.abcC
;
6508 r
= GetGlyphOutlineA(hdc
, 0x76, GGO_METRICS
, &data
[i
].gm
, 0, NULL
, &x2_mat
);
6509 ok(r
!= GDI_ERROR
, "got %d\n", ret
);
6511 SelectObject(hdc
, hfont_old
);
6512 DeleteObject(hfont
);
6514 ReleaseDC(NULL
, hdc
);
6516 /* compare results (outline) */
6517 ok(data
[0].tm
.tmHeight
== data
[1].tm
.tmHeight
,
6518 "expected %d, got %d\n", data
[0].tm
.tmHeight
, data
[1].tm
.tmHeight
);
6519 ok(data
[0].tm
.tmAscent
== data
[1].tm
.tmAscent
,
6520 "expected %d, got %d\n", data
[0].tm
.tmAscent
, data
[1].tm
.tmAscent
);
6521 ok(data
[0].tm
.tmDescent
== data
[1].tm
.tmDescent
,
6522 "expected %d, got %d\n", data
[0].tm
.tmDescent
, data
[1].tm
.tmDescent
);
6523 ok(data
[0].tm
.tmAveCharWidth
+ 1 == data
[1].tm
.tmAveCharWidth
,
6524 "expected %d, got %d\n", data
[0].tm
.tmAveCharWidth
+ 1, data
[1].tm
.tmAveCharWidth
);
6525 ok(data
[0].tm
.tmMaxCharWidth
+ 1 == data
[1].tm
.tmMaxCharWidth
,
6526 "expected %d, got %d\n", data
[0].tm
.tmMaxCharWidth
+ 1, data
[1].tm
.tmMaxCharWidth
);
6527 ok(data
[0].tm
.tmOverhang
== data
[1].tm
.tmOverhang
,
6528 "expected %d, got %d\n", data
[0].tm
.tmOverhang
, data
[1].tm
.tmOverhang
);
6529 ok(data
[0].w
+ 1 == data
[1].w
,
6530 "expected %d, got %d\n", data
[0].w
+ 1, data
[1].w
);
6532 ok(data
[0].gm
.gmCellIncX
+ 1 == data
[1].gm
.gmCellIncX
,
6533 "expected %d, got %d\n", data
[0].gm
.gmCellIncX
+ 1, data
[1].gm
.gmCellIncX
);
6534 ok(data
[0].gm
.gmCellIncY
== data
[1].gm
.gmCellIncY
,
6535 "expected %d, got %d\n", data
[0].gm
.gmCellIncY
, data
[1].gm
.gmCellIncY
);
6538 static void test_bitmap_font_glyph_index(void)
6540 const WCHAR text
[] = {'#','!','/','b','i','n','/','s','h',0};
6544 } bitmap_font_list
[] = {
6545 { "Courier", ANSI_CHARSET
},
6546 { "Small Fonts", ANSI_CHARSET
},
6547 { "Fixedsys", DEFAULT_CHARSET
},
6548 { "System", DEFAULT_CHARSET
}
6553 CHAR facename
[LF_FACESIZE
];
6564 if (!pGetGlyphIndicesW
|| !pGetGlyphIndicesA
) {
6565 win_skip("GetGlyphIndices is unavailable\n");
6569 hdc
= CreateCompatibleDC(0);
6570 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6572 memset(&bmi
, 0, sizeof(bmi
));
6573 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
6574 bmi
.bmiHeader
.biBitCount
= 32;
6575 bmi
.bmiHeader
.biPlanes
= 1;
6576 bmi
.bmiHeader
.biWidth
= 128;
6577 bmi
.bmiHeader
.biHeight
= 32;
6578 bmi
.bmiHeader
.biCompression
= BI_RGB
;
6580 for (i
= 0; i
< sizeof(bitmap_font_list
)/sizeof(bitmap_font_list
[0]); i
++) {
6581 memset(&lf
, 0, sizeof(lf
));
6582 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
6583 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
6584 hFont
= CreateFontIndirectA(&lf
);
6585 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
6586 hFont
= SelectObject(hdc
, hFont
);
6587 ret
= GetTextMetricsA(hdc
, &tm
);
6588 ok(ret
, "GetTextMetric failed\n");
6589 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
6590 ok(ret
, "GetTextFace failed\n");
6591 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
6592 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
6595 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
6596 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
6600 for (j
= 0; j
< 2; j
++) {
6602 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
6603 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
6604 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6607 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
6611 int len
= lstrlenW(text
);
6612 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
6613 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
6614 ok(ret
, "GetGlyphIndices failed\n");
6615 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
6616 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
6617 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
6618 HeapFree(GetProcessHeap(), 0, indices
);
6622 ok(ret
, "ExtTextOutW failed\n");
6623 SelectObject(hdc
, hBmpPrev
);
6626 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
6627 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6628 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6630 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
6632 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6635 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
6636 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
6640 for (j
= 0; j
< 2; j
++) {
6643 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6646 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6649 ret
= pGetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6650 ok(ret
, "GetGlyphIndices failed\n");
6651 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6652 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6655 ok(ret
, "ExtTextOutA failed\n");
6656 SelectObject(hdc
, hBmpPrev
);
6659 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6660 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6662 for (j
= 0; j
< 2; j
++)
6663 DeleteObject(hBmp
[j
]);
6664 hFont
= SelectObject(hdc
, hFont
);
6665 DeleteObject(hFont
);
6671 static void test_GetCharWidthI(void)
6673 static const char *teststr
= "wine ";
6674 HFONT hfont
, prev_hfont
;
6684 memset(&lf
, 0, sizeof(lf
));
6685 strcpy(lf
.lfFaceName
, "Tahoma");
6690 hfont
= CreateFontIndirectA(&lf
);
6691 prev_hfont
= SelectObject(hdc
, hfont
);
6693 len
= strlen(teststr
);
6694 nb
= GetGlyphIndicesA(hdc
, teststr
, len
, glyphs
, 0);
6695 ok(nb
== len
, "\n");
6697 memset(abc
, 0xcc, sizeof(abc
));
6698 ret
= GetCharABCWidthsI(hdc
, 0, len
, glyphs
, abc
);
6699 ok(ret
, "GetCharABCWidthsI failed\n");
6701 memset(widths
, 0xcc, sizeof(widths
));
6702 ret
= GetCharWidthI(hdc
, 0, len
, glyphs
, widths
);
6703 ok(ret
, "GetCharWidthI failed\n");
6705 for (i
= 0; i
< len
; i
++)
6706 ok(widths
[i
] == abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
, "%u, glyph %u, got width %d\n",
6707 i
, glyphs
[i
], widths
[i
]);
6709 DeleteObject(SelectObject(hdc
, prev_hfont
));
6720 test_outline_font();
6721 test_bitmap_font_metrics();
6722 test_GdiGetCharDimensions();
6723 test_GetCharABCWidths();
6724 test_text_extents();
6725 test_GetGlyphIndices();
6726 test_GetKerningPairs();
6727 test_GetOutlineTextMetrics();
6728 test_SetTextJustification();
6729 test_font_charset();
6730 test_GdiGetCodePage();
6731 test_GetFontUnicodeRanges();
6732 test_nonexistent_font();
6734 test_height_selection();
6735 test_AddFontMemResource();
6737 test_EnumFonts_subst();
6739 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6740 * I'd like to avoid them in this test.
6742 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
6743 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
6744 if (is_truetype_font_installed("Arial Black") &&
6745 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6747 test_EnumFontFamilies("", ANSI_CHARSET
);
6748 test_EnumFontFamilies("", SYMBOL_CHARSET
);
6749 test_EnumFontFamilies("", DEFAULT_CHARSET
);
6752 skip("Arial Black or Symbol/Wingdings is not installed\n");
6753 test_EnumFontFamiliesEx_default_charset();
6754 test_GetTextMetrics();
6755 test_RealizationInfo();
6757 test_GetGlyphOutline();
6758 test_GetTextMetrics2("Tahoma", -11);
6759 test_GetTextMetrics2("Tahoma", -55);
6760 test_GetTextMetrics2("Tahoma", -110);
6761 test_GetTextMetrics2("Arial", -11);
6762 test_GetTextMetrics2("Arial", -55);
6763 test_GetTextMetrics2("Arial", -110);
6764 test_GetCharacterPlacement();
6765 test_CreateFontIndirect();
6766 test_CreateFontIndirectEx();
6770 test_east_asian_font_selection();
6772 test_vertical_order();
6773 test_GetCharWidth32();
6774 test_fake_bold_font();
6775 test_bitmap_font_glyph_index();
6776 test_GetCharWidthI();
6778 /* These tests should be last test until RemoveFontResource
6779 * is properly implemented.
6781 test_vertical_font();
6782 test_CreateScalableFontResource();