2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b, exact) (abs((a) - (b)) <= ((exact) ? 0 : 1))
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
40 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
41 static BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
42 static BOOL (WINAPI
*pGetCharABCWidthsA
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
43 static BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
44 static BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
45 static BOOL (WINAPI
*pGetCharWidth32A
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
46 static BOOL (WINAPI
*pGetCharWidth32W
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
47 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
48 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
49 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
50 static BOOL (WINAPI
*pGetTextExtentExPointI
)(HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
51 LPINT nfit
, LPINT dxs
, LPSIZE size
);
52 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
53 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDVA
*);
54 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
55 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
56 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
57 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
59 static HMODULE hgdi32
= 0;
60 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
61 static WORD system_lang_id
;
63 #ifdef WORDS_BIGENDIAN
64 #define GET_BE_WORD(x) (x)
65 #define GET_BE_DWORD(x) (x)
67 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
68 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
71 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
72 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
73 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
74 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
75 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
76 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
78 static void init(void)
80 hgdi32
= GetModuleHandleA("gdi32.dll");
82 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
83 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
84 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
85 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
86 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
87 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
88 pGetCharWidth32A
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32A");
89 pGetCharWidth32W
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32W");
90 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
91 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
92 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
93 pGetTextExtentExPointI
= (void *)GetProcAddress(hgdi32
, "GetTextExtentExPointI");
94 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
95 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
96 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
97 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
98 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
99 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
101 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
104 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
106 if (type
!= TRUETYPE_FONTTYPE
) return 1;
111 static BOOL
is_truetype_font_installed(const char *name
)
116 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
123 static INT CALLBACK
is_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
128 static BOOL
is_font_installed(const char *name
)
133 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
140 static void *get_res_data(const char *fontname
, DWORD
*rsrc_size
)
145 rsrc
= FindResourceA(GetModuleHandleA(NULL
), fontname
, (LPCSTR
)RT_RCDATA
);
146 if (!rsrc
) return NULL
;
148 rsrc_data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
149 if (!rsrc_data
) return NULL
;
151 *rsrc_size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
152 if (!*rsrc_size
) return NULL
;
157 static BOOL
write_tmp_file( const void *data
, DWORD
*size
, char *tmp_name
)
159 char tmp_path
[MAX_PATH
];
163 GetTempPathA(MAX_PATH
, tmp_path
);
164 GetTempFileNameA(tmp_path
, "ttf", 0, tmp_name
);
166 hfile
= CreateFileA(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
167 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
169 ret
= WriteFile(hfile
, data
, *size
, size
, NULL
);
175 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
180 rsrc_data
= get_res_data( fontname
, &rsrc_size
);
181 if (!rsrc_data
) return FALSE
;
183 return write_tmp_file( rsrc_data
, &rsrc_size
, tmp_name
);
186 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
194 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
195 /* NT4 tries to be clever and only returns the minimum length */
196 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
198 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
199 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
200 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
201 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
202 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
203 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
204 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
205 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
206 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
207 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
208 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
209 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
210 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
211 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
212 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
213 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
214 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
215 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
216 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
217 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
218 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
219 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
220 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
221 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
222 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
223 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
224 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
225 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
228 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
230 HFONT hfont
= CreateFontIndirectA(lf
);
231 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
233 check_font(test
, lf
, hfont
);
237 static void test_logfont(void)
242 memset(&lf
, 0, sizeof lf
);
244 lf
.lfCharSet
= ANSI_CHARSET
;
245 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
246 lf
.lfWeight
= FW_DONTCARE
;
249 lf
.lfQuality
= DEFAULT_QUALITY
;
251 lstrcpyA(lf
.lfFaceName
, "Arial");
252 hfont
= create_font("Arial", &lf
);
255 memset(&lf
, 'A', sizeof(lf
));
256 hfont
= CreateFontIndirectA(&lf
);
257 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
259 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
260 check_font("AAA...", &lf
, hfont
);
264 static INT CALLBACK
font_enum_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
266 if (type
& RASTER_FONTTYPE
)
268 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
270 return 0; /* stop enumeration */
273 return 1; /* continue enumeration */
276 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
278 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
279 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
280 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
281 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
282 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
283 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
284 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
285 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
286 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
287 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
288 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
289 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
290 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
291 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
292 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
293 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
294 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
295 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
296 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
297 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
300 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
301 LONG lfWidth
, const char *test_str
,
302 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
303 const SIZE
*size_orig
, INT width_of_A_orig
,
304 INT scale_x
, INT scale_y
)
307 OUTLINETEXTMETRICA otm
;
310 INT width_of_A
, cx
, cy
;
316 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
318 GetObjectA(hfont
, sizeof(lf
), &lf
);
320 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
322 otm
.otmSize
= sizeof(otm
) / 2;
323 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
324 ok(ret
== sizeof(otm
)/2 /* XP */ ||
325 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
327 memset(&otm
, 0x1, sizeof(otm
));
328 otm
.otmSize
= sizeof(otm
);
329 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
330 ok(ret
== sizeof(otm
) /* XP */ ||
331 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
333 memset(&tm
, 0x2, sizeof(tm
));
334 ret
= GetTextMetricsA(hdc
, &tm
);
335 ok(ret
, "GetTextMetricsA failed\n");
336 /* the structure size is aligned */
337 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
339 ok(0, "tm != otm\n");
340 compare_tm(&tm
, &otm
.otmTextMetrics
);
343 tm
= otm
.otmTextMetrics
;
344 if (0) /* these metrics are scaled too, but with rounding errors */
346 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
347 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
349 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
350 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
351 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
352 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
353 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
354 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
358 ret
= GetTextMetricsA(hdc
, &tm
);
359 ok(ret
, "GetTextMetricsA failed\n");
362 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
363 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
364 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
365 lfHeight
, scale_x
, scale_y
, cx
, cy
);
366 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
367 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
368 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
369 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
370 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
372 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
376 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
379 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
381 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
383 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
384 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
386 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
388 ok(near_match(width_of_A
, width_of_A_orig
* scale_x
), "width A %d != %d\n", width_of_A
, width_of_A_orig
* scale_x
);
391 /* Test how GDI scales bitmap font metrics */
392 static void test_bitmap_font(void)
394 static const char test_str
[11] = "Test String";
397 HFONT hfont
, old_hfont
;
400 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
402 hdc
= CreateCompatibleDC(0);
404 /* "System" has only 1 pixel size defined, otherwise the test breaks */
405 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
409 trace("no bitmap fonts were found, skipping the test\n");
413 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
415 height_orig
= bitmap_lf
.lfHeight
;
416 lfWidth
= bitmap_lf
.lfWidth
;
418 hfont
= create_font("bitmap", &bitmap_lf
);
419 old_hfont
= SelectObject(hdc
, hfont
);
420 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
421 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
422 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
423 SelectObject(hdc
, old_hfont
);
426 bitmap_lf
.lfHeight
= 0;
427 bitmap_lf
.lfWidth
= 4;
428 hfont
= create_font("bitmap", &bitmap_lf
);
429 old_hfont
= SelectObject(hdc
, hfont
);
430 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
431 SelectObject(hdc
, old_hfont
);
434 bitmap_lf
.lfHeight
= height_orig
;
435 bitmap_lf
.lfWidth
= lfWidth
;
437 /* test fractional scaling */
438 for (i
= 1; i
<= height_orig
* 6; i
++)
442 bitmap_lf
.lfHeight
= i
;
443 hfont
= create_font("fractional", &bitmap_lf
);
444 scale
= (i
+ height_orig
- 1) / height_orig
;
445 nearest_height
= scale
* height_orig
;
446 /* Only jump to the next height if the difference <= 25% original height */
447 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
448 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
449 so we'll not test this particular height. */
450 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
451 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
452 old_hfont
= SelectObject(hdc
, hfont
);
453 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
454 SelectObject(hdc
, old_hfont
);
458 /* test integer scaling 3x2 */
459 bitmap_lf
.lfHeight
= height_orig
* 2;
460 bitmap_lf
.lfWidth
*= 3;
461 hfont
= create_font("3x2", &bitmap_lf
);
462 old_hfont
= SelectObject(hdc
, hfont
);
463 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
464 SelectObject(hdc
, old_hfont
);
467 /* test integer scaling 3x3 */
468 bitmap_lf
.lfHeight
= height_orig
* 3;
469 bitmap_lf
.lfWidth
= 0;
470 hfont
= create_font("3x3", &bitmap_lf
);
471 old_hfont
= SelectObject(hdc
, hfont
);
472 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
473 SelectObject(hdc
, old_hfont
);
479 /* Test how GDI scales outline font metrics */
480 static void test_outline_font(void)
482 static const char test_str
[11] = "Test String";
485 HFONT hfont
, old_hfont
, old_hfont_2
;
486 OUTLINETEXTMETRICA otm
;
488 INT width_orig
, height_orig
, lfWidth
;
491 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
495 if (!is_truetype_font_installed("Arial"))
497 skip("Arial is not installed\n");
501 hdc
= CreateCompatibleDC(0);
503 memset(&lf
, 0, sizeof(lf
));
504 strcpy(lf
.lfFaceName
, "Arial");
506 hfont
= create_font("outline", &lf
);
507 old_hfont
= SelectObject(hdc
, hfont
);
508 otm
.otmSize
= sizeof(otm
);
509 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
510 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
511 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
513 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
514 SelectObject(hdc
, old_hfont
);
517 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
518 lf
.lfHeight
= otm
.otmEMSquare
;
519 lf
.lfHeight
= -lf
.lfHeight
;
520 hfont
= create_font("outline", &lf
);
521 old_hfont
= SelectObject(hdc
, hfont
);
522 otm
.otmSize
= sizeof(otm
);
523 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
524 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
525 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
526 SelectObject(hdc
, old_hfont
);
529 height_orig
= otm
.otmTextMetrics
.tmHeight
;
530 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
532 /* test integer scaling 3x2 */
533 lf
.lfHeight
= height_orig
* 2;
534 lf
.lfWidth
= lfWidth
* 3;
535 hfont
= create_font("3x2", &lf
);
536 old_hfont
= SelectObject(hdc
, hfont
);
537 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
538 SelectObject(hdc
, old_hfont
);
541 /* test integer scaling 3x3 */
542 lf
.lfHeight
= height_orig
* 3;
543 lf
.lfWidth
= lfWidth
* 3;
544 hfont
= create_font("3x3", &lf
);
545 old_hfont
= SelectObject(hdc
, hfont
);
546 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
547 SelectObject(hdc
, old_hfont
);
550 /* test integer scaling 1x1 */
551 lf
.lfHeight
= height_orig
* 1;
552 lf
.lfWidth
= lfWidth
* 1;
553 hfont
= create_font("1x1", &lf
);
554 old_hfont
= SelectObject(hdc
, hfont
);
555 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
556 SelectObject(hdc
, old_hfont
);
559 /* test integer scaling 1x1 */
560 lf
.lfHeight
= height_orig
;
562 hfont
= create_font("1x1", &lf
);
563 old_hfont
= SelectObject(hdc
, hfont
);
564 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
566 /* with an identity matrix */
567 memset(&gm
, 0, sizeof(gm
));
568 SetLastError(0xdeadbeef);
569 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
570 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
571 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
572 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
573 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
574 /* with a custom matrix */
575 memset(&gm
, 0, sizeof(gm
));
576 SetLastError(0xdeadbeef);
577 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
578 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
579 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
580 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
581 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
587 hdc_2
= CreateCompatibleDC(0);
588 old_hfont_2
= SelectObject(hdc_2
, hfont
);
589 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
591 SetMapMode(hdc
, MM_ANISOTROPIC
);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc
, 100, 100, NULL
);
601 SetViewportExtEx(hdc
, 50, 100, NULL
);
602 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc
, 100, 200, NULL
);
611 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc
, MM_TEXT
);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
621 SelectObject(hdc_2
, old_hfont_2
);
624 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
626 SelectObject(hdc
, old_hfont
);
629 skip("GM_ADVANCED is not supported on this platform\n");
640 SetLastError(0xdeadbeef);
641 ret
= SetWorldTransform(hdc
, &xform
);
642 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
646 /* with an identity matrix */
647 memset(&gm
, 0, sizeof(gm
));
648 SetLastError(0xdeadbeef);
649 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
650 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
651 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
652 pt
.x
= width_orig
; pt
.y
= 0;
654 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
655 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
656 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
657 /* with a custom matrix */
658 memset(&gm
, 0, sizeof(gm
));
659 SetLastError(0xdeadbeef);
660 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
661 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
662 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
663 pt
.x
= width_orig
; pt
.y
= 0;
665 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
666 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
667 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
669 SetLastError(0xdeadbeef);
670 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
671 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
673 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
675 /* with an identity matrix */
676 memset(&gm
, 0, sizeof(gm
));
677 SetLastError(0xdeadbeef);
678 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
679 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
680 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
681 pt
.x
= width_orig
; pt
.y
= 0;
683 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
684 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
685 /* with a custom matrix */
686 memset(&gm
, 0, sizeof(gm
));
687 SetLastError(0xdeadbeef);
688 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
689 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
690 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
691 pt
.x
= width_orig
; pt
.y
= 0;
693 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
694 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
696 SetLastError(0xdeadbeef);
697 ret
= SetMapMode(hdc
, MM_TEXT
);
698 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
700 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
702 /* with an identity matrix */
703 memset(&gm
, 0, sizeof(gm
));
704 SetLastError(0xdeadbeef);
705 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
706 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
707 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
708 pt
.x
= width_orig
; pt
.y
= 0;
710 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
711 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
712 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
713 /* with a custom matrix */
714 memset(&gm
, 0, sizeof(gm
));
715 SetLastError(0xdeadbeef);
716 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
717 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
718 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
719 pt
.x
= width_orig
; pt
.y
= 0;
721 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
722 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
723 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
725 SelectObject(hdc
, old_hfont
);
730 static INT CALLBACK
find_font_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
732 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
734 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
737 return 0; /* stop enumeration */
739 return 1; /* continue enumeration */
742 static BOOL
is_CJK(void)
744 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
747 #define FH_SCALE 0x80000000
748 static void test_bitmap_font_metrics(void)
750 static const struct font_data
752 const char face_name
[LF_FACESIZE
];
753 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
754 int ave_char_width
, max_char_width
, dpi
;
755 BYTE first_char
, last_char
, def_char
, break_char
;
761 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
762 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
763 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
764 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
765 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
766 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
767 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
768 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
769 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 16 },
770 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
772 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
773 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
774 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
775 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
776 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
777 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
778 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
779 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
780 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, 0, 16 },
781 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
783 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
784 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
785 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
786 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
787 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
788 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
789 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
790 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
791 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
792 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
793 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
794 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
795 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
796 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
797 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
798 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
800 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
801 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
802 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
803 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
804 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
805 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
806 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
807 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
808 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
809 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
810 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
811 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
813 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
814 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
815 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
816 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
817 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
818 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
819 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
820 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
821 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
822 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
823 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
824 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
825 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
826 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
827 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
828 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
829 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
831 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
832 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
833 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
834 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
835 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
836 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
837 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
838 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
839 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
840 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
841 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
843 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
844 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
845 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
847 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
848 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
849 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
851 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
852 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
853 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
855 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
856 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
858 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
859 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
860 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
861 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
862 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
863 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
864 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
865 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
866 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
867 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
868 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
869 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
870 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
871 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
872 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
873 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
874 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
875 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
876 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
877 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
878 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
880 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
881 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
882 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
883 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
884 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
885 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
886 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
887 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
888 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
889 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
890 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
891 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
893 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
894 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
895 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
897 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
899 /* FIXME: add "Terminal" */
901 static const int font_log_pixels
[] = { 96, 120 };
904 HFONT hfont
, old_hfont
;
906 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
907 char face_name
[LF_FACESIZE
];
910 trace("system language id %04x\n", system_lang_id
);
912 expected_cs
= GetACP();
913 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
915 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
918 expected_cs
= csi
.ciCharset
;
919 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
921 hdc
= CreateCompatibleDC(0);
924 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
925 GetDeviceCaps(hdc
, LOGPIXELSY
));
927 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
930 for (i
= 0; i
< sizeof(font_log_pixels
)/sizeof(font_log_pixels
[0]); i
++)
932 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
936 font_res
= font_log_pixels
[i
];
939 trace("best font resolution is %d\n", font_res
);
941 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
945 memset(&lf
, 0, sizeof(lf
));
947 height
= fd
[i
].height
& ~FH_SCALE
;
948 lf
.lfHeight
= height
;
949 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
951 for(bit
= 0; bit
< 32; bit
++)
959 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
960 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
962 lf
.lfCharSet
= csi
.ciCharset
;
963 trace("looking for %s height %d charset %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
964 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
965 if (fd
[i
].height
& FH_SCALE
)
966 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
969 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
971 if (ret
) /* FIXME: Remove once Wine is fixed */
972 todo_wine
ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
974 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
977 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
980 hfont
= create_font(lf
.lfFaceName
, &lf
);
981 old_hfont
= SelectObject(hdc
, hfont
);
983 SetLastError(0xdeadbeef);
984 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
985 ok(ret
, "GetTextFace error %u\n", GetLastError());
987 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
989 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
990 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
991 trace("Skipping replacement %s height %d charset %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
);
992 SelectObject(hdc
, old_hfont
);
997 memset(&gm
, 0, sizeof(gm
));
998 SetLastError(0xdeadbeef);
999 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1001 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
1002 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1005 bRet
= GetTextMetricsA(hdc
, &tm
);
1006 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
1008 SetLastError(0xdeadbeef);
1009 ret
= GetTextCharset(hdc
);
1010 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1011 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1013 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1015 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
1016 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
1018 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1020 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1021 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
1023 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1024 if (fd
[i
].height
& FH_SCALE
)
1025 ok(tm
.tmHeight
== fd
[i
].scaled_height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmHeight
, fd
[i
].scaled_height
);
1027 ok(tm
.tmHeight
== fd
[i
].height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmHeight
, fd
[i
].height
);
1028 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1029 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1030 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1031 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1032 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
1033 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1034 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1035 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1036 make default char test fail */
1037 if (tm
.tmCharSet
== lf
.lfCharSet
)
1038 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1039 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1040 ok(tm
.tmCharSet
== expected_cs
|| tm
.tmCharSet
== ANSI_CHARSET
, "%s(%d): tm.tmCharSet %d != %d\n", fd
[i
].face_name
, height
, tm
.tmCharSet
, expected_cs
);
1042 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1043 that make the max width bigger */
1044 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1045 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
1048 skip("Skipping font metrics test for system langid 0x%x\n",
1051 SelectObject(hdc
, old_hfont
);
1052 DeleteObject(hfont
);
1059 static void test_GdiGetCharDimensions(void)
1065 LONG avgwidth
, height
;
1066 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1068 if (!pGdiGetCharDimensions
)
1070 win_skip("GdiGetCharDimensions not available on this platform\n");
1074 hdc
= CreateCompatibleDC(NULL
);
1076 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1077 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1079 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1080 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1081 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1083 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1084 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1086 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1087 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1090 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1091 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1092 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1097 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1098 const TEXTMETRICA
*lpntme
,
1099 DWORD FontType
, LPARAM lParam
)
1101 if (FontType
& TRUETYPE_FONTTYPE
)
1105 hfont
= CreateFontIndirectA(lpelfe
);
1108 *(HFONT
*)lParam
= hfont
;
1116 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, ABC
*base_abci
, ABC
*base_abcw
, ABCFLOAT
*base_abcf
, INT todo
)
1122 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1123 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1124 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1125 if (todo
) todo_wine
ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1126 else ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1127 if (todo
) todo_wine
ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1128 else ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1130 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1131 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1132 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1133 if (todo
) todo_wine
ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1134 else ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1135 if (todo
) todo_wine
ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1136 else ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's should be unchanged\n", description
);
1138 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1139 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1140 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1141 if (todo
) todo_wine
ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1142 else ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's should be unchanged\n", description
);
1143 if (todo
) todo_wine
ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1144 else ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1147 static void test_GetCharABCWidths(void)
1149 static const WCHAR str
[] = {'i',0};
1173 {0xffffff, 0xffffff},
1174 {0x1000000, 0x1000000},
1175 {0xffffff, 0x1000000},
1176 {0xffffffff, 0xffffffff},
1184 BOOL r
[sizeof range
/ sizeof range
[0]];
1187 {ANSI_CHARSET
, 0x30, 0x30,
1188 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1189 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1190 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1191 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1192 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1193 {GB2312_CHARSET
, 0x8141, 0x4e04,
1194 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1195 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1196 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1200 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1202 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1206 memset(&lf
, 0, sizeof(lf
));
1207 strcpy(lf
.lfFaceName
, "System");
1210 hfont
= CreateFontIndirectA(&lf
);
1212 hfont
= SelectObject(hdc
, hfont
);
1214 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1215 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1217 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1218 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1220 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1221 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1223 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1224 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1226 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1227 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1229 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1230 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1232 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1233 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1235 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1236 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1238 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1239 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1241 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1242 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1244 hfont
= SelectObject(hdc
, hfont
);
1245 DeleteObject(hfont
);
1247 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1251 UINT code
= 0x41, j
;
1253 lf
.lfFaceName
[0] = '\0';
1254 lf
.lfCharSet
= c
[i
].cs
;
1255 lf
.lfPitchAndFamily
= 0;
1256 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1258 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1262 memset(a
, 0, sizeof a
);
1263 memset(w
, 0, sizeof w
);
1264 hfont
= SelectObject(hdc
, hfont
);
1265 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1266 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1267 memcmp(a
, w
, sizeof a
) == 0,
1268 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1270 memset(a
, 0xbb, sizeof a
);
1271 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1272 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1273 memset(full
, 0xcc, sizeof full
);
1274 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1275 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1276 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1277 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1279 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1281 memset(full
, 0xdd, sizeof full
);
1282 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1283 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1284 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1287 UINT last
= range
[j
].last
- range
[j
].first
;
1288 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1289 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1290 "GetCharABCWidthsA %x should match. codepage = %u\n",
1291 range
[j
].last
, c
[i
].cs
);
1295 hfont
= SelectObject(hdc
, hfont
);
1296 DeleteObject(hfont
);
1299 memset(&lf
, 0, sizeof(lf
));
1300 strcpy(lf
.lfFaceName
, "Tahoma");
1302 hfont
= CreateFontIndirectA(&lf
);
1304 /* test empty glyph's metrics */
1305 hfont
= SelectObject(hdc
, hfont
);
1306 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1307 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1308 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1309 ret
= pGetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1310 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1311 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1313 /* 1) prepare unrotated font metrics */
1314 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1315 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1316 DeleteObject(SelectObject(hdc
, hfont
));
1318 /* 2) get rotated font metrics */
1319 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1320 hfont
= CreateFontIndirectA(&lf
);
1321 hfont
= SelectObject(hdc
, hfont
);
1322 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1323 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1325 /* 3) compare ABC results */
1326 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1327 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1328 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1329 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1330 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1331 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1333 DeleteObject(SelectObject(hdc
, hfont
));
1334 ReleaseDC(NULL
, hdc
);
1336 trace("ABC sign test for a variety of transforms:\n");
1337 memset(&lf
, 0, sizeof(lf
));
1338 strcpy(lf
.lfFaceName
, "Tahoma");
1340 hfont
= CreateFontIndirectA(&lf
);
1341 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1344 SetMapMode(hdc
, MM_ANISOTROPIC
);
1345 SelectObject(hdc
, hfont
);
1347 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1348 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1350 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1351 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1352 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1353 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1354 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1355 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1357 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1358 SetWindowExtEx(hdc
, -1, -1, NULL
);
1359 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1360 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1361 SetGraphicsMode(hdc
, GM_ADVANCED
);
1362 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1363 SetWindowExtEx(hdc
, 1, 1, NULL
);
1364 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1365 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1366 SetGraphicsMode(hdc
, GM_ADVANCED
);
1367 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1369 ReleaseDC(hwnd
, hdc
);
1370 DestroyWindow(hwnd
);
1372 trace("RTL layout\n");
1373 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1376 SetMapMode(hdc
, MM_ANISOTROPIC
);
1377 SelectObject(hdc
, hfont
);
1379 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1380 SetWindowExtEx(hdc
, -1, -1, NULL
);
1381 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1382 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1383 SetGraphicsMode(hdc
, GM_ADVANCED
);
1384 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1385 SetWindowExtEx(hdc
, 1, 1, NULL
);
1386 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1387 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
, 0);
1388 SetGraphicsMode(hdc
, GM_ADVANCED
);
1389 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
, 1);
1391 ReleaseDC(hwnd
, hdc
);
1392 DestroyWindow(hwnd
);
1393 DeleteObject(hfont
);
1396 static void test_text_extents(void)
1398 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1400 INT i
, len
, fit1
, fit2
, extents2
[3];
1409 memset(&lf
, 0, sizeof(lf
));
1410 strcpy(lf
.lfFaceName
, "Arial");
1413 hfont
= CreateFontIndirectA(&lf
);
1415 hfont
= SelectObject(hdc
, hfont
);
1416 GetTextMetricsA(hdc
, &tm
);
1417 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1418 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1420 SetLastError(0xdeadbeef);
1421 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1422 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1424 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1425 hfont
= SelectObject(hdc
, hfont
);
1426 DeleteObject(hfont
);
1432 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1433 extents
[0] = 1; /* So that the increasing sequence test will fail
1434 if the extents array is untouched. */
1435 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1436 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1437 ok(sz1
.cy
== sz2
.cy
,
1438 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1439 /* Because of the '\n' in the string GetTextExtentExPoint and
1440 GetTextExtentPoint return different widths under Win2k, but
1441 under WinXP they return the same width. So we don't test that
1444 for (i
= 1; i
< len
; ++i
)
1445 ok(extents
[i
-1] <= extents
[i
],
1446 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1448 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1449 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1450 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1451 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1452 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1453 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1454 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1455 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1456 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1457 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1458 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1459 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1460 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1461 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1463 /* extents functions fail with -ve counts (the interesting case being -1) */
1464 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1465 ok(ret
== FALSE
, "got %d\n", ret
);
1466 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1467 ok(ret
== FALSE
, "got %d\n", ret
);
1468 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1469 ok(ret
== FALSE
, "got %d\n", ret
);
1471 /* max_extent = 0 succeeds and returns zero */
1473 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1475 broken(ret
== FALSE
), /* NT4, 2k */
1478 broken(fit1
== -215), /* NT4, 2k */
1479 "fit = %d\n", fit1
);
1480 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1481 ok(ret
== TRUE
, "got %d\n", ret
);
1482 ok(fit2
== 0, "fit = %d\n", fit2
);
1484 /* max_extent = -1 is interpreted as a very large width that will
1485 * definitely fit our three characters */
1487 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1488 ok(ret
== TRUE
, "got %d\n", ret
);
1489 ok(fit1
== 3, "fit = %d\n", fit1
);
1490 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1491 ok(ret
== TRUE
, "got %d\n", ret
);
1492 ok(fit2
== 3, "fit = %d\n", fit2
);
1494 /* max_extent = -2 is interpreted similarly, but the Ansi version
1495 * rejects it while the Unicode one accepts it */
1497 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1498 ok(ret
== FALSE
, "got %d\n", ret
);
1499 ok(fit1
== -215, "fit = %d\n", fit1
);
1500 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1501 ok(ret
== TRUE
, "got %d\n", ret
);
1502 ok(fit2
== 3, "fit = %d\n", fit2
);
1504 hfont
= SelectObject(hdc
, hfont
);
1505 DeleteObject(hfont
);
1507 /* non-MM_TEXT mapping mode */
1509 hfont
= CreateFontIndirectA(&lf
);
1510 hfont
= SelectObject(hdc
, hfont
);
1512 SetMapMode( hdc
, MM_HIMETRIC
);
1513 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1514 ok(ret
, "got %d\n", ret
);
1515 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1517 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1518 ok(ret
, "got %d\n", ret
);
1519 ok(fit1
== 2, "got %d\n", fit1
);
1520 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1521 for(i
= 0; i
< 2; i
++)
1522 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1524 hfont
= SelectObject(hdc
, hfont
);
1525 DeleteObject(hfont
);
1526 HeapFree(GetProcessHeap(), 0, extents
);
1527 ReleaseDC(NULL
, hdc
);
1530 static void test_GetGlyphIndices(void)
1537 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1538 WORD glyphs
[(sizeof(testtext
)/2)-1];
1542 if (!pGetGlyphIndicesW
) {
1543 win_skip("GetGlyphIndicesW not available on platform\n");
1549 memset(&lf
, 0, sizeof(lf
));
1550 strcpy(lf
.lfFaceName
, "System");
1552 lf
.lfCharSet
= ANSI_CHARSET
;
1554 hfont
= CreateFontIndirectA(&lf
);
1555 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1556 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1557 if (textm
.tmCharSet
== ANSI_CHARSET
)
1559 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1560 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1561 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1562 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1564 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1565 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1566 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1567 textm
.tmDefaultChar
, glyphs
[4]);
1570 /* FIXME: Write tests for non-ANSI charsets. */
1571 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1573 if(!is_font_installed("Tahoma"))
1575 skip("Tahoma is not installed so skipping this test\n");
1578 memset(&lf
, 0, sizeof(lf
));
1579 strcpy(lf
.lfFaceName
, "Tahoma");
1582 hfont
= CreateFontIndirectA(&lf
);
1583 hOldFont
= SelectObject(hdc
, hfont
);
1584 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1585 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1586 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1587 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1588 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1590 testtext
[0] = textm
.tmDefaultChar
;
1591 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1592 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1593 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1594 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1595 DeleteObject(SelectObject(hdc
, hOldFont
));
1598 static void test_GetKerningPairs(void)
1600 static const struct kerning_data
1602 const char face_name
[LF_FACESIZE
];
1604 /* some interesting fields from OUTLINETEXTMETRIC */
1605 LONG tmHeight
, tmAscent
, tmDescent
;
1610 UINT otmsCapEmHeight
;
1615 UINT otmusMinimumPPEM
;
1616 /* small subset of kerning pairs to test */
1617 DWORD total_kern_pairs
;
1618 const KERNINGPAIR kern_pair
[26];
1621 {"Arial", 12, 12, 9, 3,
1622 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1625 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1626 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1627 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1628 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1629 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1630 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1631 {933,970,+1},{933,972,-1}
1634 {"Arial", -34, 39, 32, 7,
1635 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1638 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1639 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1640 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1641 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1642 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1643 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1644 {933,970,+2},{933,972,-3}
1647 { "Arial", 120, 120, 97, 23,
1648 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1651 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1652 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1653 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1654 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1655 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1656 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1657 {933,970,+6},{933,972,-10}
1660 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1661 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1662 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1665 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1666 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1667 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1668 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1669 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1670 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1671 {933,970,+54},{933,972,-83}
1677 HFONT hfont
, hfont_old
;
1678 KERNINGPAIR
*kern_pair
;
1680 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1684 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1685 * which may render this test unusable, so we're trying to avoid that.
1687 SetLastError(0xdeadbeef);
1688 GetKerningPairsW(hdc
, 0, NULL
);
1689 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1691 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1696 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1698 OUTLINETEXTMETRICW otm
;
1701 if (!is_font_installed(kd
[i
].face_name
))
1703 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1707 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1709 memset(&lf
, 0, sizeof(lf
));
1710 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1711 lf
.lfHeight
= kd
[i
].height
;
1712 hfont
= CreateFontIndirectA(&lf
);
1715 hfont_old
= SelectObject(hdc
, hfont
);
1717 SetLastError(0xdeadbeef);
1718 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1719 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1720 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1722 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1723 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1724 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1725 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1726 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1727 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1729 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1730 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1731 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1732 kd
[i
].otmAscent
, otm
.otmAscent
);
1733 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1734 kd
[i
].otmDescent
, otm
.otmDescent
);
1735 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1736 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1737 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1738 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1739 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1740 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1742 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1743 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1744 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1745 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1746 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1747 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1748 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1749 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1750 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1753 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1754 trace("total_kern_pairs %u\n", total_kern_pairs
);
1755 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1757 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1760 SetLastError(0xdeadbeef);
1761 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1762 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1763 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1764 ok(ret
== 0, "got %u, expected 0\n", ret
);
1766 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1767 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1769 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1770 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1772 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1773 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1777 for (n
= 0; n
< ret
; n
++)
1780 /* Disabled to limit console spam */
1781 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1782 trace("{'%c','%c',%d},\n",
1783 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1784 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1786 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1787 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1789 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1790 "pair %d:%d got %d, expected %d\n",
1791 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1792 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1798 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1799 matches
, kd
[i
].total_kern_pairs
);
1801 HeapFree(GetProcessHeap(), 0, kern_pair
);
1803 SelectObject(hdc
, hfont_old
);
1804 DeleteObject(hfont
);
1812 const char face_name
[LF_FACESIZE
];
1813 int requested_height
;
1814 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1818 static void test_height( HDC hdc
, const struct font_data
*fd
)
1821 HFONT hfont
, old_hfont
;
1825 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1827 if (!is_truetype_font_installed(fd
[i
].face_name
))
1829 skip("%s is not installed\n", fd
[i
].face_name
);
1833 memset(&lf
, 0, sizeof(lf
));
1834 lf
.lfHeight
= fd
[i
].requested_height
;
1835 lf
.lfWeight
= fd
[i
].weight
;
1836 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1838 hfont
= CreateFontIndirectA(&lf
);
1841 old_hfont
= SelectObject(hdc
, hfont
);
1842 ret
= GetTextMetricsA(hdc
, &tm
);
1843 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1844 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1846 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1847 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmWeight
, fd
[i
].weight
);
1848 ok(match_off_by_1(tm
.tmHeight
, fd
[i
].height
, fd
[i
].exact
), "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmHeight
, fd
[i
].height
);
1849 ok(match_off_by_1(tm
.tmAscent
, fd
[i
].ascent
, fd
[i
].exact
), "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmAscent
, fd
[i
].ascent
);
1850 ok(match_off_by_1(tm
.tmDescent
, fd
[i
].descent
, fd
[i
].exact
), "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmDescent
, fd
[i
].descent
);
1851 ok(match_off_by_1(tm
.tmInternalLeading
, fd
[i
].int_leading
, fd
[i
].exact
), "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1852 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1855 SelectObject(hdc
, old_hfont
);
1856 DeleteObject(hfont
);
1860 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1862 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1863 DWORD
*table
= (DWORD
*)ttf
+ 3;
1865 for (i
= 0; i
< num_tables
; i
++)
1867 if (table
[0] == tag
)
1868 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
1874 static void test_height_selection_vdmx( HDC hdc
)
1876 static const struct font_data charset_0
[] = /* doesn't use VDMX */
1878 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1879 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1880 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1881 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1882 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1883 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
1884 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1885 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1886 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1887 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1888 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
1889 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1890 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1891 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1892 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1893 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1894 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
1895 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1896 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1897 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1898 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1899 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1900 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
1901 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
1902 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
1903 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
1904 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1905 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1906 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1907 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1908 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1909 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1910 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1911 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1912 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1913 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1914 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1915 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1916 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1917 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1918 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1919 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1920 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1921 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
1922 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
1923 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
1924 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
1925 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
1926 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
1927 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
1928 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
1929 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
1930 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1933 static const struct font_data charset_1
[] = /* Uses VDMX */
1935 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1936 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1937 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1938 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1939 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1940 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1941 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1942 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1943 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1944 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1945 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1946 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1947 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1948 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1949 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1950 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1951 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1952 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1953 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1954 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1955 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1956 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1957 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1958 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
1959 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
1960 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
1961 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1962 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1963 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
1964 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1965 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
1966 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
1967 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
1968 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
1969 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
1970 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
1971 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
1972 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
1973 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
1974 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
1975 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
1976 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
1977 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
1978 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
1979 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
1980 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
1981 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
1982 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
1983 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
1984 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
1985 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
1986 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
1987 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
1990 static const struct vdmx_data
1994 const struct font_data
*fd
;
1997 { 0, 0, charset_0
},
1998 { 0, 1, charset_1
},
1999 { 1, 0, charset_0
},
2006 char ttf_name
[MAX_PATH
];
2009 if (!pAddFontResourceExA
)
2011 win_skip("AddFontResourceExA unavailable\n");
2015 for (i
= 0; i
< sizeof(data
) / sizeof(data
[0]); i
++)
2017 res
= get_res_data( "wine_vdmx.ttf", &size
);
2019 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2020 memcpy( copy
, res
, size
);
2021 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2022 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2023 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2024 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2025 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2026 ratio_rec
[0] = data
[i
].bCharSet
;
2028 write_tmp_file( copy
, &size
, ttf_name
);
2029 HeapFree( GetProcessHeap(), 0, copy
);
2031 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2032 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2033 if (!num
) win_skip("Unable to add ttf font resource\n");
2036 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2037 test_height( hdc
, data
[i
].fd
);
2038 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2040 DeleteFileA( ttf_name
);
2044 static void test_height_selection(void)
2046 static const struct font_data tahoma
[] =
2048 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2049 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2050 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2051 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2052 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2053 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2054 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2055 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2056 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2057 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2058 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2060 HDC hdc
= CreateCompatibleDC(0);
2063 test_height( hdc
, tahoma
);
2064 test_height_selection_vdmx( hdc
);
2069 static void test_GetOutlineTextMetrics(void)
2071 OUTLINETEXTMETRICA
*otm
;
2073 HFONT hfont
, hfont_old
;
2075 DWORD ret
, otm_size
;
2078 if (!is_font_installed("Arial"))
2080 skip("Arial is not installed\n");
2086 memset(&lf
, 0, sizeof(lf
));
2087 strcpy(lf
.lfFaceName
, "Arial");
2089 lf
.lfWeight
= FW_NORMAL
;
2090 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2091 lf
.lfQuality
= PROOF_QUALITY
;
2092 hfont
= CreateFontIndirectA(&lf
);
2095 hfont_old
= SelectObject(hdc
, hfont
);
2096 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2097 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
2099 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2101 memset(otm
, 0xAA, otm_size
);
2102 SetLastError(0xdeadbeef);
2103 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2104 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2105 ok(ret
== 1 /* Win9x */ ||
2106 ret
== otm
->otmSize
/* XP*/,
2107 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2108 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2110 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2111 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2112 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2113 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2116 memset(otm
, 0xAA, otm_size
);
2117 SetLastError(0xdeadbeef);
2118 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2119 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2120 ok(ret
== 1 /* Win9x */ ||
2121 ret
== otm
->otmSize
/* XP*/,
2122 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2123 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2125 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2126 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2127 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2128 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2131 /* ask about truncated data */
2132 memset(otm
, 0xAA, otm_size
);
2133 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2134 SetLastError(0xdeadbeef);
2135 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2136 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2137 ok(ret
== 1 /* Win9x */ ||
2138 ret
== otm
->otmSize
/* XP*/,
2139 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2140 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2142 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2143 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2144 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2146 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2148 HeapFree(GetProcessHeap(), 0, otm
);
2150 SelectObject(hdc
, hfont_old
);
2151 DeleteObject(hfont
);
2156 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2160 areaWidth
= clientArea
->right
- clientArea
->left
,
2162 const char *pFirstChar
, *pLastChar
;
2169 int GetTextExtentExPointWWidth
;
2172 GetTextMetricsA(hdc
, &tm
);
2173 y
= clientArea
->top
;
2176 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2182 /* if not at the end of the string, ... */
2183 if (*str
== '\0') break;
2184 /* ... add the next word to the current extent */
2185 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2187 SetTextJustification(hdc
, 0, 0);
2188 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2189 } while ((int) size
.cx
< areaWidth
);
2191 /* ignore trailing break chars */
2193 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2199 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2201 SetTextJustification(hdc
, 0, 0);
2202 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2204 /* do not justify the last extent */
2205 if (*str
!= '\0' && breakCount
> 0)
2207 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2208 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2209 if (size
.cx
!= areaWidth
&& nErrors
< sizeof(error
)/sizeof(error
[0]) - 1)
2211 error
[nErrors
].start
= pFirstChar
;
2212 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2213 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2218 trace( "%u %.*s\n", size
.cx
, (int)(pLastChar
- pFirstChar
), pFirstChar
);
2222 } while (*str
&& y
< clientArea
->bottom
);
2224 for (e
= 0; e
< nErrors
; e
++)
2226 /* The width returned by GetTextExtentPoint32() is exactly the same
2227 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2228 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2229 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2230 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2234 static void test_SetTextJustification(void)
2244 static const char testText
[] =
2245 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2246 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2247 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2248 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2249 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2250 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2251 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2253 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2254 GetClientRect( hwnd
, &clientArea
);
2255 hdc
= GetDC( hwnd
);
2257 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
);
2573 ReleaseDC(NULL
, hdc
);
2577 static void test_GetFontUnicodeRanges(void)
2581 HFONT hfont
, hfont_old
;
2586 if (!pGetFontUnicodeRanges
)
2588 win_skip("GetFontUnicodeRanges not available before W2K\n");
2592 memset(&lf
, 0, sizeof(lf
));
2593 lstrcpyA(lf
.lfFaceName
, "Arial");
2594 hfont
= create_font("Arial", &lf
);
2597 hfont_old
= SelectObject(hdc
, hfont
);
2599 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2600 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2602 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2603 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2605 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2607 size
= pGetFontUnicodeRanges(hdc
, gs
);
2608 ok(size
, "GetFontUnicodeRanges failed\n");
2610 if (0) /* Disabled to limit console spam */
2611 for (i
= 0; i
< gs
->cRanges
; i
++)
2612 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2613 trace("found %u ranges\n", gs
->cRanges
);
2615 HeapFree(GetProcessHeap(), 0, gs
);
2617 SelectObject(hdc
, hfont_old
);
2618 DeleteObject(hfont
);
2619 ReleaseDC(NULL
, hdc
);
2622 #define MAX_ENUM_FONTS 4096
2624 struct enum_font_data
2627 LOGFONTA lf
[MAX_ENUM_FONTS
];
2630 struct enum_fullname_data
2633 ENUMLOGFONTA elf
[MAX_ENUM_FONTS
];
2636 struct enum_font_dataW
2639 LOGFONTW lf
[MAX_ENUM_FONTS
];
2642 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2644 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2645 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2647 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2648 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2650 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2652 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2654 if (0) /* Disabled to limit console spam */
2655 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2656 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2657 if (efd
->total
< MAX_ENUM_FONTS
)
2658 efd
->lf
[efd
->total
++] = *lf
;
2660 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2665 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2667 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2668 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2670 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2671 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2673 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2675 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2677 if (0) /* Disabled to limit console spam */
2678 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2679 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2680 if (efd
->total
< MAX_ENUM_FONTS
)
2681 efd
->lf
[efd
->total
++] = *lf
;
2683 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2688 static void get_charset_stats(struct enum_font_data
*efd
,
2689 int *ansi_charset
, int *symbol_charset
,
2690 int *russian_charset
)
2695 *symbol_charset
= 0;
2696 *russian_charset
= 0;
2698 for (i
= 0; i
< efd
->total
; i
++)
2700 switch (efd
->lf
[i
].lfCharSet
)
2705 case SYMBOL_CHARSET
:
2706 (*symbol_charset
)++;
2708 case RUSSIAN_CHARSET
:
2709 (*russian_charset
)++;
2715 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2716 int *ansi_charset
, int *symbol_charset
,
2717 int *russian_charset
)
2722 *symbol_charset
= 0;
2723 *russian_charset
= 0;
2725 for (i
= 0; i
< efd
->total
; i
++)
2727 switch (efd
->lf
[i
].lfCharSet
)
2732 case SYMBOL_CHARSET
:
2733 (*symbol_charset
)++;
2735 case RUSSIAN_CHARSET
:
2736 (*russian_charset
)++;
2742 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2744 struct enum_font_data efd
;
2745 struct enum_font_dataW efdw
;
2748 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2750 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2752 if (*font_name
&& !is_truetype_font_installed(font_name
))
2754 skip("%s is not installed\n", font_name
);
2760 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2761 * while EnumFontFamiliesEx doesn't.
2763 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2766 * Use EnumFontFamiliesW since win98 crashes when the
2767 * second parameter is NULL using EnumFontFamilies
2770 SetLastError(0xdeadbeef);
2771 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2772 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2775 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2776 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2777 ansi_charset
, symbol_charset
, russian_charset
);
2778 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2779 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2780 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2781 ok(russian_charset
> 0 ||
2782 broken(russian_charset
== 0), /* NT4 */
2783 "NULL family should enumerate RUSSIAN_CHARSET\n");
2787 SetLastError(0xdeadbeef);
2788 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2789 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2792 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2793 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2794 ansi_charset
, symbol_charset
, russian_charset
);
2795 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2796 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2797 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2798 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2803 SetLastError(0xdeadbeef);
2804 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2805 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2806 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2807 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2808 ansi_charset
, symbol_charset
, russian_charset
,
2809 *font_name
? font_name
: "<empty>");
2811 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2813 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2814 for (i
= 0; i
< efd
.total
; i
++)
2816 /* FIXME: remove completely once Wine is fixed */
2817 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2820 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2823 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2824 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2825 font_name
, efd
.lf
[i
].lfFaceName
);
2828 memset(&lf
, 0, sizeof(lf
));
2829 lf
.lfCharSet
= ANSI_CHARSET
;
2830 strcpy(lf
.lfFaceName
, font_name
);
2832 SetLastError(0xdeadbeef);
2833 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2834 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2835 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2836 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2837 ansi_charset
, symbol_charset
, russian_charset
,
2838 *font_name
? font_name
: "<empty>");
2839 if (font_charset
== SYMBOL_CHARSET
)
2842 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2844 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2848 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2849 for (i
= 0; i
< efd
.total
; i
++)
2851 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2853 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2854 font_name
, efd
.lf
[i
].lfFaceName
);
2858 /* DEFAULT_CHARSET should enumerate all available charsets */
2859 memset(&lf
, 0, sizeof(lf
));
2860 lf
.lfCharSet
= DEFAULT_CHARSET
;
2861 strcpy(lf
.lfFaceName
, font_name
);
2863 SetLastError(0xdeadbeef);
2864 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2865 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2866 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2867 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2868 ansi_charset
, symbol_charset
, russian_charset
,
2869 *font_name
? font_name
: "<empty>");
2870 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2871 for (i
= 0; i
< efd
.total
; i
++)
2874 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2875 font_name
, efd
.lf
[i
].lfFaceName
);
2879 switch (font_charset
)
2882 ok(ansi_charset
> 0,
2883 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2885 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2886 ok(russian_charset
> 0,
2887 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2889 case SYMBOL_CHARSET
:
2891 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2893 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2894 ok(!russian_charset
,
2895 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2897 case DEFAULT_CHARSET
:
2898 ok(ansi_charset
> 0,
2899 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2900 ok(symbol_charset
> 0,
2901 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2902 ok(russian_charset
> 0,
2903 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2909 ok(ansi_charset
> 0,
2910 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2911 ok(symbol_charset
> 0,
2912 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2913 ok(russian_charset
> 0,
2914 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2917 memset(&lf
, 0, sizeof(lf
));
2918 lf
.lfCharSet
= SYMBOL_CHARSET
;
2919 strcpy(lf
.lfFaceName
, font_name
);
2921 SetLastError(0xdeadbeef);
2922 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2923 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2924 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2925 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2926 ansi_charset
, symbol_charset
, russian_charset
,
2927 *font_name
? font_name
: "<empty>");
2928 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2929 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2932 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2933 for (i
= 0; i
< efd
.total
; i
++)
2935 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2937 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2938 font_name
, efd
.lf
[i
].lfFaceName
);
2942 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2943 ok(symbol_charset
> 0,
2944 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2945 ok(!russian_charset
,
2946 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2952 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2954 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
2955 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
2956 const DWORD valid_bits
= 0x003f01ff;
2960 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
2962 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
2963 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
2964 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
2973 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
2975 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2977 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2979 if (efd
->total
< MAX_ENUM_FONTS
)
2980 efd
->lf
[efd
->total
++] = *lf
;
2982 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2987 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
2989 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
2991 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2993 if (efnd
->total
< MAX_ENUM_FONTS
)
2994 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
2996 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
3001 static void test_EnumFontFamiliesEx_default_charset(void)
3003 struct enum_font_data efd
;
3004 LOGFONTA target
, enum_font
;
3010 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3011 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3016 memset(&enum_font
, 0, sizeof(enum_font
));
3017 enum_font
.lfCharSet
= csi
.ciCharset
;
3018 target
.lfFaceName
[0] = '\0';
3019 target
.lfCharSet
= csi
.ciCharset
;
3020 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3021 if (target
.lfFaceName
[0] == '\0') {
3022 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3025 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3026 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3027 target
.lfCharSet
= ANSI_CHARSET
;
3031 memset(&enum_font
, 0, sizeof(enum_font
));
3032 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3033 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3034 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3037 trace("'%s' has %d charsets.\n", target
.lfFaceName
, efd
.total
);
3038 if (efd
.total
< 2) {
3039 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3043 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3044 "(%s) got charset %d expected %d\n",
3045 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3050 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3052 HFONT hfont
, hfont_prev
;
3054 GLYPHMETRICS gm1
, gm2
;
3058 if(!pGetGlyphIndicesA
)
3061 /* negative widths are handled just as positive ones */
3062 lf2
.lfWidth
= -lf
->lfWidth
;
3064 SetLastError(0xdeadbeef);
3065 hfont
= CreateFontIndirectA(lf
);
3066 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3067 check_font("original", lf
, hfont
);
3069 hfont_prev
= SelectObject(hdc
, hfont
);
3071 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3072 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3074 SelectObject(hdc
, hfont_prev
);
3075 DeleteObject(hfont
);
3076 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3080 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3081 memset(&gm1
, 0xab, sizeof(gm1
));
3082 SetLastError(0xdeadbeef);
3083 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3084 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3086 SelectObject(hdc
, hfont_prev
);
3087 DeleteObject(hfont
);
3089 SetLastError(0xdeadbeef);
3090 hfont
= CreateFontIndirectA(&lf2
);
3091 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3092 check_font("negative width", &lf2
, hfont
);
3094 hfont_prev
= SelectObject(hdc
, hfont
);
3096 memset(&gm2
, 0xbb, sizeof(gm2
));
3097 SetLastError(0xdeadbeef);
3098 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3099 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3101 SelectObject(hdc
, hfont_prev
);
3102 DeleteObject(hfont
);
3104 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3105 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3106 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3107 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3108 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3109 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3110 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3111 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3112 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3113 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3114 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3117 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3118 #include "pshpack2.h"
3122 SHORT xAvgCharWidth
;
3123 USHORT usWeightClass
;
3124 USHORT usWidthClass
;
3126 SHORT ySubscriptXSize
;
3127 SHORT ySubscriptYSize
;
3128 SHORT ySubscriptXOffset
;
3129 SHORT ySubscriptYOffset
;
3130 SHORT ySuperscriptXSize
;
3131 SHORT ySuperscriptYSize
;
3132 SHORT ySuperscriptXOffset
;
3133 SHORT ySuperscriptYOffset
;
3134 SHORT yStrikeoutSize
;
3135 SHORT yStrikeoutPosition
;
3138 ULONG ulUnicodeRange1
;
3139 ULONG ulUnicodeRange2
;
3140 ULONG ulUnicodeRange3
;
3141 ULONG ulUnicodeRange4
;
3144 USHORT usFirstCharIndex
;
3145 USHORT usLastCharIndex
;
3146 /* According to the Apple spec, original version didn't have the below fields,
3147 * version numbers were taken from the OpenType spec.
3149 /* version 0 (TrueType 1.5) */
3150 USHORT sTypoAscender
;
3151 USHORT sTypoDescender
;
3152 USHORT sTypoLineGap
;
3154 USHORT usWinDescent
;
3155 /* version 1 (TrueType 1.66) */
3156 ULONG ulCodePageRange1
;
3157 ULONG ulCodePageRange2
;
3158 /* version 2 (OpenType 1.2) */
3161 USHORT usDefaultChar
;
3163 USHORT usMaxContext
;
3165 #include "poppack.h"
3178 } cmap_encoding_record
;
3186 BYTE glyph_ids
[256];
3196 USHORT search_range
;
3197 USHORT entry_selector
;
3200 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3203 USHORT start_count[seg_countx2 / 2];
3204 USHORT id_delta[seg_countx2 / 2];
3205 USHORT id_range_offset[seg_countx2 / 2];
3215 USHORT id_range_offset
;
3216 } cmap_format_4_seg
;
3218 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
3220 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3221 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3222 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3223 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3224 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3227 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3230 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3234 for(i
= 0; i
< 256; i
++)
3236 if(cmap
->glyph_ids
[i
] == 0) continue;
3238 if(*first
== 256) *first
= i
;
3240 if(*first
== 256) return FALSE
;
3244 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3246 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3247 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3248 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3249 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3250 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3253 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3256 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3257 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3258 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
3262 for(i
= 0; i
< seg_count
; i
++)
3265 cmap_format_4_seg seg
;
3267 get_seg4(cmap
, i
, &seg
);
3268 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
3270 if(seg
.id_range_offset
== 0)
3271 index
= (seg
.id_delta
+ code
) & 0xffff;
3274 index
= seg
.id_range_offset
/ 2
3275 + code
- seg
.start_count
3278 /* some fonts have broken last segment */
3279 if ((char *)(glyph_ids
+ index
+ 1) < (char *)ptr
+ limit
)
3280 index
= GET_BE_WORD(glyph_ids
[index
]);
3283 trace("segment %04x/%04x index %04x points to nowhere\n",
3284 seg
.start_count
, seg
.end_count
, index
);
3287 if(index
) index
+= seg
.id_delta
;
3289 if(*first
== 0x10000)
3290 *last
= *first
= code
;
3296 if(*first
== 0x10000) return FALSE
;
3300 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3303 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3305 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3307 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3308 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3321 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3324 cmap_header
*header
;
3329 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3330 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3331 if(size
== GDI_ERROR
) return FALSE
;
3333 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3334 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3335 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3336 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3338 cmap
= get_cmap(header
, 3, 1);
3340 *cmap_type
= cmap_ms_unicode
;
3343 cmap
= get_cmap(header
, 3, 0);
3344 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3348 *cmap_type
= cmap_none
;
3352 format
= GET_BE_WORD(*(WORD
*)cmap
);
3356 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3359 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3362 trace("unhandled cmap format %d\n", format
);
3367 HeapFree(GetProcessHeap(), 0, header
);
3371 #define TT_PLATFORM_MICROSOFT 3
3372 #define TT_MS_ID_SYMBOL_CS 0
3373 #define TT_MS_ID_UNICODE_CS 1
3374 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3375 #define TT_NAME_ID_FONT_FAMILY 1
3376 #define TT_NAME_ID_FONT_SUBFAMILY 2
3377 #define TT_NAME_ID_UNIQUE_ID 3
3378 #define TT_NAME_ID_FULL_NAME 4
3380 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3382 struct sfnt_name_header
3385 USHORT number_of_record
;
3386 USHORT storage_offset
;
3398 LONG size
, offset
, length
;
3404 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3405 ok(size
!= GDI_ERROR
, "no name table found\n");
3406 if(size
== GDI_ERROR
) return FALSE
;
3408 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3409 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3410 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3412 header
= (void *)data
;
3413 header
->format
= GET_BE_WORD(header
->format
);
3414 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3415 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3416 if (header
->format
!= 0)
3418 trace("got format %u\n", header
->format
);
3421 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3423 trace("number records out of range: %d\n", header
->number_of_record
);
3426 if (header
->storage_offset
>= size
)
3428 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3432 entry
= (void *)&header
[1];
3433 for (i
= 0; i
< header
->number_of_record
; i
++)
3435 if (GET_BE_WORD(entry
[i
].platform_id
) != TT_PLATFORM_MICROSOFT
||
3436 (GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_UNICODE_CS
&& GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_SYMBOL_CS
) ||
3437 GET_BE_WORD(entry
[i
].language_id
) != language_id
||
3438 GET_BE_WORD(entry
[i
].name_id
) != name_id
)
3443 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[i
].offset
);
3444 length
= GET_BE_WORD(entry
[i
].length
);
3445 if (offset
+ length
> size
)
3447 trace("entry %d is out of range\n", i
);
3450 if (length
>= out_size
)
3452 trace("buffer too small for entry %d\n", i
);
3456 name
= (WCHAR
*)(data
+ offset
);
3457 for (c
= 0; c
< length
/ 2; c
++)
3458 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3466 HeapFree(GetProcessHeap(), 0, data
);
3470 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3473 HFONT hfont
, hfont_old
;
3477 const char *font_name
= lf
->lfFaceName
;
3478 DWORD cmap_first
= 0, cmap_last
= 0;
3479 UINT ascent
, descent
, cell_height
;
3480 cmap_type cmap_type
;
3481 BOOL sys_lang_non_english
;
3483 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3486 SetLastError(0xdeadbeef);
3487 hfont
= CreateFontIndirectA(lf
);
3488 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3490 hfont_old
= SelectObject(hdc
, hfont
);
3492 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3493 if (size
== GDI_ERROR
)
3495 trace("OS/2 chunk was not found\n");
3498 if (size
> sizeof(tt_os2
))
3500 trace("got too large OS/2 chunk of size %u\n", size
);
3501 size
= sizeof(tt_os2
);
3504 memset(&tt_os2
, 0, sizeof(tt_os2
));
3505 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3506 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3508 SetLastError(0xdeadbeef);
3509 ret
= GetTextMetricsA(hdc
, &tmA
);
3510 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3512 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3514 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3518 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3519 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3520 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3524 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3525 descent
= GET_BE_WORD(tt_os2
.usWinDescent
);
3526 cell_height
= ascent
+ descent
;
3527 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3528 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3530 version
= GET_BE_WORD(tt_os2
.version
);
3532 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3533 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3534 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3535 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3537 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3538 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3539 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3541 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3546 case 1255: /* Hebrew */
3547 expect_last_W
= 0xf896;
3549 case 1257: /* Baltic */
3550 expect_last_W
= 0xf8fd;
3553 expect_last_W
= 0xf0ff;
3555 expect_break_W
= 0x20;
3556 expect_default_W
= expect_break_W
- 1;
3557 expect_first_A
= 0x1e;
3558 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3562 expect_first_W
= cmap_first
;
3563 expect_last_W
= min(cmap_last
, os2_last_char
);
3564 if(os2_first_char
<= 1)
3565 expect_break_W
= os2_first_char
+ 2;
3566 else if(os2_first_char
> 0xff)
3567 expect_break_W
= 0x20;
3569 expect_break_W
= os2_first_char
;
3570 expect_default_W
= expect_break_W
- 1;
3571 expect_first_A
= expect_default_W
- 1;
3572 expect_last_A
= min(expect_last_W
, 0xff);
3574 expect_break_A
= expect_break_W
;
3575 expect_default_A
= expect_default_W
;
3577 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3578 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3579 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
3580 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3581 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3583 ok(tmA
.tmFirstChar
== expect_first_A
||
3584 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3585 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3586 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3587 ok(tmA
.tmLastChar
== expect_last_A
||
3588 tmA
.tmLastChar
== 0xff /* win9x */,
3589 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3591 skip("tmLastChar is DBCS lead byte\n");
3592 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3593 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3594 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3595 "A: tmDefaultChar for %s got %02x expected %02x\n",
3596 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3599 SetLastError(0xdeadbeef);
3600 ret
= GetTextMetricsW(hdc
, &tmW
);
3601 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3602 "GetTextMetricsW error %u\n", GetLastError());
3605 /* Wine uses the os2 first char */
3606 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3607 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3608 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3610 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3611 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3613 /* Wine uses the os2 last char */
3614 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3615 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3616 font_name
, tmW
.tmLastChar
, expect_last_W
);
3618 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3619 font_name
, tmW
.tmLastChar
, expect_last_W
);
3620 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3621 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3622 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3623 "W: tmDefaultChar for %s got %02x expected %02x\n",
3624 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3626 /* Test the aspect ratio while we have tmW */
3627 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3628 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3629 tmW
.tmDigitizedAspectX
, ret
);
3630 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3631 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3632 tmW
.tmDigitizedAspectX
, ret
);
3636 /* test FF_ values */
3637 switch(tt_os2
.panose
.bFamilyType
)
3641 case PAN_FAMILY_TEXT_DISPLAY
:
3642 case PAN_FAMILY_PICTORIAL
:
3644 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3645 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3647 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3650 switch(tt_os2
.panose
.bSerifStyle
)
3655 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3658 case PAN_SERIF_COVE
:
3659 case PAN_SERIF_OBTUSE_COVE
:
3660 case PAN_SERIF_SQUARE_COVE
:
3661 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3662 case PAN_SERIF_SQUARE
:
3663 case PAN_SERIF_THIN
:
3664 case PAN_SERIF_BONE
:
3665 case PAN_SERIF_EXAGGERATED
:
3666 case PAN_SERIF_TRIANGLE
:
3667 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3670 case PAN_SERIF_NORMAL_SANS
:
3671 case PAN_SERIF_OBTUSE_SANS
:
3672 case PAN_SERIF_PERP_SANS
:
3673 case PAN_SERIF_FLARED
:
3674 case PAN_SERIF_ROUNDED
:
3675 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3680 case PAN_FAMILY_SCRIPT
:
3681 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3684 case PAN_FAMILY_DECORATIVE
:
3685 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3689 test_negative_width(hdc
, lf
);
3692 SelectObject(hdc
, hfont_old
);
3693 DeleteObject(hfont
);
3698 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3700 INT
*enumed
= (INT
*)lParam
;
3702 if (type
== TRUETYPE_FONTTYPE
)
3705 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
3710 static void test_GetTextMetrics(void)
3716 /* Report only once */
3717 if(!pGetGlyphIndicesA
)
3718 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3722 memset(&lf
, 0, sizeof(lf
));
3723 lf
.lfCharSet
= DEFAULT_CHARSET
;
3725 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
3726 trace("Tested metrics of %d truetype fonts\n", enumed
);
3731 static void test_nonexistent_font(void)
3739 { "Times New Roman Baltic", 186 },
3740 { "Times New Roman CE", 238 },
3741 { "Times New Roman CYR", 204 },
3742 { "Times New Roman Greek", 161 },
3743 { "Times New Roman TUR", 162 }
3749 INT cs
, expected_cs
, i
;
3750 char buf
[LF_FACESIZE
];
3752 if (!is_truetype_font_installed("Arial") ||
3753 !is_truetype_font_installed("Times New Roman"))
3755 skip("Arial or Times New Roman not installed\n");
3759 expected_cs
= GetACP();
3760 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3762 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3765 expected_cs
= csi
.ciCharset
;
3766 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3770 memset(&lf
, 0, sizeof(lf
));
3772 lf
.lfWeight
= FW_REGULAR
;
3773 lf
.lfCharSet
= ANSI_CHARSET
;
3774 lf
.lfPitchAndFamily
= FF_SWISS
;
3775 strcpy(lf
.lfFaceName
, "Nonexistent font");
3776 hfont
= CreateFontIndirectA(&lf
);
3777 hfont
= SelectObject(hdc
, hfont
);
3778 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3779 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
3780 cs
= GetTextCharset(hdc
);
3781 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3782 DeleteObject(SelectObject(hdc
, hfont
));
3784 memset(&lf
, 0, sizeof(lf
));
3786 lf
.lfWeight
= FW_DONTCARE
;
3787 strcpy(lf
.lfFaceName
, "Nonexistent font");
3788 hfont
= CreateFontIndirectA(&lf
);
3789 hfont
= SelectObject(hdc
, hfont
);
3790 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3791 todo_wine
/* Wine uses Arial for all substitutions */
3792 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
3793 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
3794 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3796 cs
= GetTextCharset(hdc
);
3797 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
3798 DeleteObject(SelectObject(hdc
, hfont
));
3800 memset(&lf
, 0, sizeof(lf
));
3802 lf
.lfWeight
= FW_REGULAR
;
3803 strcpy(lf
.lfFaceName
, "Nonexistent font");
3804 hfont
= CreateFontIndirectA(&lf
);
3805 hfont
= SelectObject(hdc
, hfont
);
3806 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3807 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3808 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
3809 cs
= GetTextCharset(hdc
);
3810 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3811 DeleteObject(SelectObject(hdc
, hfont
));
3813 memset(&lf
, 0, sizeof(lf
));
3815 lf
.lfWeight
= FW_DONTCARE
;
3816 strcpy(lf
.lfFaceName
, "Times New Roman");
3817 hfont
= CreateFontIndirectA(&lf
);
3818 hfont
= SelectObject(hdc
, hfont
);
3819 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3820 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
3821 cs
= GetTextCharset(hdc
);
3822 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3823 DeleteObject(SelectObject(hdc
, hfont
));
3825 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
3827 memset(&lf
, 0, sizeof(lf
));
3829 lf
.lfWeight
= FW_REGULAR
;
3830 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3831 hfont
= CreateFontIndirectA(&lf
);
3832 hfont
= SelectObject(hdc
, hfont
);
3833 cs
= GetTextCharset(hdc
);
3834 if (font_subst
[i
].charset
== expected_cs
)
3836 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3837 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3838 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
3842 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
3843 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3844 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3845 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
3847 DeleteObject(SelectObject(hdc
, hfont
));
3849 memset(&lf
, 0, sizeof(lf
));
3851 lf
.lfWeight
= FW_DONTCARE
;
3852 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3853 hfont
= CreateFontIndirectA(&lf
);
3854 hfont
= SelectObject(hdc
, hfont
);
3855 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3856 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
3857 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
3858 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
3859 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3860 "got %s for font %s\n", buf
, font_subst
[i
].name
);
3861 cs
= GetTextCharset(hdc
);
3862 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3863 DeleteObject(SelectObject(hdc
, hfont
));
3869 static void test_GdiRealizationInfo(void)
3874 HFONT hfont
, hfont_old
;
3877 if(!pGdiRealizationInfo
)
3879 win_skip("GdiRealizationInfo not available\n");
3885 memset(info
, 0xcc, sizeof(info
));
3886 r
= pGdiRealizationInfo(hdc
, info
);
3887 ok(r
!= 0, "ret 0\n");
3888 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
3889 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3891 if (!is_truetype_font_installed("Arial"))
3893 skip("skipping GdiRealizationInfo with truetype font\n");
3897 memset(&lf
, 0, sizeof(lf
));
3898 strcpy(lf
.lfFaceName
, "Arial");
3900 lf
.lfWeight
= FW_NORMAL
;
3901 hfont
= CreateFontIndirectA(&lf
);
3902 hfont_old
= SelectObject(hdc
, hfont
);
3904 memset(info
, 0xcc, sizeof(info
));
3905 r
= pGdiRealizationInfo(hdc
, info
);
3906 ok(r
!= 0, "ret 0\n");
3907 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
3908 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3910 DeleteObject(SelectObject(hdc
, hfont_old
));
3916 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3917 the nul in the count of characters copied when the face name buffer is not
3918 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3919 always includes it. */
3920 static void test_GetTextFace(void)
3922 static const char faceA
[] = "Tahoma";
3923 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
3926 char bufA
[LF_FACESIZE
];
3927 WCHAR bufW
[LF_FACESIZE
];
3932 if(!is_font_installed("Tahoma"))
3934 skip("Tahoma is not installed so skipping this test\n");
3939 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
3940 f
= CreateFontIndirectA(&fA
);
3941 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
3944 g
= SelectObject(dc
, f
);
3945 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
3946 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
3947 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
3949 /* Play with the count arg. */
3951 n
= GetTextFaceA(dc
, 0, bufA
);
3952 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3953 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3956 n
= GetTextFaceA(dc
, 1, bufA
);
3957 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3958 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3960 bufA
[0] = 'x'; bufA
[1] = 'y';
3961 n
= GetTextFaceA(dc
, 2, bufA
);
3962 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
3963 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
3965 n
= GetTextFaceA(dc
, 0, NULL
);
3966 ok(n
== sizeof faceA
||
3967 broken(n
== 0), /* win98, winMe */
3968 "GetTextFaceA returned %d\n", n
);
3970 DeleteObject(SelectObject(dc
, g
));
3971 ReleaseDC(NULL
, dc
);
3974 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3975 SetLastError(0xdeadbeef);
3976 f
= CreateFontIndirectW(&fW
);
3977 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3979 win_skip("CreateFontIndirectW is not implemented\n");
3982 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3985 g
= SelectObject(dc
, f
);
3986 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3987 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3988 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3990 /* Play with the count arg. */
3992 n
= GetTextFaceW(dc
, 0, bufW
);
3993 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3994 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3997 n
= GetTextFaceW(dc
, 1, bufW
);
3998 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3999 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4001 bufW
[0] = 'x'; bufW
[1] = 'y';
4002 n
= GetTextFaceW(dc
, 2, bufW
);
4003 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4004 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4006 n
= GetTextFaceW(dc
, 0, NULL
);
4007 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
4009 DeleteObject(SelectObject(dc
, g
));
4010 ReleaseDC(NULL
, dc
);
4013 static void test_orientation(void)
4015 static const char test_str
[11] = "Test String";
4018 HFONT hfont
, old_hfont
;
4021 if (!is_truetype_font_installed("Arial"))
4023 skip("Arial is not installed\n");
4027 hdc
= CreateCompatibleDC(0);
4028 memset(&lf
, 0, sizeof(lf
));
4029 lstrcpyA(lf
.lfFaceName
, "Arial");
4031 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4032 hfont
= create_font("orientation", &lf
);
4033 old_hfont
= SelectObject(hdc
, hfont
);
4034 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4035 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4036 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4037 SelectObject(hdc
, old_hfont
);
4038 DeleteObject(hfont
);
4042 static void test_oemcharset(void)
4046 HFONT hfont
, old_hfont
;
4049 hdc
= CreateCompatibleDC(0);
4050 ZeroMemory(&lf
, sizeof(lf
));
4052 lf
.lfCharSet
= OEM_CHARSET
;
4053 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4054 lstrcpyA(lf
.lfFaceName
, "Terminal");
4055 hfont
= CreateFontIndirectA(&lf
);
4056 old_hfont
= SelectObject(hdc
, hfont
);
4057 charset
= GetTextCharset(hdc
);
4059 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4060 hfont
= SelectObject(hdc
, old_hfont
);
4061 GetObjectA(hfont
, sizeof(clf
), &clf
);
4062 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4063 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4064 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4065 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4066 DeleteObject(hfont
);
4070 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4071 const TEXTMETRICA
*lpntme
,
4072 DWORD FontType
, LPARAM lParam
)
4074 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4076 LOGFONTA lf
= *lpelfe
;
4080 /* skip bitmap, proportional or vertical font */
4081 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4082 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4083 lf
.lfFaceName
[0] == '@')
4086 /* skip linked font */
4087 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4088 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4091 /* skip linked font, like SimSun-ExtB */
4092 switch (lpelfe
->lfCharSet
) {
4093 case SHIFTJIS_CHARSET
:
4094 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4096 case GB2312_CHARSET
:
4097 case CHINESEBIG5_CHARSET
:
4098 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4100 case HANGEUL_CHARSET
:
4101 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4104 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4110 /* test with an odd height */
4113 hfont
= CreateFontIndirectA(&lf
);
4116 *(HFONT
*)lParam
= hfont
;
4122 static void test_GetGlyphOutline(void)
4125 GLYPHMETRICS gm
, gm2
;
4127 HFONT hfont
, old_hfont
;
4129 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4130 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4138 {ANSI_CHARSET
, 0x30, 0x30},
4139 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4140 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4141 {GB2312_CHARSET
, 0x8141, 0x4e04},
4142 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4146 if (!is_truetype_font_installed("Tahoma"))
4148 skip("Tahoma is not installed\n");
4152 hdc
= CreateCompatibleDC(0);
4153 memset(&lf
, 0, sizeof(lf
));
4155 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4156 SetLastError(0xdeadbeef);
4157 hfont
= CreateFontIndirectA(&lf
);
4158 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4159 old_hfont
= SelectObject(hdc
, hfont
);
4161 memset(&gm
, 0, sizeof(gm
));
4162 SetLastError(0xdeadbeef);
4163 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4164 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4166 memset(&gm
, 0, sizeof(gm
));
4167 SetLastError(0xdeadbeef);
4168 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4169 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4170 ok(GetLastError() == 0xdeadbeef ||
4171 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4172 "expected 0xdeadbeef, got %u\n", GetLastError());
4174 memset(&gm
, 0, sizeof(gm
));
4175 SetLastError(0xdeadbeef);
4176 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4177 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4178 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4180 memset(&gm
, 0, sizeof(gm
));
4181 SetLastError(0xdeadbeef);
4182 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4183 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4185 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4186 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4189 /* test for needed buffer size request on space char */
4190 memset(&gm
, 0, sizeof(gm
));
4191 SetLastError(0xdeadbeef);
4192 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4193 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4194 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4196 /* requesting buffer size for space char + error */
4197 memset(&gm
, 0, sizeof(gm
));
4198 SetLastError(0xdeadbeef);
4199 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4200 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4202 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4203 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4206 for (i
= 0; i
< sizeof(fmt
) / sizeof(fmt
[0]); ++i
)
4210 memset(&gm
, 0xab, sizeof(gm
));
4211 SetLastError(0xdeadbeef);
4212 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4213 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4215 if (fmt
[i
] == GGO_METRICS
)
4216 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4218 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4219 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4220 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4223 memset(&gm
, 0xab, sizeof(gm
));
4224 SetLastError(0xdeadbeef);
4225 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4226 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4228 if (fmt
[i
] == GGO_METRICS
)
4229 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4231 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4232 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4233 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4236 memset(&gm
, 0xab, sizeof(gm
));
4237 SetLastError(0xdeadbeef);
4238 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4239 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4241 if (fmt
[i
] == GGO_METRICS
)
4242 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4244 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4245 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4246 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4249 memset(&gm
, 0xab, sizeof(gm
));
4250 SetLastError(0xdeadbeef);
4251 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4252 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4254 if (fmt
[i
] == GGO_METRICS
) {
4255 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4256 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4257 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4261 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4262 memset(&gm2
, 0xab, sizeof(gm2
));
4263 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4264 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4269 SelectObject(hdc
, old_hfont
);
4270 DeleteObject(hfont
);
4272 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
4274 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4277 lf
.lfFaceName
[0] = '\0';
4278 lf
.lfCharSet
= c
[i
].cs
;
4279 lf
.lfPitchAndFamily
= 0;
4280 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4282 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4286 old_hfont
= SelectObject(hdc
, hfont
);
4288 /* expected to ignore superfluous bytes (sigle-byte character) */
4289 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4290 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4291 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4293 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4294 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4295 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4297 /* expected to ignore superfluous bytes (double-byte character) */
4298 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4299 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4300 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4301 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4303 /* expected to match wide-char version results */
4304 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4305 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4307 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4309 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4312 DeleteObject(SelectObject(hdc
, hfont
));
4315 DeleteObject(SelectObject(hdc
, old_hfont
));
4319 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4320 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4322 ret
= GetTextMetricsA(hdc
, &tm
);
4323 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4324 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4325 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4326 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
4327 -lf
.lfHeight
, tm
.tmAveCharWidth
, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4328 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4329 "expected %d, got %d (%s:%d)\n",
4330 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4332 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4333 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4334 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4335 "expected %d, got %d (%s:%d)\n",
4336 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4339 hfont
= CreateFontIndirectA(&lf
);
4340 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4341 DeleteObject(SelectObject(hdc
, hfont
));
4342 ret
= GetTextMetricsA(hdc
, &tm
);
4343 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4344 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4345 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4346 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4347 "expected %d, got %d (%s:%d)\n",
4348 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4350 lf
.lfItalic
= FALSE
;
4351 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4352 hfont
= CreateFontIndirectA(&lf
);
4353 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4354 DeleteObject(SelectObject(hdc
, hfont
));
4355 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4356 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4357 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4358 "expected %d, got %d (%s:%d)\n",
4359 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4361 hfont
= SelectObject(hdc
, old_hfont
);
4362 DeleteObject(hfont
);
4368 /* bug #9995: there is a limit to the character width that can be specified */
4369 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4375 int ave_width
, height
, width
, ratio
, scale
;
4377 if (!is_truetype_font_installed( fontname
)) {
4378 skip("%s is not installed\n", fontname
);
4381 hdc
= CreateCompatibleDC(0);
4382 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4383 /* select width = 0 */
4384 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4385 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4386 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4388 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4389 of
= SelectObject( hdc
, hf
);
4390 ret
= GetTextMetricsA( hdc
, &tm
);
4391 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4392 height
= tm
.tmHeight
;
4393 ave_width
= tm
.tmAveCharWidth
;
4394 SelectObject( hdc
, of
);
4397 trace("height %d, ave width %d\n", height
, ave_width
);
4399 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4401 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4402 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4403 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4404 ok(hf
!= 0, "CreateFont failed\n");
4405 of
= SelectObject(hdc
, hf
);
4406 ret
= GetTextMetricsA(hdc
, &tm
);
4407 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4408 SelectObject(hdc
, of
);
4411 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4417 ratio
= width
/ height
;
4418 scale
= width
/ ave_width
;
4420 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
4421 width
, height
, ratio
, width
, ave_width
, scale
);
4423 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4426 static void test_CreateFontIndirect(void)
4428 LOGFONTA lf
, getobj_lf
;
4431 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
4433 memset(&lf
, 0, sizeof(lf
));
4434 lf
.lfCharSet
= ANSI_CHARSET
;
4435 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4438 lf
.lfQuality
= DEFAULT_QUALITY
;
4439 lf
.lfItalic
= FALSE
;
4440 lf
.lfWeight
= FW_DONTCARE
;
4442 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
4444 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4445 hfont
= CreateFontIndirectA(&lf
);
4446 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4447 SetLastError(0xdeadbeef);
4448 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
4449 ok(ret
, "GetObject failed: %d\n", GetLastError());
4450 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
4451 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
4452 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
4453 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
4454 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
4455 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
4456 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
4457 DeleteObject(hfont
);
4461 static void test_CreateFontIndirectEx(void)
4463 ENUMLOGFONTEXDVA lfex
;
4466 if (!pCreateFontIndirectExA
)
4468 win_skip("CreateFontIndirectExA is not available\n");
4472 if (!is_truetype_font_installed("Arial"))
4474 skip("Arial is not installed\n");
4478 SetLastError(0xdeadbeef);
4479 hfont
= pCreateFontIndirectExA(NULL
);
4480 ok(hfont
== NULL
, "got %p\n", hfont
);
4481 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
4483 memset(&lfex
, 0, sizeof(lfex
));
4484 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
4485 hfont
= pCreateFontIndirectExA(&lfex
);
4486 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
4488 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
4489 DeleteObject(hfont
);
4492 static void free_font(void *font
)
4494 UnmapViewOfFile(font
);
4497 static void *load_font(const char *font_name
, DWORD
*font_size
)
4499 char file_name
[MAX_PATH
];
4500 HANDLE file
, mapping
;
4503 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
4504 strcat(file_name
, "\\fonts\\");
4505 strcat(file_name
, font_name
);
4507 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
4508 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
4510 *font_size
= GetFileSize(file
, NULL
);
4512 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4519 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
4522 CloseHandle(mapping
);
4526 static void test_AddFontMemResource(void)
4529 DWORD font_size
, num_fonts
;
4533 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
4535 win_skip("AddFontMemResourceEx is not available on this platform\n");
4539 font
= load_font("sserife.fon", &font_size
);
4542 skip("Unable to locate and load font sserife.fon\n");
4546 SetLastError(0xdeadbeef);
4547 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
4548 ok(!ret
, "AddFontMemResourceEx should fail\n");
4549 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4550 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4553 SetLastError(0xdeadbeef);
4554 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
4555 ok(!ret
, "AddFontMemResourceEx should fail\n");
4556 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4557 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4560 SetLastError(0xdeadbeef);
4561 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
4562 ok(!ret
, "AddFontMemResourceEx should fail\n");
4563 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4564 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4567 SetLastError(0xdeadbeef);
4568 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
4569 ok(!ret
, "AddFontMemResourceEx should fail\n");
4570 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4571 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4574 SetLastError(0xdeadbeef);
4575 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
4576 ok(!ret
, "AddFontMemResourceEx should fail\n");
4577 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4578 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4581 SetLastError(0xdeadbeef);
4582 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
4583 ok(!ret
, "AddFontMemResourceEx should fail\n");
4584 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4585 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4588 num_fonts
= 0xdeadbeef;
4589 SetLastError(0xdeadbeef);
4590 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
4591 ok(!ret
, "AddFontMemResourceEx should fail\n");
4592 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4593 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4595 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4597 if (0) /* hangs under windows 2000 */
4599 num_fonts
= 0xdeadbeef;
4600 SetLastError(0xdeadbeef);
4601 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
4602 ok(!ret
, "AddFontMemResourceEx should fail\n");
4603 ok(GetLastError() == 0xdeadbeef,
4604 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4606 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4609 num_fonts
= 0xdeadbeef;
4610 SetLastError(0xdeadbeef);
4611 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
4612 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
4613 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4614 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
4618 SetLastError(0xdeadbeef);
4619 bRet
= pRemoveFontMemResourceEx(ret
);
4620 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
4622 /* test invalid pointer to number of loaded fonts */
4623 font
= load_font("sserife.fon", &font_size
);
4624 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
4626 SetLastError(0xdeadbeef);
4627 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
4628 ok(!ret
, "AddFontMemResourceEx should fail\n");
4629 ok(GetLastError() == 0xdeadbeef,
4630 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4633 SetLastError(0xdeadbeef);
4634 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
4635 ok(!ret
, "AddFontMemResourceEx should fail\n");
4636 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4637 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4643 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4647 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4649 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4651 lf
= (LOGFONTA
*)lparam
;
4656 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4661 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4663 lf
= (LOGFONTA
*)lparam
;
4664 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
4667 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4674 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
4679 static void test_EnumFonts(void)
4684 struct enum_fullname_data efnd
;
4686 if (!is_truetype_font_installed("Arial"))
4688 skip("Arial is not installed\n");
4692 /* Windows uses localized font face names, so Arial Bold won't be found */
4693 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
4695 skip("User locale is not English, skipping the test\n");
4699 hdc
= CreateCompatibleDC(0);
4701 /* check that the enumproc's retval is returned */
4702 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
4703 ok(ret
== 0xcafe, "got %08x\n", ret
);
4705 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
4706 ok(!ret
, "font Arial is not enumerated\n");
4707 ret
= strcmp(lf
.lfFaceName
, "Arial");
4708 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4709 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4711 strcpy(lf
.lfFaceName
, "Arial");
4712 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4713 ok(!ret
, "font Arial is not enumerated\n");
4714 ret
= strcmp(lf
.lfFaceName
, "Arial");
4715 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4716 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4718 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4719 ok(!ret
, "font Arial Bold is not enumerated\n");
4720 ret
= strcmp(lf
.lfFaceName
, "Arial");
4721 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4722 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4724 strcpy(lf
.lfFaceName
, "Arial Bold");
4725 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4726 ok(ret
, "font Arial Bold should not be enumerated\n");
4728 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
4729 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
4730 ret
= strcmp(lf
.lfFaceName
, "Arial");
4731 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4732 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4734 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
4735 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4736 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
4738 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4739 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4741 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
4742 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4743 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4745 /* MS Shell Dlg and MS Shell Dlg 2 must exist */
4746 memset(&lf
, 0, sizeof(lf
));
4747 lf
.lfCharSet
= DEFAULT_CHARSET
;
4749 memset(&efnd
, 0, sizeof(efnd
));
4750 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
4751 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4752 ok(ret
, "font MS Shell Dlg is not enumerated\n");
4753 ret
= strcmp((char*)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
4754 todo_wine
ok(!ret
, "expected MS Shell Dlg got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
4755 ret
= strcmp((char*)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
4756 ok(ret
, "did not expect MS Shell Dlg\n");
4758 memset(&efnd
, 0, sizeof(efnd
));
4759 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
4760 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4761 ok(ret
, "font MS Shell Dlg 2 is not enumerated\n");
4762 ret
= strcmp((char*)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
4763 todo_wine
ok(!ret
, "expected MS Shell Dlg 2 got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
4764 ret
= strcmp((char*)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
4765 ok(ret
, "did not expect MS Shell Dlg 2\n");
4770 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4772 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
4773 const char *fullname
= (const char *)lParam
;
4775 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
4780 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
4785 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
4792 static void test_fullname(void)
4794 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4795 WCHAR bufW
[LF_FULLFACESIZE
];
4796 char bufA
[LF_FULLFACESIZE
];
4803 hdc
= CreateCompatibleDC(0);
4804 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4806 memset(&lf
, 0, sizeof(lf
));
4807 lf
.lfCharSet
= ANSI_CHARSET
;
4808 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4811 lf
.lfQuality
= DEFAULT_QUALITY
;
4812 lf
.lfItalic
= FALSE
;
4813 lf
.lfWeight
= FW_DONTCARE
;
4815 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
4817 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
4819 skip("%s is not installed\n", TestName
[i
]);
4823 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4824 hfont
= CreateFontIndirectA(&lf
);
4825 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4827 of
= SelectObject(hdc
, hfont
);
4830 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4831 ok(ret
, "face full name could not be read\n");
4832 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
4833 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
4834 SelectObject(hdc
, of
);
4835 DeleteObject(hfont
);
4840 static WCHAR
*prepend_at(WCHAR
*family
)
4845 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
4850 static void test_fullname2_helper(const char *Family
)
4852 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
4853 struct enum_fullname_data efnd
;
4860 DWORD otm_size
, ret
, buf_size
;
4861 OUTLINETEXTMETRICA
*otm
;
4862 BOOL want_vertical
, get_vertical
;
4863 want_vertical
= ( Family
[0] == '@' );
4865 hdc
= CreateCompatibleDC(0);
4866 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4868 memset(&lf
, 0, sizeof(lf
));
4869 lf
.lfCharSet
= DEFAULT_CHARSET
;
4870 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4873 lf
.lfQuality
= DEFAULT_QUALITY
;
4874 lf
.lfItalic
= FALSE
;
4875 lf
.lfWeight
= FW_DONTCARE
;
4876 strcpy(lf
.lfFaceName
, Family
);
4878 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4879 if (efnd
.total
== 0)
4880 skip("%s is not installed\n", lf
.lfFaceName
);
4882 for (i
= 0; i
< efnd
.total
; i
++)
4884 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
4885 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
4886 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
4888 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family
, FamilyName
, FaceName
, StyleName
);
4890 get_vertical
= ( FamilyName
[0] == '@' );
4891 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
4893 lstrcpyA(lf
.lfFaceName
, FaceName
);
4894 hfont
= CreateFontIndirectA(&lf
);
4895 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4897 of
= SelectObject(hdc
, hfont
);
4898 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
4899 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
4900 if (buf_size
== GDI_ERROR
) continue;
4902 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4903 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4905 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
4906 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
4907 memset(otm
, 0, otm_size
);
4908 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
4909 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
4910 if (ret
== 0) continue;
4914 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4917 trace("no localized FONT_FAMILY found.\n");
4918 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4920 ok(ret
, "FAMILY (family name) could not be read\n");
4921 if (want_vertical
) bufW
= prepend_at(bufW
);
4922 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4923 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
4924 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
4925 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
4929 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
4932 trace("no localized FULL_NAME found.\n");
4933 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4935 ok(ret
, "FULL_NAME (face name) could not be read\n");
4936 if (want_vertical
) bufW
= prepend_at(bufW
);
4937 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4938 ok(!lstrcmpA(FaceName
, bufA
), "font face names don't match: returned %s, expect %s\n", FaceName
, bufA
);
4939 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
4940 ok(!lstrcmpA(FaceName
, otmStr
), "FaceName %s doesn't match otmpFaceName %s\n", FaceName
, otmStr
);
4944 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4947 trace("no localized FONT_SUBFAMILY found.\n");
4948 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4950 ok(ret
, "SUBFAMILY (style name) could not be read\n");
4951 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4952 ok(!lstrcmpA(StyleName
, bufA
), "style names don't match: returned %s, expect %s\n", StyleName
, bufA
);
4953 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
4954 ok(!lstrcmpA(StyleName
, otmStr
), "StyleName %s doesn't match otmpStyleName %s\n", StyleName
, otmStr
);
4958 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
4961 trace("no localized UNIQUE_ID found.\n");
4962 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4964 ok(ret
, "UNIQUE_ID (full name) could not be read\n");
4965 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4966 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
4967 ok(!lstrcmpA(otmStr
, bufA
), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr
, bufA
);
4969 SelectObject(hdc
, of
);
4970 DeleteObject(hfont
);
4972 HeapFree(GetProcessHeap(), 0, otm
);
4973 HeapFree(GetProcessHeap(), 0, bufW
);
4974 HeapFree(GetProcessHeap(), 0, bufA
);
4979 static void test_fullname2(void)
4981 test_fullname2_helper("Arial");
4982 test_fullname2_helper("DejaVu Sans");
4983 test_fullname2_helper("Lucida Sans");
4984 test_fullname2_helper("Tahoma");
4985 test_fullname2_helper("Webdings");
4986 test_fullname2_helper("Wingdings");
4987 test_fullname2_helper("SimSun");
4988 test_fullname2_helper("NSimSun");
4989 test_fullname2_helper("MingLiu");
4990 test_fullname2_helper("PMingLiu");
4991 test_fullname2_helper("WenQuanYi Micro Hei");
4992 test_fullname2_helper("MS UI Gothic");
4993 test_fullname2_helper("Ume UI Gothic");
4994 test_fullname2_helper("MS Gothic");
4995 test_fullname2_helper("Ume Gothic");
4996 test_fullname2_helper("MS PGothic");
4997 test_fullname2_helper("Ume P Gothic");
4998 test_fullname2_helper("Gulim");
4999 test_fullname2_helper("Batang");
5000 test_fullname2_helper("UnBatang");
5001 test_fullname2_helper("UnDotum");
5002 test_fullname2_helper("@SimSun");
5003 test_fullname2_helper("@NSimSun");
5004 test_fullname2_helper("@MingLiu");
5005 test_fullname2_helper("@PMingLiu");
5006 test_fullname2_helper("@WenQuanYi Micro Hei");
5007 test_fullname2_helper("@MS UI Gothic");
5008 test_fullname2_helper("@Ume UI Gothic");
5009 test_fullname2_helper("@MS Gothic");
5010 test_fullname2_helper("@Ume Gothic");
5011 test_fullname2_helper("@MS PGothic");
5012 test_fullname2_helper("@Ume P Gothic");
5013 test_fullname2_helper("@Gulim");
5014 test_fullname2_helper("@Batang");
5015 test_fullname2_helper("@UnBatang");
5016 test_fullname2_helper("@UnDotum");
5020 static void test_GetGlyphOutline_empty_contour(void)
5024 HFONT hfont
, hfont_prev
;
5025 TTPOLYGONHEADER
*header
;
5030 memset(&lf
, 0, sizeof(lf
));
5032 lstrcpyA(lf
.lfFaceName
, "wine_test");
5034 hfont
= CreateFontIndirectA(&lf
);
5035 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5039 hfont_prev
= SelectObject(hdc
, hfont
);
5040 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5042 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5043 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5045 header
= (TTPOLYGONHEADER
*)buf
;
5046 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5047 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5048 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5049 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5050 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5051 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5052 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5053 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5055 SelectObject(hdc
, hfont_prev
);
5056 DeleteObject(hfont
);
5057 ReleaseDC(NULL
, hdc
);
5060 static void test_GetGlyphOutline_metric_clipping(void)
5064 HFONT hfont
, hfont_prev
;
5069 memset(&lf
, 0, sizeof(lf
));
5071 lstrcpyA(lf
.lfFaceName
, "wine_test");
5073 SetLastError(0xdeadbeef);
5074 hfont
= CreateFontIndirectA(&lf
);
5075 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5079 hfont_prev
= SelectObject(hdc
, hfont
);
5080 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5082 SetLastError(0xdeadbeef);
5083 ret
= GetTextMetricsA(hdc
, &tm
);
5084 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5086 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5087 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5088 "Glyph top(%d) exceeds ascent(%d)\n",
5089 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5090 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5091 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5092 "Glyph bottom(%d) exceeds descent(%d)\n",
5093 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5095 SelectObject(hdc
, hfont_prev
);
5096 DeleteObject(hfont
);
5097 ReleaseDC(NULL
, hdc
);
5100 static void test_CreateScalableFontResource(void)
5102 char ttf_name
[MAX_PATH
];
5103 char tmp_path
[MAX_PATH
];
5104 char fot_name
[MAX_PATH
];
5109 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
5111 win_skip("AddFontResourceExA is not available on this platform\n");
5115 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5117 skip("Failed to create ttf file for testing\n");
5121 trace("created %s\n", ttf_name
);
5123 ret
= is_truetype_font_installed("wine_test");
5124 ok(!ret
, "font wine_test should not be enumerated\n");
5126 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
5127 ok(ret
, "GetTempPath() error %d\n", GetLastError());
5128 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
5129 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
5131 ret
= GetFileAttributesA(fot_name
);
5132 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
5134 SetLastError(0xdeadbeef);
5135 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5136 ok(!ret
, "CreateScalableFontResource() should fail\n");
5137 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5139 SetLastError(0xdeadbeef);
5140 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
5141 ok(!ret
, "CreateScalableFontResource() should fail\n");
5142 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5144 file_part
= strrchr(ttf_name
, '\\');
5145 SetLastError(0xdeadbeef);
5146 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
5147 ok(!ret
, "CreateScalableFontResource() should fail\n");
5148 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5150 SetLastError(0xdeadbeef);
5151 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
5152 ok(!ret
, "CreateScalableFontResource() should fail\n");
5153 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5155 SetLastError(0xdeadbeef);
5156 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
5157 ok(!ret
, "CreateScalableFontResource() should fail\n");
5158 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
5160 ret
= DeleteFileA(fot_name
);
5161 ok(ret
, "DeleteFile() error %d\n", GetLastError());
5163 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5164 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5166 /* test public font resource */
5167 SetLastError(0xdeadbeef);
5168 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5169 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5171 ret
= is_truetype_font_installed("wine_test");
5172 ok(!ret
, "font wine_test should not be enumerated\n");
5174 SetLastError(0xdeadbeef);
5175 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5176 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5178 ret
= is_truetype_font_installed("wine_test");
5179 ok(ret
, "font wine_test should be enumerated\n");
5181 test_GetGlyphOutline_empty_contour();
5182 test_GetGlyphOutline_metric_clipping();
5184 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5185 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
5187 SetLastError(0xdeadbeef);
5188 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5189 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5191 ret
= is_truetype_font_installed("wine_test");
5192 ok(!ret
, "font wine_test should not be enumerated\n");
5194 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5195 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5197 /* test refcounting */
5198 for (i
= 0; i
< 5; i
++)
5200 SetLastError(0xdeadbeef);
5201 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5202 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5204 for (i
= 0; i
< 5; i
++)
5206 SetLastError(0xdeadbeef);
5207 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5208 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5210 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5211 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5213 DeleteFileA(fot_name
);
5215 /* test hidden font resource */
5216 SetLastError(0xdeadbeef);
5217 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
5218 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
5220 ret
= is_truetype_font_installed("wine_test");
5221 ok(!ret
, "font wine_test should not be enumerated\n");
5223 SetLastError(0xdeadbeef);
5224 ret
= pAddFontResourceExA(fot_name
, 0, 0);
5225 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
5227 ret
= is_truetype_font_installed("wine_test");
5229 ok(!ret
, "font wine_test should not be enumerated\n");
5231 /* XP allows removing a private font added with 0 flags */
5232 SetLastError(0xdeadbeef);
5233 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
5234 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5236 ret
= is_truetype_font_installed("wine_test");
5237 ok(!ret
, "font wine_test should not be enumerated\n");
5239 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
5240 ok(!ret
, "RemoveFontResourceEx() should fail\n");
5242 DeleteFileA(fot_name
);
5243 DeleteFileA(ttf_name
);
5246 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
5249 HFONT hfont
, hfont_prev
;
5253 static const WCHAR str
[] = { 0x2025 };
5255 *installed
= is_truetype_font_installed(name
);
5259 lf
.lfEscapement
= 0;
5260 lf
.lfOrientation
= 0;
5261 lf
.lfWeight
= FW_DONTCARE
;
5265 lf
.lfCharSet
= DEFAULT_CHARSET
;
5266 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
5267 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5268 lf
.lfQuality
= DEFAULT_QUALITY
;
5269 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
5270 strcpy(lf
.lfFaceName
, name
);
5272 hfont
= CreateFontIndirectA(&lf
);
5273 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
5277 hfont_prev
= SelectObject(hdc
, hfont
);
5278 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5280 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
5281 ok(ret
, "GetTextFaceA failed\n");
5282 *selected
= !strcmp(facename
, name
);
5284 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
5285 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5287 memset(gm
, 0, sizeof *gm
);
5289 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
5290 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
5292 SelectObject(hdc
, hfont_prev
);
5293 DeleteObject(hfont
);
5294 ReleaseDC(NULL
, hdc
);
5297 static void check_vertical_metrics(const char *face
)
5300 HFONT hfont
, hfont_prev
;
5303 GLYPHMETRICS rgm
, vgm
;
5304 const UINT code
= 0x5EAD, height
= 1000;
5307 OUTLINETEXTMETRICA otm
;
5308 USHORT numOfLongVerMetrics
;
5312 memset(&lf
, 0, sizeof(lf
));
5313 strcpy(lf
.lfFaceName
, face
);
5314 lf
.lfHeight
= -height
;
5315 lf
.lfCharSet
= DEFAULT_CHARSET
;
5316 lf
.lfEscapement
= lf
.lfOrientation
= 900;
5317 hfont
= CreateFontIndirectA(&lf
);
5318 hfont_prev
= SelectObject(hdc
, hfont
);
5319 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
5320 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5321 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
5322 ok(ret
, "GetCharABCWidthsW failed\n");
5323 DeleteObject(SelectObject(hdc
, hfont_prev
));
5325 memset(&lf
, 0, sizeof(lf
));
5326 strcpy(lf
.lfFaceName
, "@");
5327 strcat(lf
.lfFaceName
, face
);
5328 lf
.lfHeight
= -height
;
5329 lf
.lfCharSet
= DEFAULT_CHARSET
;
5330 hfont
= CreateFontIndirectA(&lf
);
5331 hfont_prev
= SelectObject(hdc
, hfont
);
5332 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
5333 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
5335 memset(&otm
, 0, sizeof(otm
));
5336 otm
.otmSize
= sizeof(otm
);
5337 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
5338 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
5340 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
5341 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
5343 SHORT topSideBearing
;
5345 if (!pGetGlyphIndicesW
) {
5346 win_skip("GetGlyphIndices is not available on this platform\n");
5349 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
5350 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
5351 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
5352 if (numOfLongVerMetrics
> idx
)
5353 offset
= idx
* 2 + 1;
5355 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
5356 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
5357 &topSideBearing
, sizeof(SHORT
));
5358 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
5359 topSideBearing
= GET_BE_WORD(topSideBearing
);
5360 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
5361 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
5362 "expected %d, got %d\n",
5363 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
5368 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
5369 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
5370 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
5373 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
5374 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
5375 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
5376 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
5378 DeleteObject(SelectObject(hdc
, hfont_prev
));
5379 ReleaseDC(NULL
, hdc
);
5382 static void test_vertical_font(void)
5384 char ttf_name
[MAX_PATH
];
5386 BOOL ret
, installed
, selected
;
5389 const char* face_list
[] = {
5390 "@WineTestVertical", /* has vmtx table */
5391 "@Ume Gothic", /* doesn't have vmtx table */
5392 "@MS UI Gothic", /* has vmtx table, available on native */
5395 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
5397 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
5401 if (!write_ttf_file("vertical.ttf", ttf_name
))
5403 skip("Failed to create ttf file for testing\n");
5407 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5408 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
5410 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
5411 ok(installed
, "WineTestVertical is not installed\n");
5412 ok(selected
, "WineTestVertical is not selected\n");
5413 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5414 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
5415 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5417 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
5418 ok(installed
, "@WineTestVertical is not installed\n");
5419 ok(selected
, "@WineTestVertical is not selected\n");
5420 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
5421 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
5422 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
5424 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
5426 for (i
= 0; i
< sizeof(face_list
)/sizeof(face_list
[0]); i
++) {
5427 const char* face
= face_list
[i
];
5428 if (!is_truetype_font_installed(face
)) {
5429 skip("%s is not installed\n", face
);
5432 trace("Testing %s...\n", face
);
5433 check_vertical_metrics(&face
[1]);
5436 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
5437 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
5439 DeleteFileA(ttf_name
);
5442 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
5443 DWORD type
, LPARAM lParam
)
5445 if (lf
->lfFaceName
[0] == '@') {
5451 static void test_east_asian_font_selection(void)
5454 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
5455 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
5460 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
5464 char face_name
[LF_FACESIZE
];
5467 memset(&lf
, 0, sizeof lf
);
5468 lf
.lfFaceName
[0] = '\0';
5469 lf
.lfCharSet
= charset
[i
];
5471 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
5473 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
5477 hfont
= CreateFontIndirectA(&lf
);
5478 hfont
= SelectObject(hdc
, hfont
);
5479 memset(face_name
, 0, sizeof face_name
);
5480 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5481 ok(ret
&& face_name
[0] != '@',
5482 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5483 DeleteObject(SelectObject(hdc
, hfont
));
5485 memset(&lf
, 0, sizeof lf
);
5486 strcpy(lf
.lfFaceName
, "@");
5487 lf
.lfCharSet
= charset
[i
];
5488 hfont
= CreateFontIndirectA(&lf
);
5489 hfont
= SelectObject(hdc
, hfont
);
5490 memset(face_name
, 0, sizeof face_name
);
5491 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
5492 ok(ret
&& face_name
[0] == '@',
5493 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
5494 DeleteObject(SelectObject(hdc
, hfont
));
5496 ReleaseDC(NULL
, hdc
);
5499 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
5501 HDC hdc
= CreateCompatibleDC(0);
5506 hfont
= CreateFontIndirectA(lf
);
5507 ok(hfont
!= 0, "CreateFontIndirect failed\n");
5509 SelectObject(hdc
, hfont
);
5510 ret
= GetTextMetricsA(hdc
, &tm
);
5511 ok(ret
, "GetTextMetrics failed\n");
5512 ret
= tm
.tmDigitizedAspectX
;
5513 if (height
) *height
= tm
.tmHeight
;
5516 DeleteObject(hfont
);
5521 static void test_stock_fonts(void)
5523 static const int font
[] =
5525 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
5526 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
5528 static const struct test_data
5530 int charset
, weight
, height
, height_pixels
, dpi
;
5531 const char face_name
[LF_FACESIZE
];
5534 { /* ANSI_FIXED_FONT */
5535 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
5536 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
5539 { /* ANSI_VAR_FONT */
5540 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
5541 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
5545 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5546 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5547 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5548 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5549 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5550 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5553 { /* DEVICE_DEFAULT_FONT */
5554 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
5555 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
5556 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
5557 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
5558 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
5559 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
5562 { /* DEFAULT_GUI_FONT */
5563 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
5564 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
5565 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
5566 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
5567 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
5568 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
5569 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
5570 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
5571 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
5572 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
5578 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
5584 hfont
= GetStockObject(font
[i
]);
5585 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
5587 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
5588 if (ret
!= sizeof(lf
))
5591 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
5595 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
5597 if (lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
)
5602 ret
= get_font_dpi(&lf
, &height
);
5603 if (ret
!= td
[i
][j
].dpi
)
5605 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5606 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
5610 /* FIXME: Remove once Wine is fixed */
5611 if (td
[i
][j
].dpi
!= 96 &&
5612 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
5613 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
5614 /* System for 120 dpi and higher should include 20 pixel bitmap set */
5615 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
5617 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5619 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
5621 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
5622 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
5623 if (td
[i
][j
].face_name
[0] == '?')
5625 /* Wine doesn't have this font, skip this case for now.
5626 Actually, the face name is localized on Windows and varies
5627 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5628 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
5632 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
);
5639 static void test_max_height(void)
5643 HFONT hfont
, hfont_old
;
5644 TEXTMETRICA tm1
, tm
;
5646 LONG invalid_height
[] = { -65536, -123456, 123456 };
5649 memset(&tm1
, 0, sizeof(tm1
));
5650 memset(&lf
, 0, sizeof(lf
));
5651 strcpy(lf
.lfFaceName
, "Tahoma");
5656 /* get 1 ppem value */
5657 hfont
= CreateFontIndirectA(&lf
);
5658 hfont_old
= SelectObject(hdc
, hfont
);
5659 r
= GetTextMetricsA(hdc
, &tm1
);
5660 ok(r
, "GetTextMetrics failed\n");
5661 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5662 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5663 DeleteObject(SelectObject(hdc
, hfont_old
));
5665 /* test the largest value */
5666 lf
.lfHeight
= -((1 << 16) - 1);
5667 hfont
= CreateFontIndirectA(&lf
);
5668 hfont_old
= SelectObject(hdc
, hfont
);
5669 memset(&tm
, 0, sizeof(tm
));
5670 r
= GetTextMetricsA(hdc
, &tm
);
5671 ok(r
, "GetTextMetrics failed\n");
5672 ok(tm
.tmHeight
> tm1
.tmHeight
,
5673 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5674 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
5675 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5676 DeleteObject(SelectObject(hdc
, hfont_old
));
5678 /* test an invalid value */
5679 for (i
= 0; i
< sizeof(invalid_height
)/sizeof(invalid_height
[0]); i
++) {
5680 lf
.lfHeight
= invalid_height
[i
];
5681 hfont
= CreateFontIndirectA(&lf
);
5682 hfont_old
= SelectObject(hdc
, hfont
);
5683 memset(&tm
, 0, sizeof(tm
));
5684 r
= GetTextMetricsA(hdc
, &tm
);
5685 ok(r
, "GetTextMetrics failed\n");
5686 ok(tm
.tmHeight
== tm1
.tmHeight
,
5687 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5688 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
5689 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5690 DeleteObject(SelectObject(hdc
, hfont_old
));
5693 ReleaseDC(NULL
, hdc
);
5697 static void test_vertical_order(void)
5699 struct enum_font_data efd
;
5704 hdc
= CreateCompatibleDC(0);
5705 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5707 memset(&lf
, 0, sizeof(lf
));
5708 lf
.lfCharSet
= DEFAULT_CHARSET
;
5709 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5712 lf
.lfQuality
= DEFAULT_QUALITY
;
5713 lf
.lfItalic
= FALSE
;
5714 lf
.lfWeight
= FW_DONTCARE
;
5716 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
5717 for (i
= 0; i
< efd
.total
; i
++)
5719 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
5720 for (j
= 0; j
< efd
.total
; j
++)
5722 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
5724 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
5732 static void test_GetCharWidth32(void)
5742 if (!pGetCharWidth32A
|| !pGetCharWidth32W
)
5744 win_skip("GetCharWidth32A/W not available on this platform\n");
5748 memset(&lf
, 0, sizeof(lf
));
5749 strcpy(lf
.lfFaceName
, "System");
5752 hfont
= CreateFontIndirectA(&lf
);
5754 hfont
= SelectObject(hdc
, hfont
);
5756 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5757 ok(ret
, "GetCharWidth32W should have succeeded\n");
5758 ret
= pGetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
5759 ok(ret
, "GetCharWidth32A should have succeeded\n");
5760 ok (bufferA
== bufferW
, "Widths should be the same\n");
5761 ok (bufferA
> 0," Width should be greater than zero\n");
5763 hfont
= SelectObject(hdc
, hfont
);
5764 DeleteObject(hfont
);
5765 ReleaseDC(NULL
, hdc
);
5767 memset(&lf
, 0, sizeof(lf
));
5768 strcpy(lf
.lfFaceName
, "Tahoma");
5771 hfont
= CreateFontIndirectA(&lf
);
5772 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
5775 SetMapMode( hdc
, MM_ANISOTROPIC
);
5776 SelectObject(hdc
, hfont
);
5778 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5779 ok(ret
, "GetCharWidth32W should have succeeded\n");
5780 ok (bufferW
> 0," Width should be greater than zero\n");
5781 SetWindowExtEx(hdc
, -1,-1,NULL
);
5782 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5783 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5784 ok(ret
, "GetCharWidth32W should have succeeded\n");
5785 ok (bufferW
> 0," Width should be greater than zero\n");
5786 SetGraphicsMode(hdc
, GM_ADVANCED
);
5787 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5788 ok(ret
, "GetCharWidth32W should have succeeded\n");
5789 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
5790 SetWindowExtEx(hdc
, 1,1,NULL
);
5791 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5792 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5793 ok(ret
, "GetCharWidth32W should have succeeded\n");
5794 ok (bufferW
> 0," Width should be greater than zero\n");
5795 SetGraphicsMode(hdc
, GM_ADVANCED
);
5796 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5797 ok(ret
, "GetCharWidth32W should have succeeded\n");
5798 ok (bufferW
> 0," Width should be greater than zero\n");
5800 ReleaseDC(hwnd
, hdc
);
5801 DestroyWindow(hwnd
);
5803 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
5806 SetMapMode( hdc
, MM_ANISOTROPIC
);
5807 SelectObject(hdc
, hfont
);
5809 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5810 ok(ret
, "GetCharWidth32W should have succeeded\n");
5811 ok (bufferW
> 0," Width should be greater than zero\n");
5812 SetWindowExtEx(hdc
, -1,-1,NULL
);
5813 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5814 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5815 ok(ret
, "GetCharWidth32W should have succeeded\n");
5816 ok (bufferW
> 0," Width should be greater than zero\n");
5817 SetGraphicsMode(hdc
, GM_ADVANCED
);
5818 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5819 ok(ret
, "GetCharWidth32W should have succeeded\n");
5820 ok (bufferW
> 0," Width should be greater than zero\n");
5821 SetWindowExtEx(hdc
, 1,1,NULL
);
5822 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
5823 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5824 ok(ret
, "GetCharWidth32W should have succeeded\n");
5825 ok (bufferW
> 0," Width should be greater than zero\n");
5826 SetGraphicsMode(hdc
, GM_ADVANCED
);
5827 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
5828 ok(ret
, "GetCharWidth32W should have succeeded\n");
5829 todo_wine
ok (bufferW
> 0," Width should be greater than zero\n");
5831 ReleaseDC(hwnd
, hdc
);
5832 DestroyWindow(hwnd
);
5833 DeleteObject(hfont
);
5836 static void test_fake_bold_font(void)
5839 HFONT hfont
, hfont_old
;
5846 if (!pGetCharWidth32A
|| !pGetCharABCWidthsA
) {
5847 win_skip("GetCharWidth32A/GetCharABCWidthA is not available on this platform\n");
5851 /* Test outline font */
5852 memset(&lf
, 0, sizeof(lf
));
5853 strcpy(lf
.lfFaceName
, "Wingdings");
5854 lf
.lfWeight
= FW_NORMAL
;
5855 lf
.lfCharSet
= SYMBOL_CHARSET
;
5856 hfont
= CreateFontIndirectA(&lf
);
5859 hfont_old
= SelectObject(hdc
, hfont
);
5862 ret
= GetTextMetricsA(hdc
, &tm
[0]);
5863 ok(ret
, "got %d\n", ret
);
5864 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[0]);
5865 ok(ret
, "got %d\n", ret
);
5867 lf
.lfWeight
= FW_BOLD
;
5868 hfont
= CreateFontIndirectA(&lf
);
5869 DeleteObject(SelectObject(hdc
, hfont
));
5872 ret
= GetTextMetricsA(hdc
, &tm
[1]);
5873 ok(ret
, "got %d\n", ret
);
5874 ret
= pGetCharABCWidthsA(hdc
, 0x76, 0x76, &abc
[1]);
5875 ok(ret
, "got %d\n", ret
);
5877 DeleteObject(SelectObject(hdc
, hfont_old
));
5878 ReleaseDC(NULL
, hdc
);
5880 /* compare results (outline) */
5881 ok(tm
[0].tmHeight
== tm
[1].tmHeight
, "expected %d, got %d\n", tm
[0].tmHeight
, tm
[1].tmHeight
);
5882 ok(tm
[0].tmAscent
== tm
[1].tmAscent
, "expected %d, got %d\n", tm
[0].tmAscent
, tm
[1].tmAscent
);
5883 ok(tm
[0].tmDescent
== tm
[1].tmDescent
, "expected %d, got %d\n", tm
[0].tmDescent
, tm
[1].tmDescent
);
5884 ok((tm
[0].tmAveCharWidth
+ 1) == tm
[1].tmAveCharWidth
,
5885 "expected %d, got %d\n", tm
[0].tmAveCharWidth
+ 1, tm
[1].tmAveCharWidth
);
5886 ok((tm
[0].tmMaxCharWidth
+ 1) == tm
[1].tmMaxCharWidth
,
5887 "expected %d, got %d\n", tm
[0].tmMaxCharWidth
+ 1, tm
[1].tmMaxCharWidth
);
5888 ok(tm
[0].tmOverhang
== tm
[1].tmOverhang
, "expected %d, got %d\n", tm
[0].tmOverhang
, tm
[1].tmOverhang
);
5889 w
[0] = abc
[0].abcA
+ abc
[0].abcB
+ abc
[0].abcC
;
5890 w
[1] = abc
[1].abcA
+ abc
[1].abcB
+ abc
[1].abcC
;
5891 ok((w
[0] + 1) == w
[1], "expected %d, got %d\n", w
[0] + 1, w
[1]);
5895 static void test_bitmap_font_glyph_index(void)
5897 const WCHAR text
[] = {'#','!','/','b','i','n','/','s','h',0};
5901 } bitmap_font_list
[] = {
5902 { "Courier", ANSI_CHARSET
},
5903 { "Small Fonts", ANSI_CHARSET
},
5904 { "Fixedsys", DEFAULT_CHARSET
},
5905 { "System", DEFAULT_CHARSET
}
5910 CHAR facename
[LF_FACESIZE
];
5921 if (!pGetGlyphIndicesW
|| !pGetGlyphIndicesA
) {
5922 win_skip("GetGlyphIndices is unavailable\n");
5926 hdc
= CreateCompatibleDC(0);
5927 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5929 memset(&bmi
, 0, sizeof(bmi
));
5930 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
5931 bmi
.bmiHeader
.biBitCount
= 32;
5932 bmi
.bmiHeader
.biPlanes
= 1;
5933 bmi
.bmiHeader
.biWidth
= 128;
5934 bmi
.bmiHeader
.biHeight
= 32;
5935 bmi
.bmiHeader
.biCompression
= BI_RGB
;
5937 for (i
= 0; i
< sizeof(bitmap_font_list
)/sizeof(bitmap_font_list
[0]); i
++) {
5938 memset(&lf
, 0, sizeof(lf
));
5939 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
5940 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
5941 hFont
= CreateFontIndirectA(&lf
);
5942 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
5943 hFont
= SelectObject(hdc
, hFont
);
5944 ret
= GetTextMetricsA(hdc
, &tm
);
5945 ok(ret
, "GetTextMetric failed\n");
5946 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
5947 ok(ret
, "GetTextFace failed\n");
5948 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
5949 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
5952 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
5953 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
5957 for (j
= 0; j
< 2; j
++) {
5959 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
5960 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
5961 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
5964 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
5968 int len
= lstrlenW(text
);
5969 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
5970 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
5971 ok(ret
, "GetGlyphIndices failed\n");
5972 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
5973 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
5974 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
5975 HeapFree(GetProcessHeap(), 0, indices
);
5979 ok(ret
, "ExtTextOutW failed\n");
5980 SelectObject(hdc
, hBmpPrev
);
5983 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
5984 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
5985 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
5987 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
5989 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
5992 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
5993 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
5997 for (j
= 0; j
< 2; j
++) {
6000 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6003 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6006 ret
= pGetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6007 ok(ret
, "GetGlyphIndices failed\n");
6008 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6009 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6012 ok(ret
, "ExtTextOutA failed\n");
6013 SelectObject(hdc
, hBmpPrev
);
6016 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6017 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6019 for (j
= 0; j
< 2; j
++)
6020 DeleteObject(hBmp
[j
]);
6021 hFont
= SelectObject(hdc
, hFont
);
6022 DeleteObject(hFont
);
6035 test_outline_font();
6036 test_bitmap_font_metrics();
6037 test_GdiGetCharDimensions();
6038 test_GetCharABCWidths();
6039 test_text_extents();
6040 test_GetGlyphIndices();
6041 test_GetKerningPairs();
6042 test_GetOutlineTextMetrics();
6043 test_SetTextJustification();
6044 test_font_charset();
6045 test_GdiGetCodePage();
6046 test_GetFontUnicodeRanges();
6047 test_nonexistent_font();
6049 test_height_selection();
6050 test_AddFontMemResource();
6053 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
6054 * I'd like to avoid them in this test.
6056 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
6057 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
6058 if (is_truetype_font_installed("Arial Black") &&
6059 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
6061 test_EnumFontFamilies("", ANSI_CHARSET
);
6062 test_EnumFontFamilies("", SYMBOL_CHARSET
);
6063 test_EnumFontFamilies("", DEFAULT_CHARSET
);
6066 skip("Arial Black or Symbol/Wingdings is not installed\n");
6067 test_EnumFontFamiliesEx_default_charset();
6068 test_GetTextMetrics();
6069 test_GdiRealizationInfo();
6071 test_GetGlyphOutline();
6072 test_GetTextMetrics2("Tahoma", -11);
6073 test_GetTextMetrics2("Tahoma", -55);
6074 test_GetTextMetrics2("Tahoma", -110);
6075 test_GetTextMetrics2("Arial", -11);
6076 test_GetTextMetrics2("Arial", -55);
6077 test_GetTextMetrics2("Arial", -110);
6078 test_CreateFontIndirect();
6079 test_CreateFontIndirectEx();
6083 test_east_asian_font_selection();
6085 test_vertical_order();
6086 test_GetCharWidth32();
6087 test_fake_bold_font();
6088 test_bitmap_font_glyph_index();
6090 /* These tests should be last test until RemoveFontResource
6091 * is properly implemented.
6093 test_vertical_font();
6094 test_CreateScalableFontResource();