2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b, exact) (abs((a) - (b)) <= ((exact) ? 0 : 1))
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
40 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
41 static BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
42 static BOOL (WINAPI
*pGetCharABCWidthsA
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
43 static BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
44 static BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
45 static BOOL (WINAPI
*pGetCharWidth32A
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
46 static BOOL (WINAPI
*pGetCharWidth32W
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
47 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
48 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
49 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
50 static BOOL (WINAPI
*pGetTextExtentExPointI
)(HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
51 LPINT nfit
, LPINT dxs
, LPSIZE size
);
52 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
53 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDVA
*);
54 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
55 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
56 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
57 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
59 static HMODULE hgdi32
= 0;
60 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
61 static WORD system_lang_id
;
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
67 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
71 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
72 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
73 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
74 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
75 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
76 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
78 static void init(void)
80 hgdi32
= GetModuleHandleA("gdi32.dll");
82 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
83 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
84 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
85 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
86 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
87 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
88 pGetCharWidth32A
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32A");
89 pGetCharWidth32W
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32W");
90 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
91 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
92 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
93 pGetTextExtentExPointI
= (void *)GetProcAddress(hgdi32
, "GetTextExtentExPointI");
94 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
95 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
96 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
97 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
98 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
99 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
101 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
104 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
106 if (type
!= TRUETYPE_FONTTYPE
) return 1;
111 static BOOL
is_truetype_font_installed(const char *name
)
116 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
123 static INT CALLBACK
is_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
128 static BOOL
is_font_installed(const char *name
)
133 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
140 static void *get_res_data(const char *fontname
, DWORD
*rsrc_size
)
145 rsrc
= FindResourceA(GetModuleHandleA(NULL
), fontname
, (LPCSTR
)RT_RCDATA
);
146 if (!rsrc
) return NULL
;
148 rsrc_data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
149 if (!rsrc_data
) return NULL
;
151 *rsrc_size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
152 if (!*rsrc_size
) return NULL
;
157 static BOOL
write_tmp_file( const void *data
, DWORD
*size
, char *tmp_name
)
159 char tmp_path
[MAX_PATH
];
163 GetTempPathA(MAX_PATH
, tmp_path
);
164 GetTempFileNameA(tmp_path
, "ttf", 0, tmp_name
);
166 hfile
= CreateFileA(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
167 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
169 ret
= WriteFile(hfile
, data
, *size
, size
, NULL
);
175 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
180 rsrc_data
= get_res_data( fontname
, &rsrc_size
);
181 if (!rsrc_data
) return FALSE
;
183 return write_tmp_file( rsrc_data
, &rsrc_size
, tmp_name
);
186 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
194 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
195 /* NT4 tries to be clever and only returns the minimum length */
196 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
198 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
199 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
200 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
201 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
202 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
203 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
204 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
205 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
206 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
207 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
208 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
209 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
210 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
211 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
212 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
213 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
214 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
215 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
216 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
217 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
218 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
219 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
220 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
221 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
222 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
223 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
224 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
225 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
228 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
230 HFONT hfont
= CreateFontIndirectA(lf
);
231 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
233 check_font(test
, lf
, hfont
);
237 static void test_logfont(void)
242 memset(&lf
, 0, sizeof lf
);
244 lf
.lfCharSet
= ANSI_CHARSET
;
245 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
246 lf
.lfWeight
= FW_DONTCARE
;
249 lf
.lfQuality
= DEFAULT_QUALITY
;
251 lstrcpyA(lf
.lfFaceName
, "Arial");
252 hfont
= create_font("Arial", &lf
);
255 memset(&lf
, 'A', sizeof(lf
));
256 hfont
= CreateFontIndirectA(&lf
);
257 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
259 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
260 check_font("AAA...", &lf
, hfont
);
264 static INT CALLBACK
font_enum_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
266 if (type
& RASTER_FONTTYPE
)
268 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
270 return 0; /* stop enumeration */
273 return 1; /* continue enumeration */
276 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
278 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
279 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
280 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
281 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
282 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
283 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
284 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
285 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
286 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
287 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
288 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
289 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
290 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
291 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
292 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
293 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
294 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
295 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
296 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
297 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
300 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
301 LONG lfWidth
, const char *test_str
,
302 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
303 const SIZE
*size_orig
, INT width_of_A_orig
,
304 INT scale_x
, INT scale_y
)
307 OUTLINETEXTMETRICA otm
;
310 INT width_of_A
, cx
, cy
;
316 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
318 GetObjectA(hfont
, sizeof(lf
), &lf
);
320 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
322 otm
.otmSize
= sizeof(otm
) / 2;
323 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
324 ok(ret
== sizeof(otm
)/2 /* XP */ ||
325 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
327 memset(&otm
, 0x1, sizeof(otm
));
328 otm
.otmSize
= sizeof(otm
);
329 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
330 ok(ret
== sizeof(otm
) /* XP */ ||
331 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
333 memset(&tm
, 0x2, sizeof(tm
));
334 ret
= GetTextMetricsA(hdc
, &tm
);
335 ok(ret
, "GetTextMetricsA failed\n");
336 /* the structure size is aligned */
337 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
339 ok(0, "tm != otm\n");
340 compare_tm(&tm
, &otm
.otmTextMetrics
);
343 tm
= otm
.otmTextMetrics
;
344 if (0) /* these metrics are scaled too, but with rounding errors */
346 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
347 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
349 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
350 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
351 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
352 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
353 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
354 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
358 ret
= GetTextMetricsA(hdc
, &tm
);
359 ok(ret
, "GetTextMetricsA failed\n");
362 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
363 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
364 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
365 lfHeight
, scale_x
, scale_y
, cx
, cy
);
366 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
367 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
368 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
369 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
370 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
372 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
376 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
379 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
381 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
383 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
384 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
386 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
388 ok(near_match(width_of_A
, width_of_A_orig
* scale_x
), "width A %d != %d\n", width_of_A
, width_of_A_orig
* scale_x
);
391 /* Test how GDI scales bitmap font metrics */
392 static void test_bitmap_font(void)
394 static const char test_str
[11] = "Test String";
397 HFONT hfont
, old_hfont
;
400 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
402 hdc
= CreateCompatibleDC(0);
404 /* "System" has only 1 pixel size defined, otherwise the test breaks */
405 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
409 trace("no bitmap fonts were found, skipping the test\n");
413 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
415 height_orig
= bitmap_lf
.lfHeight
;
416 lfWidth
= bitmap_lf
.lfWidth
;
418 hfont
= create_font("bitmap", &bitmap_lf
);
419 old_hfont
= SelectObject(hdc
, hfont
);
420 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
421 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
422 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
423 SelectObject(hdc
, old_hfont
);
426 bitmap_lf
.lfHeight
= 0;
427 bitmap_lf
.lfWidth
= 4;
428 hfont
= create_font("bitmap", &bitmap_lf
);
429 old_hfont
= SelectObject(hdc
, hfont
);
430 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
431 SelectObject(hdc
, old_hfont
);
434 bitmap_lf
.lfHeight
= height_orig
;
435 bitmap_lf
.lfWidth
= lfWidth
;
437 /* test fractional scaling */
438 for (i
= 1; i
<= height_orig
* 6; i
++)
442 bitmap_lf
.lfHeight
= i
;
443 hfont
= create_font("fractional", &bitmap_lf
);
444 scale
= (i
+ height_orig
- 1) / height_orig
;
445 nearest_height
= scale
* height_orig
;
446 /* Only jump to the next height if the difference <= 25% original height */
447 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
448 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
449 so we'll not test this particular height. */
450 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
451 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
452 old_hfont
= SelectObject(hdc
, hfont
);
453 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
454 SelectObject(hdc
, old_hfont
);
458 /* test integer scaling 3x2 */
459 bitmap_lf
.lfHeight
= height_orig
* 2;
460 bitmap_lf
.lfWidth
*= 3;
461 hfont
= create_font("3x2", &bitmap_lf
);
462 old_hfont
= SelectObject(hdc
, hfont
);
463 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
464 SelectObject(hdc
, old_hfont
);
467 /* test integer scaling 3x3 */
468 bitmap_lf
.lfHeight
= height_orig
* 3;
469 bitmap_lf
.lfWidth
= 0;
470 hfont
= create_font("3x3", &bitmap_lf
);
471 old_hfont
= SelectObject(hdc
, hfont
);
472 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
473 SelectObject(hdc
, old_hfont
);
479 /* Test how GDI scales outline font metrics */
480 static void test_outline_font(void)
482 static const char test_str
[11] = "Test String";
485 HFONT hfont
, old_hfont
, old_hfont_2
;
486 OUTLINETEXTMETRICA otm
;
488 INT width_orig
, height_orig
, lfWidth
;
491 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
495 if (!is_truetype_font_installed("Arial"))
497 skip("Arial is not installed\n");
501 hdc
= CreateCompatibleDC(0);
503 memset(&lf
, 0, sizeof(lf
));
504 strcpy(lf
.lfFaceName
, "Arial");
506 hfont
= create_font("outline", &lf
);
507 old_hfont
= SelectObject(hdc
, hfont
);
508 otm
.otmSize
= sizeof(otm
);
509 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
510 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
511 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
513 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
514 SelectObject(hdc
, old_hfont
);
517 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
518 lf
.lfHeight
= otm
.otmEMSquare
;
519 lf
.lfHeight
= -lf
.lfHeight
;
520 hfont
= create_font("outline", &lf
);
521 old_hfont
= SelectObject(hdc
, hfont
);
522 otm
.otmSize
= sizeof(otm
);
523 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
524 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
525 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
526 SelectObject(hdc
, old_hfont
);
529 height_orig
= otm
.otmTextMetrics
.tmHeight
;
530 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
532 /* test integer scaling 3x2 */
533 lf
.lfHeight
= height_orig
* 2;
534 lf
.lfWidth
= lfWidth
* 3;
535 hfont
= create_font("3x2", &lf
);
536 old_hfont
= SelectObject(hdc
, hfont
);
537 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
538 SelectObject(hdc
, old_hfont
);
541 /* test integer scaling 3x3 */
542 lf
.lfHeight
= height_orig
* 3;
543 lf
.lfWidth
= lfWidth
* 3;
544 hfont
= create_font("3x3", &lf
);
545 old_hfont
= SelectObject(hdc
, hfont
);
546 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
547 SelectObject(hdc
, old_hfont
);
550 /* test integer scaling 1x1 */
551 lf
.lfHeight
= height_orig
* 1;
552 lf
.lfWidth
= lfWidth
* 1;
553 hfont
= create_font("1x1", &lf
);
554 old_hfont
= SelectObject(hdc
, hfont
);
555 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
556 SelectObject(hdc
, old_hfont
);
559 /* test integer scaling 1x1 */
560 lf
.lfHeight
= height_orig
;
562 hfont
= create_font("1x1", &lf
);
563 old_hfont
= SelectObject(hdc
, hfont
);
564 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
566 /* with an identity matrix */
567 memset(&gm
, 0, sizeof(gm
));
568 SetLastError(0xdeadbeef);
569 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
570 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
571 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
572 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
573 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
574 /* with a custom matrix */
575 memset(&gm
, 0, sizeof(gm
));
576 SetLastError(0xdeadbeef);
577 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
578 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
580 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
581 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
587 hdc_2
= CreateCompatibleDC(0);
588 old_hfont_2
= SelectObject(hdc_2
, hfont
);
589 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
591 SetMapMode(hdc
, MM_ANISOTROPIC
);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc
, 100, 100, NULL
);
601 SetViewportExtEx(hdc
, 50, 100, NULL
);
602 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc
, 100, 200, NULL
);
611 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc
, MM_TEXT
);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
621 SelectObject(hdc_2
, old_hfont_2
);
624 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
626 SelectObject(hdc
, old_hfont
);
629 skip("GM_ADVANCED is not supported on this platform\n");
640 SetLastError(0xdeadbeef);
641 ret
= SetWorldTransform(hdc
, &xform
);
642 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
646 /* with an identity matrix */
647 memset(&gm
, 0, sizeof(gm
));
648 SetLastError(0xdeadbeef);
649 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
650 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
651 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
652 pt
.x
= width_orig
; pt
.y
= 0;
654 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
655 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
656 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
657 /* with a custom matrix */
658 memset(&gm
, 0, sizeof(gm
));
659 SetLastError(0xdeadbeef);
660 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
661 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
662 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
663 pt
.x
= width_orig
; pt
.y
= 0;
665 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
666 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
667 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
669 SetLastError(0xdeadbeef);
670 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
671 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
673 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
675 /* with an identity matrix */
676 memset(&gm
, 0, sizeof(gm
));
677 SetLastError(0xdeadbeef);
678 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
679 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
680 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
681 pt
.x
= width_orig
; pt
.y
= 0;
683 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
684 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
685 /* with a custom matrix */
686 memset(&gm
, 0, sizeof(gm
));
687 SetLastError(0xdeadbeef);
688 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
689 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
690 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
691 pt
.x
= width_orig
; pt
.y
= 0;
693 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
694 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
696 SetLastError(0xdeadbeef);
697 ret
= SetMapMode(hdc
, MM_TEXT
);
698 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
700 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
702 /* with an identity matrix */
703 memset(&gm
, 0, sizeof(gm
));
704 SetLastError(0xdeadbeef);
705 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
706 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
708 pt
.x
= width_orig
; pt
.y
= 0;
710 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
711 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
712 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
713 /* with a custom matrix */
714 memset(&gm
, 0, sizeof(gm
));
715 SetLastError(0xdeadbeef);
716 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
717 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
718 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
719 pt
.x
= width_orig
; pt
.y
= 0;
721 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
722 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
723 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
725 SelectObject(hdc
, old_hfont
);
730 static INT CALLBACK
find_font_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
732 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
734 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL
is_CJK(void)
744 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const struct font_data
752 const char face_name
[LF_FACESIZE
];
753 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
754 int ave_char_width
, max_char_width
, dpi
;
755 BYTE first_char
, last_char
, def_char
, break_char
;
761 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
762 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
763 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
764 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
765 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
766 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
767 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
768 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
769 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 16 },
770 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
772 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
773 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
774 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
775 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
776 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
777 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
778 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
779 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
780 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
781 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
783 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
784 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
785 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
786 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
787 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
788 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
789 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
790 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
791 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
792 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
793 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
794 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
795 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
796 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
797 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
798 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
800 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
801 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
802 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
803 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
804 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
805 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
806 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
807 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
808 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
809 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
810 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
811 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
813 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
814 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
815 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
816 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
817 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
818 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
819 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
820 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
821 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
822 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
823 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
824 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
825 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
826 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
827 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
828 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
829 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
831 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
832 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
833 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
834 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
835 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
836 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
837 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
838 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
839 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
840 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
841 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
843 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
844 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
845 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
847 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
848 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
849 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
851 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
852 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
853 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
855 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
856 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
858 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
859 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
860 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
861 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
862 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
863 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
864 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
865 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
866 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
867 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
868 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
869 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
870 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
871 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
872 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
873 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
874 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
875 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
876 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
877 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
878 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
880 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
881 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
882 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
883 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
884 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
885 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
886 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
887 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
888 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
889 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
890 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
891 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
893 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
894 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
895 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
897 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
899 /* FIXME: add "Terminal" */
901 static const int font_log_pixels
[] = { 96, 120 };
904 HFONT hfont
, old_hfont
;
906 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
907 char face_name
[LF_FACESIZE
];
910 trace("system language id %04x\n", system_lang_id
);
912 expected_cs
= GetACP();
913 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
915 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
918 expected_cs
= csi
.ciCharset
;
919 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
921 hdc
= CreateCompatibleDC(0);
924 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
925 GetDeviceCaps(hdc
, LOGPIXELSY
));
927 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
930 for (i
= 0; i
< sizeof(font_log_pixels
)/sizeof(font_log_pixels
[0]); i
++)
932 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
936 font_res
= font_log_pixels
[i
];
939 trace("best font resolution is %d\n", font_res
);
941 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
945 memset(&lf
, 0, sizeof(lf
));
947 height
= fd
[i
].height
& ~FH_SCALE
;
948 lf
.lfHeight
= height
;
949 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
951 for(bit
= 0; bit
< 32; bit
++)
959 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
960 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
962 lf
.lfCharSet
= csi
.ciCharset
;
963 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
964 if (fd
[i
].height
& FH_SCALE
)
965 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
968 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
970 if (ret
) /* FIXME: Remove once Wine is fixed */
971 todo_wine
ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
973 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
976 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
979 hfont
= create_font(lf
.lfFaceName
, &lf
);
980 old_hfont
= SelectObject(hdc
, hfont
);
982 SetLastError(0xdeadbeef);
983 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
984 ok(ret
, "GetTextFace error %u\n", GetLastError());
986 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
988 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
989 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
990 SelectObject(hdc
, old_hfont
);
995 memset(&gm
, 0, sizeof(gm
));
996 SetLastError(0xdeadbeef);
997 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
999 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
1000 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1003 bRet
= GetTextMetricsA(hdc
, &tm
);
1004 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
1006 SetLastError(0xdeadbeef);
1007 ret
= GetTextCharset(hdc
);
1008 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1009 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1011 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1013 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
1014 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
1016 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1018 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1019 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
1021 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1022 if (fd
[i
].height
& FH_SCALE
)
1023 ok(tm
.tmHeight
== fd
[i
].scaled_height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmHeight
, fd
[i
].scaled_height
);
1025 ok(tm
.tmHeight
== fd
[i
].height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmHeight
, fd
[i
].height
);
1026 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1027 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1028 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1029 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1030 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
1031 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1032 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1033 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1034 make default char test fail */
1035 if (tm
.tmCharSet
== lf
.lfCharSet
)
1036 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1037 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1038 ok(tm
.tmCharSet
== expected_cs
|| tm
.tmCharSet
== ANSI_CHARSET
, "%s(%d): tm.tmCharSet %d != %d\n", fd
[i
].face_name
, height
, tm
.tmCharSet
, expected_cs
);
1040 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1041 that make the max width bigger */
1042 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1043 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
1046 skip("Skipping font metrics test for system langid 0x%x\n",
1049 SelectObject(hdc
, old_hfont
);
1050 DeleteObject(hfont
);
1057 static void test_GdiGetCharDimensions(void)
1063 LONG avgwidth
, height
;
1064 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1066 if (!pGdiGetCharDimensions
)
1068 win_skip("GdiGetCharDimensions not available on this platform\n");
1072 hdc
= CreateCompatibleDC(NULL
);
1074 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1075 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1077 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1078 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1079 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1081 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1082 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1084 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1085 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1088 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1089 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1090 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1095 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1096 const TEXTMETRICA
*lpntme
,
1097 DWORD FontType
, LPARAM lParam
)
1099 if (FontType
& TRUETYPE_FONTTYPE
)
1103 hfont
= CreateFontIndirectA(lpelfe
);
1106 *(HFONT
*)lParam
= hfont
;
1114 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, ABC
*base_abci
, ABC
*base_abcw
, ABCFLOAT
*base_abcf
, INT todo
)
1120 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1121 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1122 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1123 if (todo
) todo_wine
ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1124 else ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1125 if (todo
) todo_wine
ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1126 else ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1128 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1129 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1130 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1131 if (todo
) todo_wine
ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1132 else ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1133 if (todo
) todo_wine
ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1134 else ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's should be unchanged\n", description
);
1136 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1137 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1138 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1139 if (todo
) todo_wine
ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1140 else ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's should be unchanged\n", description
);
1141 if (todo
) todo_wine
ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1142 else ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1145 static void test_GetCharABCWidths(void)
1147 static const WCHAR str
[] = {'i',0};
1171 {0xffffff, 0xffffff},
1172 {0x1000000, 0x1000000},
1173 {0xffffff, 0x1000000},
1174 {0xffffffff, 0xffffffff},
1182 BOOL r
[sizeof range
/ sizeof range
[0]];
1185 {ANSI_CHARSET
, 0x30, 0x30,
1186 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1187 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1188 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1189 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1190 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1191 {GB2312_CHARSET
, 0x8141, 0x4e04,
1192 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1193 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1194 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1198 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1200 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1204 memset(&lf
, 0, sizeof(lf
));
1205 strcpy(lf
.lfFaceName
, "System");
1208 hfont
= CreateFontIndirectA(&lf
);
1210 hfont
= SelectObject(hdc
, hfont
);
1212 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1213 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1215 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1216 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1218 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1219 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1221 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1222 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1224 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1225 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1227 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1228 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1230 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1231 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1233 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1234 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1236 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1237 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1239 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1240 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1242 hfont
= SelectObject(hdc
, hfont
);
1243 DeleteObject(hfont
);
1245 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1249 UINT code
= 0x41, j
;
1251 lf
.lfFaceName
[0] = '\0';
1252 lf
.lfCharSet
= c
[i
].cs
;
1253 lf
.lfPitchAndFamily
= 0;
1254 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1256 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1260 memset(a
, 0, sizeof a
);
1261 memset(w
, 0, sizeof w
);
1262 hfont
= SelectObject(hdc
, hfont
);
1263 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1264 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1265 memcmp(a
, w
, sizeof a
) == 0,
1266 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1268 memset(a
, 0xbb, sizeof a
);
1269 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1270 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1271 memset(full
, 0xcc, sizeof full
);
1272 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1273 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1274 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1275 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1277 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1279 memset(full
, 0xdd, sizeof full
);
1280 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1281 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1282 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1285 UINT last
= range
[j
].last
- range
[j
].first
;
1286 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1287 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1288 "GetCharABCWidthsA %x should match. codepage = %u\n",
1289 range
[j
].last
, c
[i
].cs
);
1293 hfont
= SelectObject(hdc
, hfont
);
1294 DeleteObject(hfont
);
1297 memset(&lf
, 0, sizeof(lf
));
1298 strcpy(lf
.lfFaceName
, "Tahoma");
1300 hfont
= CreateFontIndirectA(&lf
);
1302 /* test empty glyph's metrics */
1303 hfont
= SelectObject(hdc
, hfont
);
1304 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1305 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1306 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1307 ret
= pGetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1308 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1309 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1311 /* 1) prepare unrotated font metrics */
1312 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1313 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1314 DeleteObject(SelectObject(hdc
, hfont
));
1316 /* 2) get rotated font metrics */
1317 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1318 hfont
= CreateFontIndirectA(&lf
);
1319 hfont
= SelectObject(hdc
, hfont
);
1320 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1321 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1323 /* 3) compare ABC results */
1324 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1325 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1326 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1327 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1328 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1329 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1331 DeleteObject(SelectObject(hdc
, hfont
));
1332 ReleaseDC(NULL
, hdc
);
1334 trace("ABC sign test for a variety of transforms:\n");
1335 memset(&lf
, 0, sizeof(lf
));
1336 strcpy(lf
.lfFaceName
, "Tahoma");
1338 hfont
= CreateFontIndirectA(&lf
);
1339 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1342 SetMapMode(hdc
, MM_ANISOTROPIC
);
1343 SelectObject(hdc
, hfont
);
1345 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1346 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1348 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1349 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1350 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1351 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1352 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1353 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1355 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1356 SetWindowExtEx(hdc
, -1, -1, NULL
);
1357 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1358 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1359 SetGraphicsMode(hdc
, GM_ADVANCED
);
1360 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1361 SetWindowExtEx(hdc
, 1, 1, NULL
);
1362 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1363 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1364 SetGraphicsMode(hdc
, GM_ADVANCED
);
1365 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1367 ReleaseDC(hwnd
, hdc
);
1368 DestroyWindow(hwnd
);
1370 trace("RTL layout\n");
1371 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1374 SetMapMode(hdc
, MM_ANISOTROPIC
);
1375 SelectObject(hdc
, hfont
);
1377 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1378 SetWindowExtEx(hdc
, -1, -1, NULL
);
1379 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1380 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1381 SetGraphicsMode(hdc
, GM_ADVANCED
);
1382 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1383 SetWindowExtEx(hdc
, 1, 1, NULL
);
1384 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1385 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1386 SetGraphicsMode(hdc
, GM_ADVANCED
);
1387 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1389 ReleaseDC(hwnd
, hdc
);
1390 DestroyWindow(hwnd
);
1391 DeleteObject(hfont
);
1394 static void test_text_extents(void)
1396 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1398 INT i
, len
, fit1
, fit2
, extents2
[3];
1407 memset(&lf
, 0, sizeof(lf
));
1408 strcpy(lf
.lfFaceName
, "Arial");
1411 hfont
= CreateFontIndirectA(&lf
);
1413 hfont
= SelectObject(hdc
, hfont
);
1414 GetTextMetricsA(hdc
, &tm
);
1415 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1416 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1418 SetLastError(0xdeadbeef);
1419 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1420 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1422 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1423 hfont
= SelectObject(hdc
, hfont
);
1424 DeleteObject(hfont
);
1430 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1431 extents
[0] = 1; /* So that the increasing sequence test will fail
1432 if the extents array is untouched. */
1433 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1434 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1435 ok(sz1
.cy
== sz2
.cy
,
1436 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1437 /* Because of the '\n' in the string GetTextExtentExPoint and
1438 GetTextExtentPoint return different widths under Win2k, but
1439 under WinXP they return the same width. So we don't test that
1442 for (i
= 1; i
< len
; ++i
)
1443 ok(extents
[i
-1] <= extents
[i
],
1444 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1446 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1447 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1448 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1449 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1450 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1451 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1452 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1453 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1455 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1456 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1457 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1458 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1459 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1461 /* extents functions fail with -ve counts (the interesting case being -1) */
1462 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1463 ok(ret
== FALSE
, "got %d\n", ret
);
1464 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1465 ok(ret
== FALSE
, "got %d\n", ret
);
1466 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1467 ok(ret
== FALSE
, "got %d\n", ret
);
1469 /* max_extent = 0 succeeds and returns zero */
1471 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1473 broken(ret
== FALSE
), /* NT4, 2k */
1476 broken(fit1
== -215), /* NT4, 2k */
1477 "fit = %d\n", fit1
);
1478 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1479 ok(ret
== TRUE
, "got %d\n", ret
);
1480 ok(fit2
== 0, "fit = %d\n", fit2
);
1482 /* max_extent = -1 is interpreted as a very large width that will
1483 * definitely fit our three characters */
1485 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1486 ok(ret
== TRUE
, "got %d\n", ret
);
1487 ok(fit1
== 3, "fit = %d\n", fit1
);
1488 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1489 ok(ret
== TRUE
, "got %d\n", ret
);
1490 ok(fit2
== 3, "fit = %d\n", fit2
);
1492 /* max_extent = -2 is interpreted similarly, but the Ansi version
1493 * rejects it while the Unicode one accepts it */
1495 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1496 ok(ret
== FALSE
, "got %d\n", ret
);
1497 ok(fit1
== -215, "fit = %d\n", fit1
);
1498 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1499 ok(ret
== TRUE
, "got %d\n", ret
);
1500 ok(fit2
== 3, "fit = %d\n", fit2
);
1502 hfont
= SelectObject(hdc
, hfont
);
1503 DeleteObject(hfont
);
1505 /* non-MM_TEXT mapping mode */
1507 hfont
= CreateFontIndirectA(&lf
);
1508 hfont
= SelectObject(hdc
, hfont
);
1510 SetMapMode( hdc
, MM_HIMETRIC
);
1511 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1512 ok(ret
, "got %d\n", ret
);
1513 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1515 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1516 ok(ret
, "got %d\n", ret
);
1517 ok(fit1
== 2, "got %d\n", fit1
);
1518 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1519 for(i
= 0; i
< 2; i
++)
1520 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1522 hfont
= SelectObject(hdc
, hfont
);
1523 DeleteObject(hfont
);
1524 HeapFree(GetProcessHeap(), 0, extents
);
1525 ReleaseDC(NULL
, hdc
);
1528 static void test_GetGlyphIndices(void)
1535 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1536 WORD glyphs
[(sizeof(testtext
)/2)-1];
1540 if (!pGetGlyphIndicesW
) {
1541 win_skip("GetGlyphIndicesW not available on platform\n");
1547 memset(&lf
, 0, sizeof(lf
));
1548 strcpy(lf
.lfFaceName
, "System");
1550 lf
.lfCharSet
= ANSI_CHARSET
;
1552 hfont
= CreateFontIndirectA(&lf
);
1553 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1554 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1555 if (textm
.tmCharSet
== ANSI_CHARSET
)
1557 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1558 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1559 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1560 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1562 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1563 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1564 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1565 textm
.tmDefaultChar
, glyphs
[4]);
1568 /* FIXME: Write tests for non-ANSI charsets. */
1569 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1571 if(!is_font_installed("Tahoma"))
1573 skip("Tahoma is not installed so skipping this test\n");
1576 memset(&lf
, 0, sizeof(lf
));
1577 strcpy(lf
.lfFaceName
, "Tahoma");
1580 hfont
= CreateFontIndirectA(&lf
);
1581 hOldFont
= SelectObject(hdc
, hfont
);
1582 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1583 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1584 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1585 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1586 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1588 testtext
[0] = textm
.tmDefaultChar
;
1589 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1590 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1591 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1592 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1593 DeleteObject(SelectObject(hdc
, hOldFont
));
1596 static void test_GetKerningPairs(void)
1598 static const struct kerning_data
1600 const char face_name
[LF_FACESIZE
];
1602 /* some interesting fields from OUTLINETEXTMETRIC */
1603 LONG tmHeight
, tmAscent
, tmDescent
;
1608 UINT otmsCapEmHeight
;
1613 UINT otmusMinimumPPEM
;
1614 /* small subset of kerning pairs to test */
1615 DWORD total_kern_pairs
;
1616 const KERNINGPAIR kern_pair
[26];
1619 {"Arial", 12, 12, 9, 3,
1620 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1623 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1624 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1625 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1626 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1627 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1628 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1629 {933,970,+1},{933,972,-1}
1632 {"Arial", -34, 39, 32, 7,
1633 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1636 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1637 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1638 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1639 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1640 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1641 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1642 {933,970,+2},{933,972,-3}
1645 { "Arial", 120, 120, 97, 23,
1646 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1649 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1650 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1651 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1652 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1653 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1654 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1655 {933,970,+6},{933,972,-10}
1658 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1659 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1660 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1663 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1664 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1665 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1666 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1667 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1668 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1669 {933,970,+54},{933,972,-83}
1675 HFONT hfont
, hfont_old
;
1676 KERNINGPAIR
*kern_pair
;
1678 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1682 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1683 * which may render this test unusable, so we're trying to avoid that.
1685 SetLastError(0xdeadbeef);
1686 GetKerningPairsW(hdc
, 0, NULL
);
1687 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1689 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1694 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1696 OUTLINETEXTMETRICW otm
;
1699 if (!is_font_installed(kd
[i
].face_name
))
1701 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1705 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1707 memset(&lf
, 0, sizeof(lf
));
1708 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1709 lf
.lfHeight
= kd
[i
].height
;
1710 hfont
= CreateFontIndirectA(&lf
);
1713 hfont_old
= SelectObject(hdc
, hfont
);
1715 SetLastError(0xdeadbeef);
1716 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1717 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1718 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1720 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1721 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1722 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1723 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1724 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1725 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1727 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1728 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1729 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1730 kd
[i
].otmAscent
, otm
.otmAscent
);
1731 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1732 kd
[i
].otmDescent
, otm
.otmDescent
);
1733 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1734 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1735 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1736 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1737 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1738 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1740 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1741 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1742 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1743 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1744 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1745 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1746 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1747 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1748 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1751 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1752 trace("total_kern_pairs %u\n", total_kern_pairs
);
1753 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1755 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1758 SetLastError(0xdeadbeef);
1759 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1760 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1761 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1762 ok(ret
== 0, "got %u, expected 0\n", ret
);
1764 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1765 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1767 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1768 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1770 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1771 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1775 for (n
= 0; n
< ret
; n
++)
1778 /* Disabled to limit console spam */
1779 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1780 trace("{'%c','%c',%d},\n",
1781 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1782 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1784 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1785 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1787 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1788 "pair %d:%d got %d, expected %d\n",
1789 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1790 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1796 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1797 matches
, kd
[i
].total_kern_pairs
);
1799 HeapFree(GetProcessHeap(), 0, kern_pair
);
1801 SelectObject(hdc
, hfont_old
);
1802 DeleteObject(hfont
);
1810 const char face_name
[LF_FACESIZE
];
1811 int requested_height
;
1812 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1816 static void test_height( HDC hdc
, const struct font_data
*fd
)
1819 HFONT hfont
, old_hfont
;
1823 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1825 if (!is_truetype_font_installed(fd
[i
].face_name
))
1827 skip("%s is not installed\n", fd
[i
].face_name
);
1831 memset(&lf
, 0, sizeof(lf
));
1832 lf
.lfHeight
= fd
[i
].requested_height
;
1833 lf
.lfWeight
= fd
[i
].weight
;
1834 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1836 hfont
= CreateFontIndirectA(&lf
);
1839 old_hfont
= SelectObject(hdc
, hfont
);
1840 ret
= GetTextMetricsA(hdc
, &tm
);
1841 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1842 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1844 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmWeight
, fd
[i
].weight
);
1845 ok(match_off_by_1(tm
.tmHeight
, fd
[i
].height
, fd
[i
].exact
), "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmHeight
, fd
[i
].height
);
1846 ok(match_off_by_1(tm
.tmAscent
, fd
[i
].ascent
, fd
[i
].exact
), "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmAscent
, fd
[i
].ascent
);
1847 ok(match_off_by_1(tm
.tmDescent
, fd
[i
].descent
, fd
[i
].exact
), "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmDescent
, fd
[i
].descent
);
1848 ok(match_off_by_1(tm
.tmInternalLeading
, fd
[i
].int_leading
, fd
[i
].exact
), "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1849 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1852 SelectObject(hdc
, old_hfont
);
1853 /* force GDI to use new font, otherwise Windows leaks the font reference */
1854 GetTextMetricsA(hdc
, &tm
);
1855 DeleteObject(hfont
);
1859 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1861 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1862 DWORD
*table
= (DWORD
*)ttf
+ 3;
1864 for (i
= 0; i
< num_tables
; i
++)
1866 if (table
[0] == tag
)
1867 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
1873 static void test_height_selection_vdmx( HDC hdc
)
1875 static const struct font_data charset_0
[] = /* doesn't use VDMX */
1877 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1878 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1879 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1880 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1881 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1882 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
1883 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1884 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1885 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1886 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1887 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
1888 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1889 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1890 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1891 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1892 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1893 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
1894 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1895 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1896 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1897 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1898 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1899 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
1900 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
1901 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
1902 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
1903 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1904 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1905 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1906 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1907 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1908 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1909 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1910 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1911 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1912 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1913 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1914 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1915 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1916 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1917 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1918 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1919 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1920 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
1921 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
1922 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
1923 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
1924 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
1925 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
1926 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
1927 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
1928 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
1929 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1932 static const struct font_data charset_1
[] = /* Uses VDMX */
1934 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1935 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1936 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1937 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1938 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1939 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1940 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1941 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1942 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1943 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1944 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1945 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1946 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1947 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1948 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1949 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1950 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1951 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1952 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1953 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1954 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1955 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1956 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1957 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
1958 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
1959 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
1960 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1961 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1962 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1963 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1964 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1965 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1966 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1967 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1968 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1969 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1970 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1971 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1972 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1973 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1974 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1975 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
1976 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
1977 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
1978 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
1979 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
1980 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
1981 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
1982 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
1983 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
1984 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
1985 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
1986 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1989 static const struct vdmx_data
1993 const struct font_data
*fd
;
1996 { 0, 0, charset_0
},
1997 { 0, 1, charset_1
},
1998 { 1, 0, charset_0
},
2005 char ttf_name
[MAX_PATH
];
2009 if (!pAddFontResourceExA
)
2011 win_skip("AddFontResourceExA unavailable\n");
2015 for (i
= 0; i
< sizeof(data
) / sizeof(data
[0]); i
++)
2017 res
= get_res_data( "wine_vdmx.ttf", &size
);
2019 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2020 memcpy( copy
, res
, size
);
2021 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2022 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2023 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2024 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2025 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2026 ratio_rec
[0] = data
[i
].bCharSet
;
2028 write_tmp_file( copy
, &size
, ttf_name
);
2029 HeapFree( GetProcessHeap(), 0, copy
);
2031 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2032 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2033 if (!num
) win_skip("Unable to add ttf font resource\n");
2036 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2037 test_height( hdc
, data
[i
].fd
);
2038 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2040 ret
= DeleteFileA( ttf_name
);
2041 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
),
2042 "DeleteFile error %d\n", GetLastError());
2046 static void test_height_selection(void)
2048 static const struct font_data tahoma
[] =
2050 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2051 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2052 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2053 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2054 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2055 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2056 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2057 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2058 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2059 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2060 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2062 HDC hdc
= CreateCompatibleDC(0);
2065 test_height( hdc
, tahoma
);
2066 test_height_selection_vdmx( hdc
);
2071 static void test_GetOutlineTextMetrics(void)
2073 OUTLINETEXTMETRICA
*otm
;
2075 HFONT hfont
, hfont_old
;
2077 DWORD ret
, otm_size
;
2080 if (!is_font_installed("Arial"))
2082 skip("Arial is not installed\n");
2088 memset(&lf
, 0, sizeof(lf
));
2089 strcpy(lf
.lfFaceName
, "Arial");
2091 lf
.lfWeight
= FW_NORMAL
;
2092 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2093 lf
.lfQuality
= PROOF_QUALITY
;
2094 hfont
= CreateFontIndirectA(&lf
);
2097 hfont_old
= SelectObject(hdc
, hfont
);
2098 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2099 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
2101 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2103 memset(otm
, 0xAA, otm_size
);
2104 SetLastError(0xdeadbeef);
2105 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2106 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2107 ok(ret
== 1 /* Win9x */ ||
2108 ret
== otm
->otmSize
/* XP*/,
2109 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2110 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2112 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2113 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2114 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2115 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2118 memset(otm
, 0xAA, otm_size
);
2119 SetLastError(0xdeadbeef);
2120 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2121 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2122 ok(ret
== 1 /* Win9x */ ||
2123 ret
== otm
->otmSize
/* XP*/,
2124 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2125 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2127 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2128 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2129 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2130 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2133 /* ask about truncated data */
2134 memset(otm
, 0xAA, otm_size
);
2135 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2136 SetLastError(0xdeadbeef);
2137 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2138 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2139 ok(ret
== 1 /* Win9x */ ||
2140 ret
== otm
->otmSize
/* XP*/,
2141 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2142 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2144 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2145 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2146 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2148 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2150 HeapFree(GetProcessHeap(), 0, otm
);
2152 SelectObject(hdc
, hfont_old
);
2153 DeleteObject(hfont
);
2158 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2162 areaWidth
= clientArea
->right
- clientArea
->left
,
2164 const char *pFirstChar
, *pLastChar
;
2171 int GetTextExtentExPointWWidth
;
2174 GetTextMetricsA(hdc
, &tm
);
2175 y
= clientArea
->top
;
2178 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2184 /* if not at the end of the string, ... */
2185 if (*str
== '\0') break;
2186 /* ... add the next word to the current extent */
2187 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2189 SetTextJustification(hdc
, 0, 0);
2190 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2191 } while ((int) size
.cx
< areaWidth
);
2193 /* ignore trailing break chars */
2195 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2201 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2203 SetTextJustification(hdc
, 0, 0);
2204 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2206 /* do not justify the last extent */
2207 if (*str
!= '\0' && breakCount
> 0)
2209 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2210 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2211 if (size
.cx
!= areaWidth
&& nErrors
< sizeof(error
)/sizeof(error
[0]) - 1)
2213 error
[nErrors
].start
= pFirstChar
;
2214 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2215 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2222 } while (*str
&& y
< clientArea
->bottom
);
2224 for (e
= 0; e
< nErrors
; e
++)
2226 /* The width returned by GetTextExtentPoint32() is exactly the same
2227 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2228 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2229 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2230 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2234 static void test_SetTextJustification(void)
2244 static const char testText
[] =
2245 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2246 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2247 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2248 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2249 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2250 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2251 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2253 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2254 GetClientRect( hwnd
, &clientArea
);
2255 hdc
= GetDC( hwnd
);
2257 if (!is_font_installed("Times New Roman"))
2259 skip("Times New Roman is not installed\n");
2263 memset(&lf
, 0, sizeof lf
);
2264 lf
.lfCharSet
= ANSI_CHARSET
;
2265 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2266 lf
.lfWeight
= FW_DONTCARE
;
2268 lf
.lfQuality
= DEFAULT_QUALITY
;
2269 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2270 hfont
= create_font("Times New Roman", &lf
);
2271 SelectObject(hdc
, hfont
);
2273 testJustification(hdc
, testText
, &clientArea
);
2275 if (!pGetGlyphIndicesA
|| !pGetTextExtentExPointI
) goto done
;
2276 pGetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2278 SetTextJustification(hdc
, 0, 0);
2279 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2280 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2281 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2282 SetTextJustification(hdc
, 4, 1);
2283 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2284 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2285 SetTextJustification(hdc
, 9, 2);
2286 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2287 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2288 SetTextJustification(hdc
, 7, 3);
2289 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2290 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2291 SetTextJustification(hdc
, 7, 3);
2292 SetTextCharacterExtra(hdc
, 2 );
2293 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2294 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2295 SetTextJustification(hdc
, 0, 0);
2296 SetTextCharacterExtra(hdc
, 0);
2297 size
.cx
= size
.cy
= 1234;
2298 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2299 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
2300 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2301 SetTextJustification(hdc
, 5, 1);
2302 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2303 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2304 SetTextJustification(hdc
, 0, 0);
2306 SetMapMode( hdc
, MM_ANISOTROPIC
);
2307 SetWindowExtEx( hdc
, 2, 2, NULL
);
2308 GetClientRect( hwnd
, &clientArea
);
2309 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2310 testJustification(hdc
, testText
, &clientArea
);
2312 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2313 for (i
= 0; i
< 10; i
++)
2315 SetTextCharacterExtra(hdc
, i
);
2316 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2317 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2319 SetTextCharacterExtra(hdc
, 0);
2320 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2321 for (i
= 0; i
< 10; i
++)
2323 SetTextCharacterExtra(hdc
, i
);
2324 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2325 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2327 SetTextCharacterExtra(hdc
, 0);
2329 SetViewportExtEx( hdc
, 3, 3, NULL
);
2330 GetClientRect( hwnd
, &clientArea
);
2331 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2332 testJustification(hdc
, testText
, &clientArea
);
2334 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2335 for (i
= 0; i
< 10; i
++)
2337 SetTextCharacterExtra(hdc
, i
);
2338 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2339 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2343 DeleteObject(hfont
);
2344 ReleaseDC(hwnd
, hdc
);
2345 DestroyWindow(hwnd
);
2348 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2352 HFONT hfont
, hfont_old
;
2359 assert(count
<= 128);
2361 memset(&lf
, 0, sizeof(lf
));
2363 lf
.lfCharSet
= charset
;
2365 lstrcpyA(lf
.lfFaceName
, "Arial");
2366 SetLastError(0xdeadbeef);
2367 hfont
= CreateFontIndirectA(&lf
);
2368 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2371 hfont_old
= SelectObject(hdc
, hfont
);
2373 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2374 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2376 SetLastError(0xdeadbeef);
2377 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2378 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
2380 if (charset
== SYMBOL_CHARSET
)
2382 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2383 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
2387 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2388 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
2391 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2393 trace("Can't find codepage for charset %d\n", cs
);
2397 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2399 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2401 skip("Font code page %d, looking for code page %d\n",
2402 pGdiGetCodePage(hdc
), code_page
);
2410 WCHAR unicode_buf
[128];
2412 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2414 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2416 SetLastError(0xdeadbeef);
2417 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2418 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2419 count
, ret
, GetLastError());
2425 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2427 SetLastError(0xdeadbeef);
2428 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2429 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2430 count
, ret
, GetLastError());
2433 SelectObject(hdc
, hfont_old
);
2434 DeleteObject(hfont
);
2441 static void test_font_charset(void)
2443 static struct charset_data
2447 WORD font_idxA
[128], font_idxW
[128];
2450 { ANSI_CHARSET
, 1252 },
2451 { RUSSIAN_CHARSET
, 1251 },
2452 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2456 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
2458 win_skip("Skipping the font charset test on a Win9x platform\n");
2462 if (!is_font_installed("Arial"))
2464 skip("Arial is not installed\n");
2468 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
2470 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2472 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2474 skip("Symbol or Wingdings is not installed\n");
2478 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2479 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2480 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2483 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2486 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2487 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2490 skip("Symbol or Wingdings is not installed\n");
2493 static void test_GdiGetCodePage(void)
2495 static const struct _matching_data
2497 UINT current_codepage
;
2500 UINT expected_codepage
;
2501 } matching_data
[] = {
2502 {1251, "Arial", ANSI_CHARSET
, 1252},
2503 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2505 {1252, "Arial", ANSI_CHARSET
, 1252},
2506 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2508 {1253, "Arial", ANSI_CHARSET
, 1252},
2509 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2511 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2512 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2513 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2515 { 936, "Arial", ANSI_CHARSET
, 936},
2516 { 936, "Tahoma", ANSI_CHARSET
, 936},
2517 { 936, "Simsun", ANSI_CHARSET
, 936},
2519 { 949, "Arial", ANSI_CHARSET
, 949},
2520 { 949, "Tahoma", ANSI_CHARSET
, 949},
2521 { 949, "Gulim", ANSI_CHARSET
, 949},
2523 { 950, "Arial", ANSI_CHARSET
, 950},
2524 { 950, "Tahoma", ANSI_CHARSET
, 950},
2525 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2534 if (!pGdiGetCodePage
)
2536 skip("GdiGetCodePage not available on this platform\n");
2542 for (i
= 0; i
< sizeof(matching_data
) / sizeof(struct _matching_data
); i
++)
2544 /* only test data matched current locale codepage */
2545 if (matching_data
[i
].current_codepage
!= acp
)
2548 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2550 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2556 memset(&lf
, 0, sizeof(lf
));
2558 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2559 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2560 hfont
= CreateFontIndirectA(&lf
);
2561 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2563 hfont
= SelectObject(hdc
, hfont
);
2564 charset
= GetTextCharset(hdc
);
2565 codepage
= pGdiGetCodePage(hdc
);
2566 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2567 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
, matching_data
[i
].expected_codepage
);
2568 ok(codepage
== matching_data
[i
].expected_codepage
,
2569 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2571 hfont
= SelectObject(hdc
, hfont
);
2572 DeleteObject(hfont
);
2574 /* CLIP_DFA_DISABLE turns off the font association */
2575 lf
.lfClipPrecision
= CLIP_DFA_DISABLE
;
2576 hfont
= CreateFontIndirectA(&lf
);
2577 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2579 hfont
= SelectObject(hdc
, hfont
);
2580 charset
= GetTextCharset(hdc
);
2581 codepage
= pGdiGetCodePage(hdc
);
2582 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d\n",
2583 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
);
2584 ok(codepage
== 1252, "GdiGetCodePage returned %d\n", codepage
);
2586 hfont
= SelectObject(hdc
, hfont
);
2587 DeleteObject(hfont
);
2589 ReleaseDC(NULL
, hdc
);
2593 static void test_GetFontUnicodeRanges(void)
2597 HFONT hfont
, hfont_old
;
2602 if (!pGetFontUnicodeRanges
)
2604 win_skip("GetFontUnicodeRanges not available before W2K\n");
2608 memset(&lf
, 0, sizeof(lf
));
2609 lstrcpyA(lf
.lfFaceName
, "Arial");
2610 hfont
= create_font("Arial", &lf
);
2613 hfont_old
= SelectObject(hdc
, hfont
);
2615 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2616 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2618 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2619 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2621 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2623 size
= pGetFontUnicodeRanges(hdc
, gs
);
2624 ok(size
, "GetFontUnicodeRanges failed\n");
2626 if (0) /* Disabled to limit console spam */
2627 for (i
= 0; i
< gs
->cRanges
; i
++)
2628 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2629 trace("found %u ranges\n", gs
->cRanges
);
2631 HeapFree(GetProcessHeap(), 0, gs
);
2633 SelectObject(hdc
, hfont_old
);
2634 DeleteObject(hfont
);
2635 ReleaseDC(NULL
, hdc
);
2638 #define MAX_ENUM_FONTS 4096
2640 struct enum_font_data
2643 LOGFONTA lf
[MAX_ENUM_FONTS
];
2646 struct enum_fullname_data
2649 ENUMLOGFONTA elf
[MAX_ENUM_FONTS
];
2652 struct enum_font_dataW
2655 LOGFONTW lf
[MAX_ENUM_FONTS
];
2658 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2660 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2661 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2663 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2664 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2666 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2668 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2670 if (0) /* Disabled to limit console spam */
2671 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2672 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2673 if (efd
->total
< MAX_ENUM_FONTS
)
2674 efd
->lf
[efd
->total
++] = *lf
;
2676 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2681 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2683 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2684 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2686 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2687 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2689 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2691 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2693 if (0) /* Disabled to limit console spam */
2694 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2695 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2696 if (efd
->total
< MAX_ENUM_FONTS
)
2697 efd
->lf
[efd
->total
++] = *lf
;
2699 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2704 static void get_charset_stats(struct enum_font_data
*efd
,
2705 int *ansi_charset
, int *symbol_charset
,
2706 int *russian_charset
)
2711 *symbol_charset
= 0;
2712 *russian_charset
= 0;
2714 for (i
= 0; i
< efd
->total
; i
++)
2716 switch (efd
->lf
[i
].lfCharSet
)
2721 case SYMBOL_CHARSET
:
2722 (*symbol_charset
)++;
2724 case RUSSIAN_CHARSET
:
2725 (*russian_charset
)++;
2731 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2732 int *ansi_charset
, int *symbol_charset
,
2733 int *russian_charset
)
2738 *symbol_charset
= 0;
2739 *russian_charset
= 0;
2741 for (i
= 0; i
< efd
->total
; i
++)
2743 switch (efd
->lf
[i
].lfCharSet
)
2748 case SYMBOL_CHARSET
:
2749 (*symbol_charset
)++;
2751 case RUSSIAN_CHARSET
:
2752 (*russian_charset
)++;
2758 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2760 struct enum_font_data efd
;
2761 struct enum_font_dataW efdw
;
2764 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2766 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2768 if (*font_name
&& !is_truetype_font_installed(font_name
))
2770 skip("%s is not installed\n", font_name
);
2776 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2777 * while EnumFontFamiliesEx doesn't.
2779 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2782 * Use EnumFontFamiliesW since win98 crashes when the
2783 * second parameter is NULL using EnumFontFamilies
2786 SetLastError(0xdeadbeef);
2787 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2788 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2791 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2792 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2793 ansi_charset
, symbol_charset
, russian_charset
);
2794 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2795 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2796 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2797 ok(russian_charset
> 0 ||
2798 broken(russian_charset
== 0), /* NT4 */
2799 "NULL family should enumerate RUSSIAN_CHARSET\n");
2803 SetLastError(0xdeadbeef);
2804 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2805 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2808 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2809 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2810 ansi_charset
, symbol_charset
, russian_charset
);
2811 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2812 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2813 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2814 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2819 SetLastError(0xdeadbeef);
2820 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2821 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2822 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2823 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2824 ansi_charset
, symbol_charset
, russian_charset
,
2825 *font_name
? font_name
: "<empty>");
2827 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2829 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2830 for (i
= 0; i
< efd
.total
; i
++)
2832 /* FIXME: remove completely once Wine is fixed */
2833 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2836 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2839 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2840 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2841 font_name
, efd
.lf
[i
].lfFaceName
);
2844 memset(&lf
, 0, sizeof(lf
));
2845 lf
.lfCharSet
= ANSI_CHARSET
;
2846 strcpy(lf
.lfFaceName
, font_name
);
2848 SetLastError(0xdeadbeef);
2849 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2850 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2851 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2852 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2853 ansi_charset
, symbol_charset
, russian_charset
,
2854 *font_name
? font_name
: "<empty>");
2855 if (font_charset
== SYMBOL_CHARSET
)
2858 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2860 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2864 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2865 for (i
= 0; i
< efd
.total
; i
++)
2867 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2869 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2870 font_name
, efd
.lf
[i
].lfFaceName
);
2874 /* DEFAULT_CHARSET should enumerate all available charsets */
2875 memset(&lf
, 0, sizeof(lf
));
2876 lf
.lfCharSet
= DEFAULT_CHARSET
;
2877 strcpy(lf
.lfFaceName
, font_name
);
2879 SetLastError(0xdeadbeef);
2880 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2881 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2882 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2883 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2884 ansi_charset
, symbol_charset
, russian_charset
,
2885 *font_name
? font_name
: "<empty>");
2886 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2887 for (i
= 0; i
< efd
.total
; i
++)
2890 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2891 font_name
, efd
.lf
[i
].lfFaceName
);
2895 switch (font_charset
)
2898 ok(ansi_charset
> 0,
2899 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2901 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2902 ok(russian_charset
> 0,
2903 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2905 case SYMBOL_CHARSET
:
2907 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2909 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2910 ok(!russian_charset
,
2911 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2913 case DEFAULT_CHARSET
:
2914 ok(ansi_charset
> 0,
2915 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2916 ok(symbol_charset
> 0,
2917 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2918 ok(russian_charset
> 0,
2919 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2925 ok(ansi_charset
> 0,
2926 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2927 ok(symbol_charset
> 0,
2928 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2929 ok(russian_charset
> 0,
2930 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2933 memset(&lf
, 0, sizeof(lf
));
2934 lf
.lfCharSet
= SYMBOL_CHARSET
;
2935 strcpy(lf
.lfFaceName
, font_name
);
2937 SetLastError(0xdeadbeef);
2938 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2939 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2940 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2941 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2942 ansi_charset
, symbol_charset
, russian_charset
,
2943 *font_name
? font_name
: "<empty>");
2944 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2945 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2948 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2949 for (i
= 0; i
< efd
.total
; i
++)
2951 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2953 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2954 font_name
, efd
.lf
[i
].lfFaceName
);
2958 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2959 ok(symbol_charset
> 0,
2960 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2961 ok(!russian_charset
,
2962 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2968 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2970 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
2971 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
2972 const DWORD valid_bits
= 0x003f01ff;
2976 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
2978 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
2979 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
2980 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
2989 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
2991 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2993 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2995 if (efd
->total
< MAX_ENUM_FONTS
)
2996 efd
->lf
[efd
->total
++] = *lf
;
2998 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
3003 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3005 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
3007 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3009 if (efnd
->total
< MAX_ENUM_FONTS
)
3010 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
3012 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
3017 static void test_EnumFontFamiliesEx_default_charset(void)
3019 struct enum_font_data efd
;
3020 LOGFONTA target
, enum_font
;
3026 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3027 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3032 memset(&enum_font
, 0, sizeof(enum_font
));
3033 enum_font
.lfCharSet
= csi
.ciCharset
;
3034 target
.lfFaceName
[0] = '\0';
3035 target
.lfCharSet
= csi
.ciCharset
;
3036 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3037 if (target
.lfFaceName
[0] == '\0') {
3038 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3041 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3042 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3043 target
.lfCharSet
= ANSI_CHARSET
;
3047 memset(&enum_font
, 0, sizeof(enum_font
));
3048 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3049 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3050 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3053 trace("'%s' has %d charsets.\n", target
.lfFaceName
, efd
.total
);
3054 if (efd
.total
< 2) {
3055 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3059 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3060 "(%s) got charset %d expected %d\n",
3061 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3066 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3068 HFONT hfont
, hfont_prev
;
3070 GLYPHMETRICS gm1
, gm2
;
3074 if(!pGetGlyphIndicesA
)
3077 /* negative widths are handled just as positive ones */
3078 lf2
.lfWidth
= -lf
->lfWidth
;
3080 SetLastError(0xdeadbeef);
3081 hfont
= CreateFontIndirectA(lf
);
3082 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3083 check_font("original", lf
, hfont
);
3085 hfont_prev
= SelectObject(hdc
, hfont
);
3087 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3088 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3090 SelectObject(hdc
, hfont_prev
);
3091 DeleteObject(hfont
);
3092 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3096 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3097 memset(&gm1
, 0xab, sizeof(gm1
));
3098 SetLastError(0xdeadbeef);
3099 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3100 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3102 SelectObject(hdc
, hfont_prev
);
3103 DeleteObject(hfont
);
3105 SetLastError(0xdeadbeef);
3106 hfont
= CreateFontIndirectA(&lf2
);
3107 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3108 check_font("negative width", &lf2
, hfont
);
3110 hfont_prev
= SelectObject(hdc
, hfont
);
3112 memset(&gm2
, 0xbb, sizeof(gm2
));
3113 SetLastError(0xdeadbeef);
3114 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3115 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3117 SelectObject(hdc
, hfont_prev
);
3118 DeleteObject(hfont
);
3120 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3121 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3122 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3123 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3124 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3125 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3126 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3127 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3128 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3129 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3130 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3133 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3134 #include "pshpack2.h"
3138 SHORT xAvgCharWidth
;
3139 USHORT usWeightClass
;
3140 USHORT usWidthClass
;
3142 SHORT ySubscriptXSize
;
3143 SHORT ySubscriptYSize
;
3144 SHORT ySubscriptXOffset
;
3145 SHORT ySubscriptYOffset
;
3146 SHORT ySuperscriptXSize
;
3147 SHORT ySuperscriptYSize
;
3148 SHORT ySuperscriptXOffset
;
3149 SHORT ySuperscriptYOffset
;
3150 SHORT yStrikeoutSize
;
3151 SHORT yStrikeoutPosition
;
3154 ULONG ulUnicodeRange1
;
3155 ULONG ulUnicodeRange2
;
3156 ULONG ulUnicodeRange3
;
3157 ULONG ulUnicodeRange4
;
3160 USHORT usFirstCharIndex
;
3161 USHORT usLastCharIndex
;
3162 /* According to the Apple spec, original version didn't have the below fields,
3163 * version numbers were taken from the OpenType spec.
3165 /* version 0 (TrueType 1.5) */
3166 USHORT sTypoAscender
;
3167 USHORT sTypoDescender
;
3168 USHORT sTypoLineGap
;
3170 USHORT usWinDescent
;
3171 /* version 1 (TrueType 1.66) */
3172 ULONG ulCodePageRange1
;
3173 ULONG ulCodePageRange2
;
3174 /* version 2 (OpenType 1.2) */
3177 USHORT usDefaultChar
;
3179 USHORT usMaxContext
;
3181 #include "poppack.h"
3194 } cmap_encoding_record
;
3202 BYTE glyph_ids
[256];
3212 USHORT search_range
;
3213 USHORT entry_selector
;
3216 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3219 USHORT start_count[seg_countx2 / 2];
3220 USHORT id_delta[seg_countx2 / 2];
3221 USHORT id_range_offset[seg_countx2 / 2];
3231 USHORT id_range_offset
;
3232 } cmap_format_4_seg
;
3234 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
3236 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3237 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3238 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3239 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3240 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3243 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3246 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3250 for(i
= 0; i
< 256; i
++)
3252 if(cmap
->glyph_ids
[i
] == 0) continue;
3254 if(*first
== 256) *first
= i
;
3256 if(*first
== 256) return FALSE
;
3260 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3262 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3263 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3264 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3265 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3266 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3269 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3272 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3273 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3277 for(i
= 0; i
< seg_count
; i
++)
3279 cmap_format_4_seg seg
;
3281 get_seg4(cmap
, i
, &seg
);
3283 if(seg
.start_count
> 0xfffe) break;
3285 if(*first
== 0x10000) *first
= seg
.start_count
;
3287 *last
= min(seg
.end_count
, 0xfffe);
3290 if(*first
== 0x10000) return FALSE
;
3294 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3297 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3299 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3301 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3302 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3315 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3318 cmap_header
*header
;
3323 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3324 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3325 if(size
== GDI_ERROR
) return FALSE
;
3327 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3328 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3329 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3330 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3332 cmap
= get_cmap(header
, 3, 1);
3334 *cmap_type
= cmap_ms_unicode
;
3337 cmap
= get_cmap(header
, 3, 0);
3338 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3342 *cmap_type
= cmap_none
;
3346 format
= GET_BE_WORD(*(WORD
*)cmap
);
3350 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3353 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3356 trace("unhandled cmap format %d\n", format
);
3361 HeapFree(GetProcessHeap(), 0, header
);
3365 #define TT_PLATFORM_APPLE_UNICODE 0
3366 #define TT_PLATFORM_MACINTOSH 1
3367 #define TT_PLATFORM_MICROSOFT 3
3368 #define TT_APPLE_ID_DEFAULT 0
3369 #define TT_APPLE_ID_ISO_10646 2
3370 #define TT_APPLE_ID_UNICODE_2_0 3
3371 #define TT_MS_ID_SYMBOL_CS 0
3372 #define TT_MS_ID_UNICODE_CS 1
3373 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3374 #define TT_NAME_ID_FONT_FAMILY 1
3375 #define TT_NAME_ID_FONT_SUBFAMILY 2
3376 #define TT_NAME_ID_UNIQUE_ID 3
3377 #define TT_NAME_ID_FULL_NAME 4
3378 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3380 typedef struct sfnt_name
3390 static const LANGID mac_langid_table
[] =
3392 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
3393 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
3394 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
3395 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
3396 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
3397 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
3398 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
3399 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
3400 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
3401 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
3402 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
3403 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
3404 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
3405 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
3406 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
3407 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
3408 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
3409 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
3410 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
3411 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3412 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
3413 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
3414 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
3415 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
3416 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
3417 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
3418 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
3419 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
3420 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
3421 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
3422 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
3423 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
3424 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
3425 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3426 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
3427 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
3428 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
3429 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
3430 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
3431 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
3432 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
3433 0, /* TT_MAC_LANGID_YIDDISH */
3434 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
3435 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
3436 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
3437 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
3438 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
3439 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
3440 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
3441 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
3442 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3443 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
3444 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
3445 0, /* TT_MAC_LANGID_MOLDAVIAN */
3446 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
3447 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
3448 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
3449 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
3450 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3451 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
3452 0, /* TT_MAC_LANGID_KURDISH */
3453 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
3454 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
3455 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
3456 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
3457 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
3458 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
3459 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
3460 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
3461 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
3462 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
3463 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
3464 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
3465 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
3466 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
3467 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
3468 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
3469 0, /* TT_MAC_LANGID_BURMESE */
3470 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
3471 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
3472 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
3473 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
3474 0, /* TT_MAC_LANGID_TAGALOG */
3475 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3476 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3477 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
3478 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
3479 0, /* TT_MAC_LANGID_GALLA */
3480 0, /* TT_MAC_LANGID_SOMALI */
3481 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
3482 0, /* TT_MAC_LANGID_RUANDA */
3483 0, /* TT_MAC_LANGID_RUNDI */
3484 0, /* TT_MAC_LANGID_CHEWA */
3485 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
3486 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
3487 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3489 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
3490 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
3491 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
3492 0, /* TT_MAC_LANGID_LATIN */
3493 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
3494 0, /* TT_MAC_LANGID_GUARANI */
3495 0, /* TT_MAC_LANGID_AYMARA */
3496 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
3497 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
3498 0, /* TT_MAC_LANGID_DZONGKHA */
3499 0, /* TT_MAC_LANGID_JAVANESE */
3500 0, /* TT_MAC_LANGID_SUNDANESE */
3501 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
3502 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
3503 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
3504 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
3505 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3506 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
3507 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
3508 0, /* TT_MAC_LANGID_TONGAN */
3509 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3510 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
3511 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3514 static inline WORD
get_mac_code_page( const sfnt_name
*name
)
3516 if (GET_BE_WORD(name
->encoding_id
) == TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
3517 return 10000 + GET_BE_WORD(name
->encoding_id
);
3520 static int match_name_table_language( const sfnt_name
*name
, LANGID lang
)
3525 switch (GET_BE_WORD(name
->platform_id
))
3527 case TT_PLATFORM_MICROSOFT
:
3528 res
+= 5; /* prefer the Microsoft name */
3529 switch (GET_BE_WORD(name
->encoding_id
))
3531 case TT_MS_ID_UNICODE_CS
:
3532 case TT_MS_ID_SYMBOL_CS
:
3533 name_lang
= GET_BE_WORD(name
->language_id
);
3539 case TT_PLATFORM_MACINTOSH
:
3540 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
3541 if (GET_BE_WORD(name
->language_id
) >= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
3542 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3544 case TT_PLATFORM_APPLE_UNICODE
:
3545 res
+= 2; /* prefer Unicode encodings */
3546 switch (GET_BE_WORD(name
->encoding_id
))
3548 case TT_APPLE_ID_DEFAULT
:
3549 case TT_APPLE_ID_ISO_10646
:
3550 case TT_APPLE_ID_UNICODE_2_0
:
3551 if (GET_BE_WORD(name
->language_id
) >= sizeof(mac_langid_table
)/sizeof(mac_langid_table
[0])) return 0;
3552 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3561 if (name_lang
== lang
) res
+= 30;
3562 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
3563 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
3567 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3569 struct sfnt_name_header
3572 USHORT number_of_record
;
3573 USHORT storage_offset
;
3577 LONG size
, offset
, length
;
3582 int res
, best_lang
= 0, best_index
= -1;
3584 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3585 ok(size
!= GDI_ERROR
, "no name table found\n");
3586 if(size
== GDI_ERROR
) return FALSE
;
3588 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3589 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3590 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3592 header
= (void *)data
;
3593 header
->format
= GET_BE_WORD(header
->format
);
3594 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3595 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3596 if (header
->format
!= 0)
3598 trace("got format %u\n", header
->format
);
3601 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3603 trace("number records out of range: %d\n", header
->number_of_record
);
3606 if (header
->storage_offset
>= size
)
3608 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3612 entry
= (void *)&header
[1];
3613 for (i
= 0; i
< header
->number_of_record
; i
++)
3615 if (GET_BE_WORD(entry
[i
].name_id
) != name_id
) continue;
3616 res
= match_name_table_language( &entry
[i
], language_id
);
3617 if (res
> best_lang
)
3624 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[best_index
].offset
);
3625 length
= GET_BE_WORD(entry
[best_index
].length
);
3626 if (offset
+ length
> size
)
3628 trace("entry %d is out of range\n", best_index
);
3631 if (length
>= out_size
)
3633 trace("buffer too small for entry %d\n", best_index
);
3637 name
= (WCHAR
*)(data
+ offset
);
3638 for (c
= 0; c
< length
/ 2; c
++)
3639 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3645 HeapFree(GetProcessHeap(), 0, data
);
3649 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3652 HFONT hfont
, hfont_old
;
3656 const char *font_name
= lf
->lfFaceName
;
3657 DWORD cmap_first
= 0, cmap_last
= 0;
3658 UINT ascent
, descent
, cell_height
;
3659 cmap_type cmap_type
;
3660 BOOL sys_lang_non_english
;
3662 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3665 SetLastError(0xdeadbeef);
3666 hfont
= CreateFontIndirectA(lf
);
3667 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3669 hfont_old
= SelectObject(hdc
, hfont
);
3671 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3672 if (size
== GDI_ERROR
)
3674 trace("OS/2 chunk was not found\n");
3677 if (size
> sizeof(tt_os2
))
3679 trace("got too large OS/2 chunk of size %u\n", size
);
3680 size
= sizeof(tt_os2
);
3683 memset(&tt_os2
, 0, sizeof(tt_os2
));
3684 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3685 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3687 SetLastError(0xdeadbeef);
3688 ret
= GetTextMetricsA(hdc
, &tmA
);
3689 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3691 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3693 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3697 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3698 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3699 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3703 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3704 descent
= GET_BE_WORD(tt_os2
.usWinDescent
);
3705 cell_height
= ascent
+ descent
;
3706 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3707 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3709 version
= GET_BE_WORD(tt_os2
.version
);
3711 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3712 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3713 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3714 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3716 if (winetest_debug
> 1)
3717 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3718 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3719 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3721 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3726 case 1255: /* Hebrew */
3727 expect_last_W
= 0xf896;
3729 case 1257: /* Baltic */
3730 expect_last_W
= 0xf8fd;
3733 expect_last_W
= 0xf0ff;
3735 expect_break_W
= 0x20;
3736 expect_default_W
= expect_break_W
- 1;
3737 expect_first_A
= 0x1e;
3738 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3742 expect_first_W
= cmap_first
;
3743 expect_last_W
= cmap_last
;
3744 if(os2_first_char
<= 1)
3745 expect_break_W
= os2_first_char
+ 2;
3746 else if(os2_first_char
> 0xff)
3747 expect_break_W
= 0x20;
3749 expect_break_W
= os2_first_char
;
3750 expect_default_W
= expect_break_W
- 1;
3751 expect_first_A
= expect_default_W
- 1;
3752 expect_last_A
= min(expect_last_W
, 0xff);
3754 expect_break_A
= expect_break_W
;
3755 expect_default_A
= expect_default_W
;
3757 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3758 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3759 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
3760 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3761 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3763 ok(tmA
.tmFirstChar
== expect_first_A
||
3764 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3765 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3766 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3767 ok(tmA
.tmLastChar
== expect_last_A
||
3768 tmA
.tmLastChar
== 0xff /* win9x */,
3769 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3771 skip("tmLastChar is DBCS lead byte\n");
3772 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3773 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3774 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3775 "A: tmDefaultChar for %s got %02x expected %02x\n",
3776 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3779 SetLastError(0xdeadbeef);
3780 ret
= GetTextMetricsW(hdc
, &tmW
);
3781 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3782 "GetTextMetricsW error %u\n", GetLastError());
3785 /* Wine uses the os2 first char */
3786 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3787 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3788 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3790 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3791 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3793 /* Wine uses the os2 last char */
3794 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3795 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3796 font_name
, tmW
.tmLastChar
, expect_last_W
);
3798 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3799 font_name
, tmW
.tmLastChar
, expect_last_W
);
3800 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3801 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3802 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3803 "W: tmDefaultChar for %s got %02x expected %02x\n",
3804 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3806 /* Test the aspect ratio while we have tmW */
3807 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3808 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3809 tmW
.tmDigitizedAspectX
, ret
);
3810 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3811 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3812 tmW
.tmDigitizedAspectX
, ret
);
3816 /* test FF_ values */
3817 switch(tt_os2
.panose
.bFamilyType
)
3821 case PAN_FAMILY_TEXT_DISPLAY
:
3822 case PAN_FAMILY_PICTORIAL
:
3824 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3825 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3827 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3830 switch(tt_os2
.panose
.bSerifStyle
)
3835 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3838 case PAN_SERIF_COVE
:
3839 case PAN_SERIF_OBTUSE_COVE
:
3840 case PAN_SERIF_SQUARE_COVE
:
3841 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3842 case PAN_SERIF_SQUARE
:
3843 case PAN_SERIF_THIN
:
3844 case PAN_SERIF_BONE
:
3845 case PAN_SERIF_EXAGGERATED
:
3846 case PAN_SERIF_TRIANGLE
:
3847 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3850 case PAN_SERIF_NORMAL_SANS
:
3851 case PAN_SERIF_OBTUSE_SANS
:
3852 case PAN_SERIF_PERP_SANS
:
3853 case PAN_SERIF_FLARED
:
3854 case PAN_SERIF_ROUNDED
:
3855 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3860 case PAN_FAMILY_SCRIPT
:
3861 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3864 case PAN_FAMILY_DECORATIVE
:
3865 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3869 test_negative_width(hdc
, lf
);
3872 SelectObject(hdc
, hfont_old
);
3873 DeleteObject(hfont
);
3878 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3880 INT
*enumed
= (INT
*)lParam
;
3882 if (type
== TRUETYPE_FONTTYPE
)
3885 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
3890 static void test_GetTextMetrics(void)
3896 /* Report only once */
3897 if(!pGetGlyphIndicesA
)
3898 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3902 memset(&lf
, 0, sizeof(lf
));
3903 lf
.lfCharSet
= DEFAULT_CHARSET
;
3905 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
3906 trace("Tested metrics of %d truetype fonts\n", enumed
);
3911 static void test_nonexistent_font(void)
3919 { "Times New Roman Baltic", 186 },
3920 { "Times New Roman CE", 238 },
3921 { "Times New Roman CYR", 204 },
3922 { "Times New Roman Greek", 161 },
3923 { "Times New Roman TUR", 162 }
3931 { "MS Shell Dlg", 186 },
3932 { "MS Shell Dlg", 238 },
3933 { "MS Shell Dlg", 204 },
3934 { "MS Shell Dlg", 161 },
3935 { "MS Shell Dlg", 162 }
3941 INT cs
, expected_cs
, i
, ret
;
3942 char buf
[LF_FACESIZE
];
3944 expected_cs
= GetACP();
3945 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3947 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3950 expected_cs
= csi
.ciCharset
;
3951 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3953 hdc
= CreateCompatibleDC(0);
3955 for (i
= 0; i
< sizeof(shell_subst
)/sizeof(shell_subst
[0]); i
++)
3957 ret
= is_font_installed(shell_subst
[i
].name
);
3958 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
3959 ret
= is_truetype_font_installed(shell_subst
[i
].name
);
3960 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
3962 memset(&lf
, 0, sizeof(lf
));
3964 lf
.lfWeight
= FW_REGULAR
;
3965 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
3966 hfont
= CreateFontIndirectA(&lf
);
3967 hfont
= SelectObject(hdc
, hfont
);
3968 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3969 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
3970 cs
= GetTextCharset(hdc
);
3971 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, shell_subst
[i
].name
);
3973 DeleteObject(SelectObject(hdc
, hfont
));
3975 memset(&lf
, 0, sizeof(lf
));
3977 lf
.lfWeight
= FW_DONTCARE
;
3978 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
3979 hfont
= CreateFontIndirectA(&lf
);
3980 hfont
= SelectObject(hdc
, hfont
);
3981 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3982 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
3983 cs
= GetTextCharset(hdc
);
3984 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, shell_subst
[i
].name
);
3985 DeleteObject(SelectObject(hdc
, hfont
));
3988 if (!is_truetype_font_installed("Arial") ||
3989 !is_truetype_font_installed("Times New Roman"))
3992 skip("Arial or Times New Roman not installed\n");
3996 memset(&lf
, 0, sizeof(lf
));
3998 lf
.lfWeight
= FW_REGULAR
;
3999 lf
.lfCharSet
= ANSI_CHARSET
;
4000 lf
.lfPitchAndFamily
= FF_SWISS
;
4001 strcpy(lf
.lfFaceName
, "Nonexistent font");
4002 hfont
= CreateFontIndirectA(&lf
);
4003 hfont
= SelectObject(hdc
, hfont
);
4004 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4005 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
4006 cs
= GetTextCharset(hdc
);
4007 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4008 DeleteObject(SelectObject(hdc
, hfont
));
4010 memset(&lf
, 0, sizeof(lf
));
4012 lf
.lfWeight
= FW_DONTCARE
;
4013 strcpy(lf
.lfFaceName
, "Nonexistent font");
4014 hfont
= CreateFontIndirectA(&lf
);
4015 hfont
= SelectObject(hdc
, hfont
);
4016 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4017 todo_wine
/* Wine uses Arial for all substitutions */
4018 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
4019 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
4020 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4022 cs
= GetTextCharset(hdc
);
4023 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
4024 DeleteObject(SelectObject(hdc
, hfont
));
4026 memset(&lf
, 0, sizeof(lf
));
4028 lf
.lfWeight
= FW_REGULAR
;
4029 strcpy(lf
.lfFaceName
, "Nonexistent font");
4030 hfont
= CreateFontIndirectA(&lf
);
4031 hfont
= SelectObject(hdc
, hfont
);
4032 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4033 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4034 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
4035 cs
= GetTextCharset(hdc
);
4036 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4037 DeleteObject(SelectObject(hdc
, hfont
));
4039 memset(&lf
, 0, sizeof(lf
));
4041 lf
.lfWeight
= FW_DONTCARE
;
4042 strcpy(lf
.lfFaceName
, "Times New Roman");
4043 hfont
= CreateFontIndirectA(&lf
);
4044 hfont
= SelectObject(hdc
, hfont
);
4045 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4046 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
4047 cs
= GetTextCharset(hdc
);
4048 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4049 DeleteObject(SelectObject(hdc
, hfont
));
4051 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
4053 ret
= is_font_installed(font_subst
[i
].name
);
4055 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4056 "%s should be enumerated\n", font_subst
[i
].name
);
4057 ret
= is_truetype_font_installed(font_subst
[i
].name
);
4059 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4060 "%s should be enumerated\n", font_subst
[i
].name
);
4062 memset(&lf
, 0, sizeof(lf
));
4064 lf
.lfWeight
= FW_REGULAR
;
4065 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4066 hfont
= CreateFontIndirectA(&lf
);
4067 hfont
= SelectObject(hdc
, hfont
);
4068 cs
= GetTextCharset(hdc
);
4069 if (font_subst
[i
].charset
== expected_cs
)
4071 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4072 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4073 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
4077 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
4078 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4079 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4080 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
4082 DeleteObject(SelectObject(hdc
, hfont
));
4084 memset(&lf
, 0, sizeof(lf
));
4086 lf
.lfWeight
= FW_DONTCARE
;
4087 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4088 hfont
= CreateFontIndirectA(&lf
);
4089 hfont
= SelectObject(hdc
, hfont
);
4090 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4091 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
4092 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
4093 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
4094 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4095 "got %s for font %s\n", buf
, font_subst
[i
].name
);
4096 cs
= GetTextCharset(hdc
);
4097 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4098 DeleteObject(SelectObject(hdc
, hfont
));
4104 static void test_GdiRealizationInfo(void)
4109 HFONT hfont
, hfont_old
;
4112 if(!pGdiRealizationInfo
)
4114 win_skip("GdiRealizationInfo not available\n");
4120 memset(info
, 0xcc, sizeof(info
));
4121 r
= pGdiRealizationInfo(hdc
, info
);
4122 ok(r
!= 0, "ret 0\n");
4123 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
4124 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4126 if (!is_truetype_font_installed("Arial"))
4128 skip("skipping GdiRealizationInfo with truetype font\n");
4132 memset(&lf
, 0, sizeof(lf
));
4133 strcpy(lf
.lfFaceName
, "Arial");
4135 lf
.lfWeight
= FW_NORMAL
;
4136 hfont
= CreateFontIndirectA(&lf
);
4137 hfont_old
= SelectObject(hdc
, hfont
);
4139 memset(info
, 0xcc, sizeof(info
));
4140 r
= pGdiRealizationInfo(hdc
, info
);
4141 ok(r
!= 0, "ret 0\n");
4142 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
4143 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4145 DeleteObject(SelectObject(hdc
, hfont_old
));
4151 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4152 the nul in the count of characters copied when the face name buffer is not
4153 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4154 always includes it. */
4155 static void test_GetTextFace(void)
4157 static const char faceA
[] = "Tahoma";
4158 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
4161 char bufA
[LF_FACESIZE
];
4162 WCHAR bufW
[LF_FACESIZE
];
4167 if(!is_font_installed("Tahoma"))
4169 skip("Tahoma is not installed so skipping this test\n");
4174 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
4175 f
= CreateFontIndirectA(&fA
);
4176 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
4179 g
= SelectObject(dc
, f
);
4180 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
4181 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
4182 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
4184 /* Play with the count arg. */
4186 n
= GetTextFaceA(dc
, 0, bufA
);
4187 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4188 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4191 n
= GetTextFaceA(dc
, 1, bufA
);
4192 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4193 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4195 bufA
[0] = 'x'; bufA
[1] = 'y';
4196 n
= GetTextFaceA(dc
, 2, bufA
);
4197 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
4198 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
4200 n
= GetTextFaceA(dc
, 0, NULL
);
4201 ok(n
== sizeof faceA
||
4202 broken(n
== 0), /* win98, winMe */
4203 "GetTextFaceA returned %d\n", n
);
4205 DeleteObject(SelectObject(dc
, g
));
4206 ReleaseDC(NULL
, dc
);
4209 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
4210 SetLastError(0xdeadbeef);
4211 f
= CreateFontIndirectW(&fW
);
4212 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4214 win_skip("CreateFontIndirectW is not implemented\n");
4217 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
4220 g
= SelectObject(dc
, f
);
4221 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
4222 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4223 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
4225 /* Play with the count arg. */
4227 n
= GetTextFaceW(dc
, 0, bufW
);
4228 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
4229 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4232 n
= GetTextFaceW(dc
, 1, bufW
);
4233 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
4234 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4236 bufW
[0] = 'x'; bufW
[1] = 'y';
4237 n
= GetTextFaceW(dc
, 2, bufW
);
4238 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4239 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4241 n
= GetTextFaceW(dc
, 0, NULL
);
4242 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4244 DeleteObject(SelectObject(dc
, g
));
4245 ReleaseDC(NULL
, dc
);
4248 static void test_orientation(void)
4250 static const char test_str
[11] = "Test String";
4253 HFONT hfont
, old_hfont
;
4256 if (!is_truetype_font_installed("Arial"))
4258 skip("Arial is not installed\n");
4262 hdc
= CreateCompatibleDC(0);
4263 memset(&lf
, 0, sizeof(lf
));
4264 lstrcpyA(lf
.lfFaceName
, "Arial");
4266 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4267 hfont
= create_font("orientation", &lf
);
4268 old_hfont
= SelectObject(hdc
, hfont
);
4269 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4270 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4271 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4272 SelectObject(hdc
, old_hfont
);
4273 DeleteObject(hfont
);
4277 static void test_oemcharset(void)
4281 HFONT hfont
, old_hfont
;
4284 hdc
= CreateCompatibleDC(0);
4285 ZeroMemory(&lf
, sizeof(lf
));
4287 lf
.lfCharSet
= OEM_CHARSET
;
4288 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4289 lstrcpyA(lf
.lfFaceName
, "Terminal");
4290 hfont
= CreateFontIndirectA(&lf
);
4291 old_hfont
= SelectObject(hdc
, hfont
);
4292 charset
= GetTextCharset(hdc
);
4294 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4295 hfont
= SelectObject(hdc
, old_hfont
);
4296 GetObjectA(hfont
, sizeof(clf
), &clf
);
4297 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4298 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4299 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4300 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4301 DeleteObject(hfont
);
4305 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4306 const TEXTMETRICA
*lpntme
,
4307 DWORD FontType
, LPARAM lParam
)
4309 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4311 LOGFONTA lf
= *lpelfe
;
4315 /* skip bitmap, proportional or vertical font */
4316 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4317 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4318 lf
.lfFaceName
[0] == '@')
4321 /* skip linked font */
4322 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4323 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4326 /* skip linked font, like SimSun-ExtB */
4327 switch (lpelfe
->lfCharSet
) {
4328 case SHIFTJIS_CHARSET
:
4329 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4331 case GB2312_CHARSET
:
4332 case CHINESEBIG5_CHARSET
:
4333 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4335 case HANGEUL_CHARSET
:
4336 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4339 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4345 /* test with an odd height */
4348 hfont
= CreateFontIndirectA(&lf
);
4351 *(HFONT
*)lParam
= hfont
;
4357 static void test_GetGlyphOutline(void)
4360 GLYPHMETRICS gm
, gm2
;
4362 HFONT hfont
, old_hfont
;
4364 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4365 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4373 {ANSI_CHARSET
, 0x30, 0x30},
4374 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4375 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4376 {GB2312_CHARSET
, 0x8141, 0x4e04},
4377 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4381 if (!is_truetype_font_installed("Tahoma"))
4383 skip("Tahoma is not installed\n");
4387 hdc
= CreateCompatibleDC(0);
4388 memset(&lf
, 0, sizeof(lf
));
4390 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4391 SetLastError(0xdeadbeef);
4392 hfont
= CreateFontIndirectA(&lf
);
4393 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4394 old_hfont
= SelectObject(hdc
, hfont
);
4396 memset(&gm
, 0, sizeof(gm
));
4397 SetLastError(0xdeadbeef);
4398 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4399 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4401 memset(&gm
, 0, sizeof(gm
));
4402 SetLastError(0xdeadbeef);
4403 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4404 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4405 ok(GetLastError() == 0xdeadbeef ||
4406 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4407 "expected 0xdeadbeef, got %u\n", GetLastError());
4409 memset(&gm
, 0, sizeof(gm
));
4410 SetLastError(0xdeadbeef);
4411 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4412 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4413 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4415 memset(&gm
, 0, sizeof(gm
));
4416 SetLastError(0xdeadbeef);
4417 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4418 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4420 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4421 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4424 /* test for needed buffer size request on space char */
4425 memset(&gm
, 0, sizeof(gm
));
4426 SetLastError(0xdeadbeef);
4427 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4428 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4430 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4431 ok(gm
.gmBlackBoxX
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxX
);
4432 ok(gm
.gmBlackBoxY
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxY
);
4435 /* requesting buffer size for space char + error */
4436 memset(&gm
, 0, sizeof(gm
));
4437 SetLastError(0xdeadbeef);
4438 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4439 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4441 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4442 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4443 ok(gm
.gmBlackBoxX
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxX
);
4444 ok(gm
.gmBlackBoxY
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxY
);
4447 /* test GetGlyphOutline with a buffer too small */
4448 SetLastError(0xdeadbeef);
4449 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_NATIVE
, &gm
, sizeof(i
), &i
, &mat
);
4450 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4451 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4453 for (i
= 0; i
< sizeof(fmt
) / sizeof(fmt
[0]); ++i
)
4457 memset(&gm
, 0xab, sizeof(gm
));
4458 SetLastError(0xdeadbeef);
4459 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4460 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4462 if (fmt
[i
] == GGO_METRICS
)
4463 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4465 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4466 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4467 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4470 memset(&gm
, 0xab, sizeof(gm
));
4471 SetLastError(0xdeadbeef);
4472 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4473 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4475 if (fmt
[i
] == GGO_METRICS
)
4476 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4478 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4479 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4480 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4483 memset(&gm
, 0xab, sizeof(gm
));
4484 SetLastError(0xdeadbeef);
4485 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4486 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4488 if (fmt
[i
] == GGO_METRICS
)
4489 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4491 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4492 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4493 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4496 memset(&gm
, 0xab, sizeof(gm
));
4497 SetLastError(0xdeadbeef);
4498 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4499 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4501 if (fmt
[i
] == GGO_METRICS
) {
4502 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4503 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4504 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4508 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4509 memset(&gm2
, 0xab, sizeof(gm2
));
4510 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4511 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4516 SelectObject(hdc
, old_hfont
);
4517 DeleteObject(hfont
);
4519 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
4521 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4524 lf
.lfFaceName
[0] = '\0';
4525 lf
.lfCharSet
= c
[i
].cs
;
4526 lf
.lfPitchAndFamily
= 0;
4527 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4529 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4533 old_hfont
= SelectObject(hdc
, hfont
);
4535 /* expected to ignore superfluous bytes (sigle-byte character) */
4536 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4537 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4538 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4540 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4541 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4542 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4544 /* expected to ignore superfluous bytes (double-byte character) */
4545 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4546 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4547 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4548 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4550 /* expected to match wide-char version results */
4551 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4552 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4554 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4556 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4559 DeleteObject(SelectObject(hdc
, hfont
));
4562 DeleteObject(SelectObject(hdc
, old_hfont
));
4566 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4567 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4569 ret
= GetTextMetricsA(hdc
, &tm
);
4570 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4571 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4572 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4573 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4574 -lf
.lfHeight
, tm
.tmAveCharWidth
, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4575 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4576 "expected %d, got %d (%s:%d)\n",
4577 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4579 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4580 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4581 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4582 "expected %d, got %d (%s:%d)\n",
4583 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4586 hfont
= CreateFontIndirectA(&lf
);
4587 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4588 DeleteObject(SelectObject(hdc
, hfont
));
4589 ret
= GetTextMetricsA(hdc
, &tm
);
4590 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4591 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4592 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4593 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4594 "expected %d, got %d (%s:%d)\n",
4595 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4597 lf
.lfItalic
= FALSE
;
4598 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4599 hfont
= CreateFontIndirectA(&lf
);
4600 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4601 DeleteObject(SelectObject(hdc
, hfont
));
4602 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4603 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4604 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4605 "expected %d, got %d (%s:%d)\n",
4606 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4608 hfont
= SelectObject(hdc
, old_hfont
);
4609 DeleteObject(hfont
);
4615 /* bug #9995: there is a limit to the character width that can be specified */
4616 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4622 int ave_width
, height
, width
, ratio
, scale
;
4624 if (!is_truetype_font_installed( fontname
)) {
4625 skip("%s is not installed\n", fontname
);
4628 hdc
= CreateCompatibleDC(0);
4629 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4630 /* select width = 0 */
4631 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4632 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4633 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4635 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4636 of
= SelectObject( hdc
, hf
);
4637 ret
= GetTextMetricsA( hdc
, &tm
);
4638 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4639 height
= tm
.tmHeight
;
4640 ave_width
= tm
.tmAveCharWidth
;
4641 SelectObject( hdc
, of
);
4644 trace("height %d, ave width %d\n", height
, ave_width
);
4646 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4648 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4649 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4650 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4651 ok(hf
!= 0, "CreateFont failed\n");
4652 of
= SelectObject(hdc
, hf
);
4653 ret
= GetTextMetricsA(hdc
, &tm
);
4654 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4655 SelectObject(hdc
, of
);
4658 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4664 ratio
= width
/ height
;
4665 scale
= width
/ ave_width
;
4667 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4668 width
, height
, ratio
, width
, ave_width
, scale
);
4670 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4673 static void test_CreateFontIndirect(void)
4675 LOGFONTA lf
, getobj_lf
;
4678 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4680 memset(&lf
, 0, sizeof(lf
));
4681 lf
.lfCharSet
= ANSI_CHARSET
;
4682 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4685 lf
.lfQuality
= DEFAULT_QUALITY
;
4686 lf
.lfItalic
= FALSE
;
4687 lf
.lfWeight
= FW_DONTCARE
;
4689 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
4691 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4692 hfont
= CreateFontIndirectA(&lf
);
4693 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4694 SetLastError(0xdeadbeef);
4695 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
4696 ok(ret
, "GetObject failed: %d\n", GetLastError());
4697 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
4698 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
4699 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
4700 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
4701 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
4702 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
4703 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
4704 DeleteObject(hfont
);
4708 static void test_CreateFontIndirectEx(void)
4710 ENUMLOGFONTEXDVA lfex
;
4713 if (!pCreateFontIndirectExA
)
4715 win_skip("CreateFontIndirectExA is not available\n");
4719 if (!is_truetype_font_installed("Arial"))
4721 skip("Arial is not installed\n");
4725 SetLastError(0xdeadbeef);
4726 hfont
= pCreateFontIndirectExA(NULL
);
4727 ok(hfont
== NULL
, "got %p\n", hfont
);
4728 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4730 memset(&lfex
, 0, sizeof(lfex
));
4731 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
4732 hfont
= pCreateFontIndirectExA(&lfex
);
4733 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
4735 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
4736 DeleteObject(hfont
);
4739 static void free_font(void *font
)
4741 UnmapViewOfFile(font
);
4744 static void *load_font(const char *font_name
, DWORD
*font_size
)
4746 char file_name
[MAX_PATH
];
4747 HANDLE file
, mapping
;
4750 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
4751 strcat(file_name
, "\\fonts\\");
4752 strcat(file_name
, font_name
);
4754 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
4755 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
4757 *font_size
= GetFileSize(file
, NULL
);
4759 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4766 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
4769 CloseHandle(mapping
);
4773 static void test_AddFontMemResource(void)
4776 DWORD font_size
, num_fonts
;
4780 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
4782 win_skip("AddFontMemResourceEx is not available on this platform\n");
4786 font
= load_font("sserife.fon", &font_size
);
4789 skip("Unable to locate and load font sserife.fon\n");
4793 SetLastError(0xdeadbeef);
4794 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
4795 ok(!ret
, "AddFontMemResourceEx should fail\n");
4796 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4797 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4800 SetLastError(0xdeadbeef);
4801 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
4802 ok(!ret
, "AddFontMemResourceEx should fail\n");
4803 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4804 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4807 SetLastError(0xdeadbeef);
4808 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
4809 ok(!ret
, "AddFontMemResourceEx should fail\n");
4810 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4811 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4814 SetLastError(0xdeadbeef);
4815 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
4816 ok(!ret
, "AddFontMemResourceEx should fail\n");
4817 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4818 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4821 SetLastError(0xdeadbeef);
4822 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
4823 ok(!ret
, "AddFontMemResourceEx should fail\n");
4824 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4825 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4828 SetLastError(0xdeadbeef);
4829 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
4830 ok(!ret
, "AddFontMemResourceEx should fail\n");
4831 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4832 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4835 num_fonts
= 0xdeadbeef;
4836 SetLastError(0xdeadbeef);
4837 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
4838 ok(!ret
, "AddFontMemResourceEx should fail\n");
4839 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4840 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4842 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4844 if (0) /* hangs under windows 2000 */
4846 num_fonts
= 0xdeadbeef;
4847 SetLastError(0xdeadbeef);
4848 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
4849 ok(!ret
, "AddFontMemResourceEx should fail\n");
4850 ok(GetLastError() == 0xdeadbeef,
4851 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4853 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4856 num_fonts
= 0xdeadbeef;
4857 SetLastError(0xdeadbeef);
4858 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
4859 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
4860 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4861 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
4865 SetLastError(0xdeadbeef);
4866 bRet
= pRemoveFontMemResourceEx(ret
);
4867 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
4869 /* test invalid pointer to number of loaded fonts */
4870 font
= load_font("sserife.fon", &font_size
);
4871 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
4873 SetLastError(0xdeadbeef);
4874 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
4875 ok(!ret
, "AddFontMemResourceEx should fail\n");
4876 ok(GetLastError() == 0xdeadbeef,
4877 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4880 SetLastError(0xdeadbeef);
4881 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
4882 ok(!ret
, "AddFontMemResourceEx should fail\n");
4883 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4884 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4890 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4894 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4896 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4898 lf
= (LOGFONTA
*)lparam
;
4903 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4908 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4910 lf
= (LOGFONTA
*)lparam
;
4911 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
4914 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4921 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4926 static void test_EnumFonts(void)
4932 if (!is_truetype_font_installed("Arial"))
4934 skip("Arial is not installed\n");
4938 /* Windows uses localized font face names, so Arial Bold won't be found */
4939 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
4941 skip("User locale is not English, skipping the test\n");
4945 hdc
= CreateCompatibleDC(0);
4947 /* check that the enumproc's retval is returned */
4948 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
4949 ok(ret
== 0xcafe, "got %08x\n", ret
);
4951 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
4952 ok(!ret
, "font Arial is not enumerated\n");
4953 ret
= strcmp(lf
.lfFaceName
, "Arial");
4954 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4955 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4957 strcpy(lf
.lfFaceName
, "Arial");
4958 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4959 ok(!ret
, "font Arial is not enumerated\n");
4960 ret
= strcmp(lf
.lfFaceName
, "Arial");
4961 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4962 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4964 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4965 ok(!ret
, "font Arial Bold is not enumerated\n");
4966 ret
= strcmp(lf
.lfFaceName
, "Arial");
4967 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4968 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4970 strcpy(lf
.lfFaceName
, "Arial Bold");
4971 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4972 ok(ret
, "font Arial Bold should not be enumerated\n");
4974 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
4975 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
4976 ret
= strcmp(lf
.lfFaceName
, "Arial");
4977 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4978 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4980 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
4981 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4982 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
4984 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4985 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4987 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
4988 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4989 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4994 static INT CALLBACK
enum_ms_shell_dlg_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4996 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
4998 if (0) /* Disabled to limit console spam */
4999 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5000 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5002 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5003 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg") != 0) return 1;
5005 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5009 static INT CALLBACK
enum_ms_shell_dlg2_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5011 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5013 if (0) /* Disabled to limit console spam */
5014 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5015 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5017 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5018 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg 2") != 0) return 1;
5020 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5024 static void test_EnumFonts_subst(void)
5029 struct enum_fullname_data efnd
;
5031 ret
= is_font_installed("MS Shell Dlg");
5032 ok(ret
, "MS Shell Dlg should be enumerated\n");
5033 ret
= is_truetype_font_installed("MS Shell Dlg");
5034 ok(ret
, "MS Shell Dlg should be enumerated as a TrueType font\n");
5036 ret
= is_font_installed("MS Shell Dlg 2");
5037 ok(ret
, "MS Shell Dlg 2 should be enumerated\n");
5038 ret
= is_truetype_font_installed("MS Shell Dlg 2");
5039 ok(ret
, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5041 hdc
= CreateCompatibleDC(0);
5043 memset(&efnd
, 0, sizeof(efnd
));
5044 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5045 ok(ret
, "MS Shell Dlg should not be enumerated\n");
5046 ok(!efnd
.total
, "MS Shell Dlg should not be enumerated\n");
5048 memset(&lf
, 0, sizeof(lf
));
5049 lf
.lfCharSet
= DEFAULT_CHARSET
;
5051 memset(&efnd
, 0, sizeof(efnd
));
5052 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
5053 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5054 ok(!ret
, "MS Shell Dlg should be enumerated\n");
5055 ok(efnd
.total
> 0, "MS Shell Dlg should be enumerated\n");
5056 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
5057 ok(!ret
, "expected MS Shell Dlg, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5058 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
5059 ok(ret
, "did not expect MS Shell Dlg\n");
5061 memset(&efnd
, 0, sizeof(efnd
));
5062 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5063 ok(ret
, "MS Shell Dlg 2 should not be enumerated\n");
5064 ok(!efnd
.total
, "MS Shell Dlg 2 should not be enumerated\n");
5066 memset(&efnd
, 0, sizeof(efnd
));
5067 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
5068 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5069 ok(!ret
, "MS Shell Dlg 2 should be enumerated\n");
5070 ok(efnd
.total
> 0, "MS Shell Dlg 2 should be enumerated\n");
5071 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
5072 ok(!ret
, "expected MS Shell Dlg 2, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5073 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
5074 ok(ret
, "did not expect MS Shell Dlg 2\n");
5079 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5081 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
5082 const char *fullname
= (const char *)lParam
;
5084 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
5089 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
5094 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
5101 static void test_fullname(void)
5103 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5104 WCHAR bufW
[LF_FULLFACESIZE
];
5105 char bufA
[LF_FULLFACESIZE
];
5112 hdc
= CreateCompatibleDC(0);
5113 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5115 memset(&lf
, 0, sizeof(lf
));
5116 lf
.lfCharSet
= ANSI_CHARSET
;
5117 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5120 lf
.lfQuality
= DEFAULT_QUALITY
;
5121 lf
.lfItalic
= FALSE
;
5122 lf
.lfWeight
= FW_DONTCARE
;
5124 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
5126 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
5128 skip("%s is not installed\n", TestName
[i
]);
5132 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5133 hfont
= CreateFontIndirectA(&lf
);
5134 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5136 of
= SelectObject(hdc
, hfont
);
5139 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5140 ok(ret
, "face full name could not be read\n");
5141 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
5142 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
5143 SelectObject(hdc
, of
);
5144 DeleteObject(hfont
);
5149 static WCHAR
*prepend_at(WCHAR
*family
)
5154 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
5159 static void test_fullname2_helper(const char *Family
)
5161 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
5162 struct enum_fullname_data efnd
;
5169 DWORD otm_size
, ret
, buf_size
;
5170 OUTLINETEXTMETRICA
*otm
;
5171 BOOL want_vertical
, get_vertical
;
5172 want_vertical
= ( Family
[0] == '@' );
5174 hdc
= CreateCompatibleDC(0);
5175 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5177 memset(&lf
, 0, sizeof(lf
));
5178 lf
.lfCharSet
= DEFAULT_CHARSET
;
5179 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5182 lf
.lfQuality
= DEFAULT_QUALITY
;
5183 lf
.lfItalic
= FALSE
;
5184 lf
.lfWeight
= FW_DONTCARE
;
5185 strcpy(lf
.lfFaceName
, Family
);
5187 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
5188 if (efnd
.total
== 0)
5189 skip("%s is not installed\n", lf
.lfFaceName
);
5191 for (i
= 0; i
< efnd
.total
; i
++)
5193 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
5194 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
5195 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
5197 get_vertical
= ( FamilyName
[0] == '@' );
5198 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
5200 lstrcpyA(lf
.lfFaceName
, FaceName
);
5201 hfont
= CreateFontIndirectA(&lf
);
5202 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5204 of
= SelectObject(hdc
, hfont
);
5205 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
5206 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
5207 if (buf_size
== GDI_ERROR
) continue;
5209 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5210 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5212 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5213 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5214 memset(otm
, 0, otm_size
);
5215 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
5216 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
5217 if (ret
== 0) continue;
5221 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5222 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5223 ok(ret
, "%s: FAMILY (family name) could not be read\n", FamilyName
);
5224 if (want_vertical
) bufW
= prepend_at(bufW
);
5225 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5226 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
5227 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
5228 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
5232 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
5233 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5234 ok(ret
, "FULL_NAME (face name) could not be read\n");
5235 if (want_vertical
) bufW
= prepend_at(bufW
);
5236 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5237 ok(!lstrcmpA(FaceName
, bufA
), "%s: font face names don't match: returned %s, expect %s\n", FamilyName
, FaceName
, bufA
);
5238 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
5239 ok(!lstrcmpA(FaceName
, otmStr
), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName
, FaceName
, otmStr
);
5243 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5244 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5245 ok(ret
, "%s: SUBFAMILY (style name) could not be read\n", FamilyName
);
5246 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5247 ok(!lstrcmpA(StyleName
, bufA
), "%s: style names don't match: returned %s, expect %s\n", FamilyName
, StyleName
, bufA
);
5248 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
5249 ok(!lstrcmpA(StyleName
, otmStr
), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName
, StyleName
, otmStr
);
5253 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
5254 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5255 ok(ret
, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName
);
5256 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5257 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
5258 ok(!lstrcmpA(otmStr
, bufA
), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName
, otmStr
, bufA
);
5260 SelectObject(hdc
, of
);
5261 DeleteObject(hfont
);
5263 HeapFree(GetProcessHeap(), 0, otm
);
5264 HeapFree(GetProcessHeap(), 0, bufW
);
5265 HeapFree(GetProcessHeap(), 0, bufA
);
5270 static void test_fullname2(void)
5272 test_fullname2_helper("Arial");
5273 test_fullname2_helper("DejaVu Sans");
5274 test_fullname2_helper("Lucida Sans");
5275 test_fullname2_helper("Tahoma");
5276 test_fullname2_helper("Webdings");
5277 test_fullname2_helper("Wingdings");
5278 test_fullname2_helper("SimSun");
5279 test_fullname2_helper("NSimSun");
5280 test_fullname2_helper("MingLiu");
5281 test_fullname2_helper("PMingLiu");
5282 test_fullname2_helper("WenQuanYi Micro Hei");
5283 test_fullname2_helper("MS UI Gothic");
5284 test_fullname2_helper("Ume UI Gothic");
5285 test_fullname2_helper("MS Gothic");
5286 test_fullname2_helper("Ume Gothic");
5287 test_fullname2_helper("MS PGothic");
5288 test_fullname2_helper("Ume P Gothic");
5289 test_fullname2_helper("Gulim");
5290 test_fullname2_helper("Batang");
5291 test_fullname2_helper("UnBatang");
5292 test_fullname2_helper("UnDotum");
5293 test_fullname2_helper("@SimSun");
5294 test_fullname2_helper("@NSimSun");
5295 test_fullname2_helper("@MingLiu");
5296 test_fullname2_helper("@PMingLiu");
5297 test_fullname2_helper("@WenQuanYi Micro Hei");
5298 test_fullname2_helper("@MS UI Gothic");
5299 test_fullname2_helper("@Ume UI Gothic");
5300 test_fullname2_helper("@MS Gothic");
5301 test_fullname2_helper("@Ume Gothic");
5302 test_fullname2_helper("@MS PGothic");
5303 test_fullname2_helper("@Ume P Gothic");
5304 test_fullname2_helper("@Gulim");
5305 test_fullname2_helper("@Batang");
5306 test_fullname2_helper("@UnBatang");
5307 test_fullname2_helper("@UnDotum");
5311 static void test_GetGlyphOutline_empty_contour(void)
5315 HFONT hfont
, hfont_prev
;
5316 TTPOLYGONHEADER
*header
;
5321 memset(&lf
, 0, sizeof(lf
));
5323 lstrcpyA(lf
.lfFaceName
, "wine_test");
5325 hfont
= CreateFontIndirectA(&lf
);
5326 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5330 hfont_prev
= SelectObject(hdc
, hfont
);
5331 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5333 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5334 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5336 header
= (TTPOLYGONHEADER
*)buf
;
5337 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5338 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5339 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5340 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5341 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5342 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5343 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5344 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5346 SelectObject(hdc
, hfont_prev
);
5347 DeleteObject(hfont
);
5348 ReleaseDC(NULL
, hdc
);
5351 static void test_GetGlyphOutline_metric_clipping(void)
5355 HFONT hfont
, hfont_prev
;
5361 memset(&lf
, 0, sizeof(lf
));
5363 lstrcpyA(lf
.lfFaceName
, "wine_test");
5365 SetLastError(0xdeadbeef);
5366 hfont
= CreateFontIndirectA(&lf
);
5367 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5371 hfont_prev
= SelectObject(hdc
, hfont
);
5372 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5374 SetLastError(0xdeadbeef);
5375 ret
= GetTextMetricsA(hdc
, &tm
);
5376 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5378 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5379 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5380 "Glyph top(%d) exceeds ascent(%d)\n",
5381 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5382 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5383 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5384 "Glyph bottom(%d) exceeds descent(%d)\n",
5385 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5387 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5388 GetTextMetricsW(hdc
, &tmW
);
5390 ok( tmW
.tmLastChar
== 0xfffe, "got %04x\n", tmW
.tmLastChar
);
5392 SelectObject(hdc
, hfont_prev
);
5393 DeleteObject(hfont
);
5394 ReleaseDC(NULL
, hdc
);
5397 static void test_CreateScalableFontResource(void)
5399 char ttf_name
[MAX_PATH
];
5400 char tmp_path
[MAX_PATH
];
5401 char fot_name
[MAX_PATH
];
5406 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
5408 win_skip("AddFontResourceExA is not available on this platform\n");
5412 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5414 skip("Failed to create ttf file for testing\n");
5418 trace("created %s\n", ttf_name
);
5420 ret
= is_truetype_font_installed("wine_test");
5421 ok(!ret
, "font wine_test should not be enumerated\n");
5423 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
5424 ok(ret
, "GetTempPath() error %d\n", GetLastError());
5425 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
5426 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
5428 ret
= GetFileAttributesA(fot_name
);
5429 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
5431 SetLastError(0xdeadbeef);
5432 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5433 ok(!ret
, "CreateScalableFontResource() should fail\n");
5434 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5436 SetLastError(0xdeadbeef);
5437 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
5438 ok(!ret
, "CreateScalableFontResource() should fail\n");
5439 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5441 file_part
= strrchr(ttf_name
, '\\');
5442 SetLastError(0xdeadbeef);
5443 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
5444 ok(!ret
, "CreateScalableFontResource() should fail\n");
5445 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5447 SetLastError(0xdeadbeef);
5448 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
5449 ok(!ret
, "CreateScalableFontResource() should fail\n");
5450 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5452 SetLastError(0xdeadbeef);
5453 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
5454 ok(!ret
, "CreateScalableFontResource() should fail\n");
5455 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5457 ret
= DeleteFileA(fot_name
);
5458 ok(ret
, "DeleteFile() error %d\n", GetLastError());
5460 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5461 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5463 /* test public font resource */
5464 SetLastError(0xdeadbeef);
5465 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5466 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5468 ret
= is_truetype_font_installed("wine_test");
5469 ok(!ret
, "font wine_test should not be enumerated\n");
5471 SetLastError(0xdeadbeef);
5472 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5473 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5475 ret
= is_truetype_font_installed("wine_test");
5476 ok(ret
, "font wine_test should be enumerated\n");
5478 test_GetGlyphOutline_empty_contour();
5479 test_GetGlyphOutline_metric_clipping();
5481 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5482 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
5484 SetLastError(0xdeadbeef);
5485 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5486 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5488 ret
= is_truetype_font_installed("wine_test");
5489 ok(!ret
, "font wine_test should not be enumerated\n");
5491 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5492 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5494 /* test refcounting */
5495 for (i
= 0; i
< 5; i
++)
5497 SetLastError(0xdeadbeef);
5498 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5499 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5501 for (i
= 0; i
< 5; i
++)
5503 SetLastError(0xdeadbeef);
5504 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5505 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5507 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5508 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5510 DeleteFileA(fot_name
);
5512 /* test hidden font resource */
5513 SetLastError(0xdeadbeef);
5514 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
5515 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5517 ret
= is_truetype_font_installed("wine_test");
5518 ok(!ret
, "font wine_test should not be enumerated\n");
5520 SetLastError(0xdeadbeef);
5521 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5522 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5524 ret
= is_truetype_font_installed("wine_test");
5526 ok(!ret
, "font wine_test should not be enumerated\n");
5528 /* XP allows removing a private font added with 0 flags */
5529 SetLastError(0xdeadbeef);
5530 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5531 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5533 ret
= is_truetype_font_installed("wine_test");
5534 ok(!ret
, "font wine_test should not be enumerated\n");
5536 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5537 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5539 DeleteFileA(fot_name
);
5540 DeleteFileA(ttf_name
);
5543 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
5546 HFONT hfont
, hfont_prev
;
5550 static const WCHAR str
[] = { 0x2025 };
5552 *installed
= is_truetype_font_installed(name
);
5556 lf
.lfEscapement
= 0;
5557 lf
.lfOrientation
= 0;
5558 lf
.lfWeight
= FW_DONTCARE
;
5562 lf
.lfCharSet
= DEFAULT_CHARSET
;
5563 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
5564 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5565 lf
.lfQuality
= DEFAULT_QUALITY
;
5566 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
5567 strcpy(lf
.lfFaceName
, name
);
5569 hfont
= CreateFontIndirectA(&lf
);
5570 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
5574 hfont_prev
= SelectObject(hdc
, hfont
);
5575 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5577 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
5578 ok(ret
, "GetTextFaceA failed\n");
5579 *selected
= !strcmp(facename
, name
);
5581 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
5582 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5584 memset(gm
, 0, sizeof *gm
);
5586 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
5587 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
5589 SelectObject(hdc
, hfont_prev
);
5590 DeleteObject(hfont
);
5591 ReleaseDC(NULL
, hdc
);
5594 static void check_vertical_metrics(const char *face
)
5597 HFONT hfont
, hfont_prev
;
5600 GLYPHMETRICS rgm
, vgm
;
5601 const UINT code
= 0x5EAD, height
= 1000;
5604 OUTLINETEXTMETRICA otm
;
5605 USHORT numOfLongVerMetrics
;
5609 memset(&lf
, 0, sizeof(lf
));
5610 strcpy(lf
.lfFaceName
, face
);
5611 lf
.lfHeight
= -height
;
5612 lf
.lfCharSet
= DEFAULT_CHARSET
;
5613 lf
.lfEscapement
= lf
.lfOrientation
= 900;
5614 hfont
= CreateFontIndirectA(&lf
);
5615 hfont_prev
= SelectObject(hdc
, hfont
);
5616 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
5617 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5618 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
5619 ok(ret
, "GetCharABCWidthsW failed\n");
5620 DeleteObject(SelectObject(hdc
, hfont_prev
));
5622 memset(&lf
, 0, sizeof(lf
));
5623 strcpy(lf
.lfFaceName
, "@");
5624 strcat(lf
.lfFaceName
, face
);
5625 lf
.lfHeight
= -height
;
5626 lf
.lfCharSet
= DEFAULT_CHARSET
;
5627 hfont
= CreateFontIndirectA(&lf
);
5628 hfont_prev
= SelectObject(hdc
, hfont
);
5629 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
5630 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5632 memset(&otm
, 0, sizeof(otm
));
5633 otm
.otmSize
= sizeof(otm
);
5634 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
5635 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
5637 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
5638 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
5640 SHORT topSideBearing
;
5642 if (!pGetGlyphIndicesW
) {
5643 win_skip("GetGlyphIndices is not available on this platform\n");
5646 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
5647 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
5648 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
5649 if (numOfLongVerMetrics
> idx
)
5650 offset
= idx
* 2 + 1;
5652 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
5653 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
5654 &topSideBearing
, sizeof(SHORT
));
5655 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
5656 topSideBearing
= GET_BE_WORD(topSideBearing
);
5657 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
5658 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
5659 "expected %d, got %d\n",
5660 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
5665 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
5666 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5667 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
5670 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
5671 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
5672 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5673 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
5675 DeleteObject(SelectObject(hdc
, hfont_prev
));
5676 ReleaseDC(NULL
, hdc
);
5679 static void test_vertical_font(void)
5681 char ttf_name
[MAX_PATH
];
5683 BOOL ret
, installed
, selected
;
5686 const char* face_list
[] = {
5687 "@WineTestVertical", /* has vmtx table */
5688 "@Ume Gothic", /* doesn't have vmtx table */
5689 "@MS UI Gothic", /* has vmtx table, available on native */
5692 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
5694 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5698 if (!write_ttf_file("vertical.ttf", ttf_name
))
5700 skip("Failed to create ttf file for testing\n");
5704 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5705 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5707 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
5708 ok(installed
, "WineTestVertical is not installed\n");
5709 ok(selected
, "WineTestVertical is not selected\n");
5710 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5711 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5712 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5714 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
5715 ok(installed
, "@WineTestVertical is not installed\n");
5716 ok(selected
, "@WineTestVertical is not selected\n");
5717 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5718 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5719 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5721 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
5723 for (i
= 0; i
< sizeof(face_list
)/sizeof(face_list
[0]); i
++) {
5724 const char* face
= face_list
[i
];
5725 if (!is_truetype_font_installed(face
)) {
5726 skip("%s is not installed\n", face
);
5729 trace("Testing %s...\n", face
);
5730 check_vertical_metrics(&face
[1]);
5733 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5734 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5736 DeleteFileA(ttf_name
);
5739 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
5740 DWORD type
, LPARAM lParam
)
5742 if (lf
->lfFaceName
[0] == '@') {
5748 static void test_east_asian_font_selection(void)
5751 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
5752 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
5757 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
5761 char face_name
[LF_FACESIZE
];
5764 memset(&lf
, 0, sizeof lf
);
5765 lf
.lfFaceName
[0] = '\0';
5766 lf
.lfCharSet
= charset
[i
];
5768 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
5770 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
5774 hfont
= CreateFontIndirectA(&lf
);
5775 hfont
= SelectObject(hdc
, hfont
);
5776 memset(face_name
, 0, sizeof face_name
);
5777 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5778 ok(ret
&& face_name
[0] != '@',
5779 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5780 DeleteObject(SelectObject(hdc
, hfont
));
5782 memset(&lf
, 0, sizeof lf
);
5783 strcpy(lf
.lfFaceName
, "@");
5784 lf
.lfCharSet
= charset
[i
];
5785 hfont
= CreateFontIndirectA(&lf
);
5786 hfont
= SelectObject(hdc
, hfont
);
5787 memset(face_name
, 0, sizeof face_name
);
5788 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5789 ok(ret
&& face_name
[0] == '@',
5790 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5791 DeleteObject(SelectObject(hdc
, hfont
));
5793 ReleaseDC(NULL
, hdc
);
5796 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
5798 HDC hdc
= CreateCompatibleDC(0);
5803 hfont
= CreateFontIndirectA(lf
);
5804 ok(hfont
!= 0, "CreateFontIndirect failed\n");
5806 SelectObject(hdc
, hfont
);
5807 ret
= GetTextMetricsA(hdc
, &tm
);
5808 ok(ret
, "GetTextMetrics failed\n");
5809 ret
= tm
.tmDigitizedAspectX
;
5810 if (height
) *height
= tm
.tmHeight
;
5813 DeleteObject(hfont
);
5818 static void test_stock_fonts(void)
5820 static const int font
[] =
5822 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
5823 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5825 static const struct test_data
5827 int charset
, weight
, height
, height_pixels
, dpi
;
5828 const char face_name
[LF_FACESIZE
];
5832 { /* ANSI_FIXED_FONT */
5833 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_ARABIC
},
5834 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
5835 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
5838 { /* ANSI_VAR_FONT */
5839 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
5840 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
5844 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5845 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5846 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5847 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5848 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5849 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5852 { /* DEVICE_DEFAULT_FONT */
5853 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5854 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5855 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5856 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5857 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5858 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5861 { /* DEFAULT_GUI_FONT */
5862 { SHIFTJIS_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
5863 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
5864 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
5865 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
5866 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
5867 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
5868 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
5869 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
5870 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
5871 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
5872 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
5878 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
5884 hfont
= GetStockObject(font
[i
]);
5885 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
5887 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
5888 if (ret
!= sizeof(lf
))
5891 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
5895 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
5897 if ((lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
) ||
5898 (system_lang_id
!= td
[i
][j
].lang_id
&& td
[i
][j
].lang_id
!= LANG_NEUTRAL
) ||
5899 (td
[i
][j
].face_name
[0] != '?' && strcmp(lf
.lfFaceName
, td
[i
][j
].face_name
)))
5904 ret
= get_font_dpi(&lf
, &height
);
5905 if (ret
!= td
[i
][j
].dpi
)
5907 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5908 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
5912 /* FIXME: Remove once Wine is fixed */
5913 if (td
[i
][j
].dpi
!= 96 &&
5914 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5915 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
5916 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5917 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
5919 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5921 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5923 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
5924 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
5925 if (td
[i
][j
].face_name
[0] == '?')
5927 /* Wine doesn't have this font, skip this case for now.
5928 Actually, the face name is localized on Windows and varies
5929 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5930 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
5934 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
);
5941 static void test_max_height(void)
5945 HFONT hfont
, hfont_old
;
5946 TEXTMETRICA tm1
, tm
;
5948 LONG invalid_height
[] = { -65536, -123456, 123456 };
5951 memset(&tm1
, 0, sizeof(tm1
));
5952 memset(&lf
, 0, sizeof(lf
));
5953 strcpy(lf
.lfFaceName
, "Tahoma");
5958 /* get 1 ppem value */
5959 hfont
= CreateFontIndirectA(&lf
);
5960 hfont_old
= SelectObject(hdc
, hfont
);
5961 r
= GetTextMetricsA(hdc
, &tm1
);
5962 ok(r
, "GetTextMetrics failed\n");
5963 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5964 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5965 DeleteObject(SelectObject(hdc
, hfont_old
));
5967 /* test the largest value */
5968 lf
.lfHeight
= -((1 << 16) - 1);
5969 hfont
= CreateFontIndirectA(&lf
);
5970 hfont_old
= SelectObject(hdc
, hfont
);
5971 memset(&tm
, 0, sizeof(tm
));
5972 r
= GetTextMetricsA(hdc
, &tm
);
5973 ok(r
, "GetTextMetrics failed\n");
5974 ok(tm
.tmHeight
> tm1
.tmHeight
,
5975 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5976 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
5977 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5978 DeleteObject(SelectObject(hdc
, hfont_old
));
5980 /* test an invalid value */
5981 for (i
= 0; i
< sizeof(invalid_height
)/sizeof(invalid_height
[0]); i
++) {
5982 lf
.lfHeight
= invalid_height
[i
];
5983 hfont
= CreateFontIndirectA(&lf
);
5984 hfont_old
= SelectObject(hdc
, hfont
);
5985 memset(&tm
, 0, sizeof(tm
));
5986 r
= GetTextMetricsA(hdc
, &tm
);
5987 ok(r
, "GetTextMetrics failed\n");
5988 ok(tm
.tmHeight
== tm1
.tmHeight
,
5989 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5990 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
5991 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5992 DeleteObject(SelectObject(hdc
, hfont_old
));
5995 ReleaseDC(NULL
, hdc
);
5999 static void test_vertical_order(void)
6001 struct enum_font_data efd
;
6006 hdc
= CreateCompatibleDC(0);
6007 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6009 memset(&lf
, 0, sizeof(lf
));
6010 lf
.lfCharSet
= DEFAULT_CHARSET
;
6011 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6014 lf
.lfQuality
= DEFAULT_QUALITY
;
6015 lf
.lfItalic
= FALSE
;
6016 lf
.lfWeight
= FW_DONTCARE
;
6018 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
6019 for (i
= 0; i
< efd
.total
; i
++)
6021 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
6022 for (j
= 0; j
< efd
.total
; j
++)
6024 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
6026 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
6034 static void test_GetCharWidth32(void)
6044 if (!pGetCharWidth32A
|| !pGetCharWidth32W
)
6046 win_skip("GetCharWidth32A/W not available on this platform\n");
6050 memset(&lf
, 0, sizeof(lf
));
6051 strcpy(lf
.lfFaceName
, "System");
6054 hfont
= CreateFontIndirectA(&lf
);
6056 hfont
= SelectObject(hdc
, hfont
);
6058 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6059 ok(ret
, "GetCharWidth32W should have succeeded\n");
6060 ret
= pGetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
6061 ok(ret
, "GetCharWidth32A should have succeeded\n");
6062 ok (bufferA
== bufferW
, "Widths should be the same\n");
6063 ok (bufferA
> 0," Width should be greater than zero\n");
6065 hfont
= SelectObject(hdc
, hfont
);
6066 DeleteObject(hfont
);
6067 ReleaseDC(NULL
, hdc
);
6069 memset(&lf
, 0, sizeof(lf
));
6070 strcpy(lf
.lfFaceName
, "Tahoma");
6073 hfont
= CreateFontIndirectA(&lf
);
6074 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
6077 SetMapMode( hdc
, MM_ANISOTROPIC
);
6078 SelectObject(hdc
, hfont
);
6080 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6081 ok(ret
, "GetCharWidth32W should have succeeded\n");
6082 ok (bufferW
> 0," Width should be greater than zero\n");
6083 SetWindowExtEx(hdc
, -1,-1,NULL
);
6084 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6085 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6086 ok(ret
, "GetCharWidth32W should have succeeded\n");
6087 ok (bufferW
> 0," Width should be greater than zero\n");
6088 SetGraphicsMode(hdc
, GM_ADVANCED
);
6089 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6090 ok(ret
, "GetCharWidth32W should have succeeded\n");
6091 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
6092 SetWindowExtEx(hdc
, 1,1,NULL
);
6093 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6094 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6095 ok(ret
, "GetCharWidth32W should have succeeded\n");
6096 ok (bufferW
> 0," Width should be greater than zero\n");
6097 SetGraphicsMode(hdc
, GM_ADVANCED
);
6098 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6099 ok(ret
, "GetCharWidth32W should have succeeded\n");
6100 ok (bufferW
> 0," Width should be greater than zero\n");
6102 ReleaseDC(hwnd
, hdc
);
6103 DestroyWindow(hwnd
);
6105 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
6108 SetMapMode( hdc
, MM_ANISOTROPIC
);
6109 SelectObject(hdc
, hfont
);
6111 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6112 ok(ret
, "GetCharWidth32W should have succeeded\n");
6113 ok (bufferW
> 0," Width should be greater than zero\n");
6114 SetWindowExtEx(hdc
, -1,-1,NULL
);
6115 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6116 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6117 ok(ret
, "GetCharWidth32W should have succeeded\n");
6118 ok (bufferW
> 0," Width should be greater than zero\n");
6119 SetGraphicsMode(hdc
, GM_ADVANCED
);
6120 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6121 ok(ret
, "GetCharWidth32W should have succeeded\n");
6122 ok (bufferW
> 0," Width should be greater than zero\n");
6123 SetWindowExtEx(hdc
, 1,1,NULL
);
6124 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6125 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6126 ok(ret
, "GetCharWidth32W should have succeeded\n");
6127 ok (bufferW
> 0," Width should be greater than zero\n");
6128 SetGraphicsMode(hdc
, GM_ADVANCED
);
6129 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6130 ok(ret
, "GetCharWidth32W should have succeeded\n");
6131 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
6133 ReleaseDC(hwnd
, hdc
);
6134 DestroyWindow(hwnd
);
6135 DeleteObject(hfont
);
6138 static void test_fake_bold_font(void)
6141 HFONT hfont
, hfont_old
;
6148 if (!pGetCharWidth32A
|| !pGetCharABCWidthsA
) {
6149 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
6153 /* Test outline font */
6154 memset(&lf
, 0, sizeof(lf
));
6155 strcpy(lf
.lfFaceName
, "Wingdings");
6156 lf
.lfWeight
= FW_NORMAL
;
6157 lf
.lfCharSet
= SYMBOL_CHARSET
;
6158 hfont
= CreateFontIndirectA(&lf
);
6161 hfont_old
= SelectObject(hdc
, hfont
);
6164 ret
= GetTextMetricsA(hdc
, &tm
[0]);
6165 ok(ret
, "got %d\n", ret
);
6166 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[0]);
6167 ok(ret
, "got %d\n", ret
);
6169 lf
.lfWeight
= FW_BOLD
;
6170 hfont
= CreateFontIndirectA(&lf
);
6171 DeleteObject(SelectObject(hdc
, hfont
));
6174 ret
= GetTextMetricsA(hdc
, &tm
[1]);
6175 ok(ret
, "got %d\n", ret
);
6176 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[1]);
6177 ok(ret
, "got %d\n", ret
);
6179 DeleteObject(SelectObject(hdc
, hfont_old
));
6180 ReleaseDC(NULL
, hdc
);
6182 /* compare results (outline) */
6183 ok(tm
[0].tmHeight
== tm
[1].tmHeight
, "expected %d, got %d\n", tm
[0].tmHeight
, tm
[1].tmHeight
);
6184 ok(tm
[0].tmAscent
== tm
[1].tmAscent
, "expected %d, got %d\n", tm
[0].tmAscent
, tm
[1].tmAscent
);
6185 ok(tm
[0].tmDescent
== tm
[1].tmDescent
, "expected %d, got %d\n", tm
[0].tmDescent
, tm
[1].tmDescent
);
6186 ok((tm
[0].tmAveCharWidth
+ 1) == tm
[1].tmAveCharWidth
,
6187 "expected %d, got %d\n", tm
[0].tmAveCharWidth
+ 1, tm
[1].tmAveCharWidth
);
6188 ok((tm
[0].tmMaxCharWidth
+ 1) == tm
[1].tmMaxCharWidth
,
6189 "expected %d, got %d\n", tm
[0].tmMaxCharWidth
+ 1, tm
[1].tmMaxCharWidth
);
6190 ok(tm
[0].tmOverhang
== tm
[1].tmOverhang
, "expected %d, got %d\n", tm
[0].tmOverhang
, tm
[1].tmOverhang
);
6191 w
[0] = abc
[0].abcA
+ abc
[0].abcB
+ abc
[0].abcC
;
6192 w
[1] = abc
[1].abcA
+ abc
[1].abcB
+ abc
[1].abcC
;
6193 ok((w
[0] + 1) == w
[1], "expected %d, got %d\n", w
[0] + 1, w
[1]);
6197 static void test_bitmap_font_glyph_index(void)
6199 const WCHAR text
[] = {'#','!','/','b','i','n','/','s','h',0};
6203 } bitmap_font_list
[] = {
6204 { "Courier", ANSI_CHARSET
},
6205 { "Small Fonts", ANSI_CHARSET
},
6206 { "Fixedsys", DEFAULT_CHARSET
},
6207 { "System", DEFAULT_CHARSET
}
6212 CHAR facename
[LF_FACESIZE
];
6223 if (!pGetGlyphIndicesW
|| !pGetGlyphIndicesA
) {
6224 win_skip("GetGlyphIndices is unavailable\n");
6228 hdc
= CreateCompatibleDC(0);
6229 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6231 memset(&bmi
, 0, sizeof(bmi
));
6232 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
6233 bmi
.bmiHeader
.biBitCount
= 32;
6234 bmi
.bmiHeader
.biPlanes
= 1;
6235 bmi
.bmiHeader
.biWidth
= 128;
6236 bmi
.bmiHeader
.biHeight
= 32;
6237 bmi
.bmiHeader
.biCompression
= BI_RGB
;
6239 for (i
= 0; i
< sizeof(bitmap_font_list
)/sizeof(bitmap_font_list
[0]); i
++) {
6240 memset(&lf
, 0, sizeof(lf
));
6241 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
6242 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
6243 hFont
= CreateFontIndirectA(&lf
);
6244 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
6245 hFont
= SelectObject(hdc
, hFont
);
6246 ret
= GetTextMetricsA(hdc
, &tm
);
6247 ok(ret
, "GetTextMetric failed\n");
6248 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
6249 ok(ret
, "GetTextFace failed\n");
6250 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
6251 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
6254 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
6255 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
6259 for (j
= 0; j
< 2; j
++) {
6261 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
6262 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
6263 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6266 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
6270 int len
= lstrlenW(text
);
6271 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
6272 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
6273 ok(ret
, "GetGlyphIndices failed\n");
6274 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
6275 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
6276 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
6277 HeapFree(GetProcessHeap(), 0, indices
);
6281 ok(ret
, "ExtTextOutW failed\n");
6282 SelectObject(hdc
, hBmpPrev
);
6285 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
6286 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6287 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6289 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
6291 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6294 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
6295 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
6299 for (j
= 0; j
< 2; j
++) {
6302 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6305 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6308 ret
= pGetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6309 ok(ret
, "GetGlyphIndices failed\n");
6310 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6311 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6314 ok(ret
, "ExtTextOutA failed\n");
6315 SelectObject(hdc
, hBmpPrev
);
6318 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6319 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6321 for (j
= 0; j
< 2; j
++)
6322 DeleteObject(hBmp
[j
]);
6323 hFont
= SelectObject(hdc
, hFont
);
6324 DeleteObject(hFont
);
6337 test_outline_font();
6338 test_bitmap_font_metrics();
6339 test_GdiGetCharDimensions();
6340 test_GetCharABCWidths();
6341 test_text_extents();
6342 test_GetGlyphIndices();
6343 test_GetKerningPairs();
6344 test_GetOutlineTextMetrics();
6345 test_SetTextJustification();
6346 test_font_charset();
6347 test_GdiGetCodePage();
6348 test_GetFontUnicodeRanges();
6349 test_nonexistent_font();
6351 test_height_selection();
6352 test_AddFontMemResource();
6354 test_EnumFonts_subst();
6356 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6357 * I'd like to avoid them in this test.
6359 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
6360 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
6361 if (is_truetype_font_installed("Arial Black") &&
6362 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6364 test_EnumFontFamilies("", ANSI_CHARSET
);
6365 test_EnumFontFamilies("", SYMBOL_CHARSET
);
6366 test_EnumFontFamilies("", DEFAULT_CHARSET
);
6369 skip("Arial Black or Symbol/Wingdings is not installed\n");
6370 test_EnumFontFamiliesEx_default_charset();
6371 test_GetTextMetrics();
6372 test_GdiRealizationInfo();
6374 test_GetGlyphOutline();
6375 test_GetTextMetrics2("Tahoma", -11);
6376 test_GetTextMetrics2("Tahoma", -55);
6377 test_GetTextMetrics2("Tahoma", -110);
6378 test_GetTextMetrics2("Arial", -11);
6379 test_GetTextMetrics2("Arial", -55);
6380 test_GetTextMetrics2("Arial", -110);
6381 test_CreateFontIndirect();
6382 test_CreateFontIndirectEx();
6386 test_east_asian_font_selection();
6388 test_vertical_order();
6389 test_GetCharWidth32();
6390 test_fake_bold_font();
6391 test_bitmap_font_glyph_index();
6393 /* These tests should be last test until RemoveFontResource
6394 * is properly implemented.
6396 test_vertical_font();
6397 test_CreateScalableFontResource();