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
32 #include "wine/heap.h"
33 #include "wine/test.h"
35 static inline BOOL
match_off_by_n(int a
, int b
, unsigned int n
)
37 return abs(a
- b
) <= n
;
39 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
40 #define near_match(a, b) match_off_by_n((a), (b), 6)
41 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
43 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
44 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
45 static BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
46 static BOOL (WINAPI
*pGetCharWidth32W
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
47 static BOOL (WINAPI
*pGetCharWidthInfo
)(HDC hdc
, void *);
48 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
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
);
58 static BOOL (WINAPI
*pGetFontRealizationInfo
)(HDC hdc
, DWORD
*);
59 static BOOL (WINAPI
*pGetFontFileInfo
)(DWORD
, DWORD
, void *, SIZE_T
, SIZE_T
*);
60 static BOOL (WINAPI
*pGetFontFileData
)(DWORD
, DWORD
, UINT64
, void *, DWORD
);
62 static HMODULE hgdi32
= 0;
63 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
64 static WORD system_lang_id
;
66 #ifdef WORDS_BIGENDIAN
67 #define GET_BE_WORD(x) (x)
68 #define GET_BE_DWORD(x) (x)
70 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
71 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
74 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
75 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
76 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
77 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
78 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
79 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
81 static void init(void)
83 hgdi32
= GetModuleHandleA("gdi32.dll");
85 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
86 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
87 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
88 pGetCharWidth32W
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32W");
89 pGetCharWidthInfo
= (void *)GetProcAddress(hgdi32
, "GetCharWidthInfo");
90 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
91 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
92 pGetTextExtentExPointI
= (void *)GetProcAddress(hgdi32
, "GetTextExtentExPointI");
93 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
94 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
95 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
96 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
97 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
98 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
99 pGetFontRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GetFontRealizationInfo");
100 pGetFontFileInfo
= (void *)GetProcAddress(hgdi32
, "GetFontFileInfo");
101 pGetFontFileData
= (void *)GetProcAddress(hgdi32
, "GetFontFileData");
103 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
106 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
108 if (type
!= TRUETYPE_FONTTYPE
) return 1;
113 static BOOL
is_truetype_font_installed(const char *name
)
118 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
125 static INT CALLBACK
is_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
130 static BOOL
is_font_installed(const char *name
)
135 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
142 static void *get_res_data(const char *fontname
, DWORD
*rsrc_size
)
147 rsrc
= FindResourceA(GetModuleHandleA(NULL
), fontname
, (LPCSTR
)RT_RCDATA
);
148 if (!rsrc
) return NULL
;
150 rsrc_data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
151 if (!rsrc_data
) return NULL
;
153 *rsrc_size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
154 if (!*rsrc_size
) return NULL
;
159 static BOOL
write_tmp_file( const void *data
, DWORD
*size
, char *tmp_name
)
161 char tmp_path
[MAX_PATH
];
165 GetTempPathA(MAX_PATH
, tmp_path
);
166 GetTempFileNameA(tmp_path
, "ttf", 0, tmp_name
);
168 hfile
= CreateFileA(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
169 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
171 ret
= WriteFile(hfile
, data
, *size
, size
, NULL
);
177 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
182 rsrc_data
= get_res_data( fontname
, &rsrc_size
);
183 if (!rsrc_data
) return FALSE
;
185 return write_tmp_file( rsrc_data
, &rsrc_size
, tmp_name
);
188 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
196 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
197 /* NT4 tries to be clever and only returns the minimum length */
198 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
200 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
201 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
202 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
203 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
204 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
205 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
206 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
207 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
208 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
209 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
210 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
211 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
212 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
213 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
214 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
215 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
216 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
217 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
218 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
219 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
220 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
221 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
222 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
223 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
224 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
225 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
226 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
227 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
230 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
232 HFONT hfont
= CreateFontIndirectA(lf
);
233 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
235 check_font(test
, lf
, hfont
);
239 static void test_logfont(void)
244 memset(&lf
, 0, sizeof lf
);
246 lf
.lfCharSet
= ANSI_CHARSET
;
247 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
248 lf
.lfWeight
= FW_DONTCARE
;
251 lf
.lfQuality
= DEFAULT_QUALITY
;
253 lstrcpyA(lf
.lfFaceName
, "Arial");
254 hfont
= create_font("Arial", &lf
);
257 memset(&lf
, 'A', sizeof(lf
));
258 hfont
= CreateFontIndirectA(&lf
);
259 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
261 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
262 check_font("AAA...", &lf
, hfont
);
266 static INT CALLBACK
font_enum_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
268 if (type
& RASTER_FONTTYPE
)
270 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
272 return 0; /* stop enumeration */
275 return 1; /* continue enumeration */
278 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
280 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
281 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
282 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
283 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
284 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
285 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
286 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
287 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
288 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
289 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
290 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
291 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
292 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
293 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
294 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
295 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
296 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
297 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
298 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
299 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
302 static void test_font_metrics(const char *context
,
303 HDC hdc
, HFONT hfont
, LONG lfHeight
,
304 LONG lfWidth
, const char *test_str
,
305 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
306 const SIZE
*size_orig
, INT width_of_A_orig
,
307 INT scale_x
, INT scale_y
)
310 OUTLINETEXTMETRICA otm
;
313 INT width_of_A
, cx
, cy
;
319 if (context
) winetest_push_context("%s", context
);
320 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
322 GetObjectA(hfont
, sizeof(lf
), &lf
);
324 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
326 otm
.otmSize
= sizeof(otm
) / 2;
327 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
328 ok(ret
== sizeof(otm
)/2 /* XP */ ||
329 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
331 memset(&otm
, 0x1, sizeof(otm
));
332 otm
.otmSize
= sizeof(otm
);
333 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
334 ok(ret
== sizeof(otm
) /* XP */ ||
335 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
337 memset(&tm
, 0x2, sizeof(tm
));
338 ret
= GetTextMetricsA(hdc
, &tm
);
339 ok(ret
, "GetTextMetricsA failed\n");
340 /* the structure size is aligned */
341 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
343 ok(0, "tm != otm\n");
344 compare_tm(&tm
, &otm
.otmTextMetrics
);
347 tm
= otm
.otmTextMetrics
;
348 if (0) /* these metrics are scaled too, but with rounding errors */
350 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
351 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
353 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
354 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
355 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
356 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
357 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
358 if (otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_TRUETYPE
)
359 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
363 ret
= GetTextMetricsA(hdc
, &tm
);
364 ok(ret
, "GetTextMetricsA failed\n");
367 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
368 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
369 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
370 lfHeight
, scale_x
, scale_y
, cx
, cy
);
371 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
372 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
373 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
374 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
375 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
377 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
381 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
384 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
386 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
388 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
389 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
391 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
393 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
);
394 if (context
) winetest_pop_context();
397 /* Test how GDI scales bitmap font metrics */
398 static void test_bitmap_font(void)
400 static const char test_str
[11] = "Test String";
403 HFONT hfont
, old_hfont
;
406 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
408 hdc
= CreateCompatibleDC(0);
410 /* "System" has only 1 pixel size defined, otherwise the test breaks */
411 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
415 skip("no bitmap fonts were found, skipping the test\n");
419 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
421 height_orig
= bitmap_lf
.lfHeight
;
422 lfWidth
= bitmap_lf
.lfWidth
;
424 hfont
= create_font("bitmap", &bitmap_lf
);
425 old_hfont
= SelectObject(hdc
, hfont
);
426 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
427 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
428 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
429 SelectObject(hdc
, old_hfont
);
432 bitmap_lf
.lfHeight
= 0;
433 bitmap_lf
.lfWidth
= 4;
434 hfont
= create_font("bitmap", &bitmap_lf
);
435 old_hfont
= SelectObject(hdc
, hfont
);
436 test_font_metrics("bitmap", hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
437 SelectObject(hdc
, old_hfont
);
440 bitmap_lf
.lfHeight
= height_orig
;
441 bitmap_lf
.lfWidth
= lfWidth
;
443 /* test fractional scaling */
444 for (i
= 1; i
<= height_orig
* 6; i
++)
448 bitmap_lf
.lfHeight
= i
;
449 hfont
= create_font("fractional", &bitmap_lf
);
450 scale
= (i
+ height_orig
- 1) / height_orig
;
451 nearest_height
= scale
* height_orig
;
452 /* Only jump to the next height if the difference <= 25% original height */
453 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
454 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
455 so we'll not test this particular height. */
456 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
457 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
458 old_hfont
= SelectObject(hdc
, hfont
);
459 winetest_push_context("height %i", i
);
460 test_font_metrics(NULL
, hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
461 winetest_pop_context();
462 SelectObject(hdc
, old_hfont
);
466 /* test integer scaling 3x2 */
467 bitmap_lf
.lfHeight
= height_orig
* 2;
468 bitmap_lf
.lfWidth
*= 3;
469 hfont
= create_font("3x2", &bitmap_lf
);
470 old_hfont
= SelectObject(hdc
, hfont
);
471 test_font_metrics("bitmap 3x2", hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
472 SelectObject(hdc
, old_hfont
);
475 /* test integer scaling 3x3 */
476 bitmap_lf
.lfHeight
= height_orig
* 3;
477 bitmap_lf
.lfWidth
= 0;
478 hfont
= create_font("3x3", &bitmap_lf
);
479 old_hfont
= SelectObject(hdc
, hfont
);
480 test_font_metrics("bitmap 3x3", hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
481 SelectObject(hdc
, old_hfont
);
487 /* Test how GDI scales outline font metrics */
488 static void test_outline_font(void)
490 static const char test_str
[11] = "Test String";
493 HFONT hfont
, old_hfont
, old_hfont_2
;
494 OUTLINETEXTMETRICA otm
;
496 INT width_orig
, height_orig
, lfWidth
;
499 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
503 if (!is_truetype_font_installed("Arial"))
505 skip("Arial is not installed\n");
509 hdc
= CreateCompatibleDC(0);
511 memset(&lf
, 0, sizeof(lf
));
512 strcpy(lf
.lfFaceName
, "Arial");
514 hfont
= create_font("outline", &lf
);
515 old_hfont
= SelectObject(hdc
, hfont
);
516 otm
.otmSize
= sizeof(otm
);
517 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
518 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
519 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
521 test_font_metrics("outline", hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
522 SelectObject(hdc
, old_hfont
);
525 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
526 lf
.lfHeight
= otm
.otmEMSquare
;
527 lf
.lfHeight
= -lf
.lfHeight
;
528 hfont
= create_font("outline", &lf
);
529 old_hfont
= SelectObject(hdc
, hfont
);
530 otm
.otmSize
= sizeof(otm
);
531 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
532 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
533 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
534 SelectObject(hdc
, old_hfont
);
537 height_orig
= otm
.otmTextMetrics
.tmHeight
;
538 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
540 /* test integer scaling 3x2 */
541 lf
.lfHeight
= height_orig
* 2;
542 lf
.lfWidth
= lfWidth
* 3;
543 hfont
= create_font("3x2", &lf
);
544 old_hfont
= SelectObject(hdc
, hfont
);
545 test_font_metrics("outline 3x2", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
546 SelectObject(hdc
, old_hfont
);
549 /* test integer scaling 3x3 */
550 lf
.lfHeight
= height_orig
* 3;
551 lf
.lfWidth
= lfWidth
* 3;
552 hfont
= create_font("3x3", &lf
);
553 old_hfont
= SelectObject(hdc
, hfont
);
554 test_font_metrics("outline 3x3", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
555 SelectObject(hdc
, old_hfont
);
558 /* test integer scaling 1x1 */
559 lf
.lfHeight
= height_orig
* 1;
560 lf
.lfWidth
= lfWidth
* 1;
561 hfont
= create_font("1x1", &lf
);
562 old_hfont
= SelectObject(hdc
, hfont
);
563 test_font_metrics("outline 1x1", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
564 SelectObject(hdc
, old_hfont
);
567 /* test integer scaling 1x1 */
568 lf
.lfHeight
= height_orig
;
570 hfont
= create_font("1x1", &lf
);
571 old_hfont
= SelectObject(hdc
, hfont
);
572 test_font_metrics("outline 1x0", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
574 /* with an identity matrix */
575 memset(&gm
, 0, sizeof(gm
));
576 SetLastError(0xdeadbeef);
577 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
578 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
579 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
580 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
581 /* with a custom matrix */
582 memset(&gm
, 0, sizeof(gm
));
583 SetLastError(0xdeadbeef);
584 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
585 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
586 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
587 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
589 /* Test that changing the DC transformation affects only the font
590 * selected on this DC and doesn't affect the same font selected on
593 hdc_2
= CreateCompatibleDC(0);
594 old_hfont_2
= SelectObject(hdc_2
, hfont
);
595 test_font_metrics("dc2.base", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
597 SetMapMode(hdc
, MM_ANISOTROPIC
);
599 /* font metrics on another DC should be unchanged */
600 test_font_metrics("dc2.aniso", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
602 /* test restrictions of compatibility mode GM_COMPATIBLE */
603 /* part 1: rescaling only X should not change font scaling on screen.
604 So compressing the X axis by 2 is not done, and this
605 appears as X scaling of 2 that no one requested. */
606 SetWindowExtEx(hdc
, 100, 100, NULL
);
607 SetViewportExtEx(hdc
, 50, 100, NULL
);
608 test_font_metrics("xscaling", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
609 /* font metrics on another DC should be unchanged */
610 test_font_metrics("dc2.xscaling", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
612 /* part 2: rescaling only Y should change font scaling.
613 As also X is scaled by a factor of 2, but this is not
614 requested by the DC transformation, we get a scaling factor
615 of 2 in the X coordinate. */
616 SetViewportExtEx(hdc
, 100, 200, NULL
);
617 test_font_metrics("yscaling", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics("dc2.yscaling", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
621 /* restore scaling */
622 SetMapMode(hdc
, MM_TEXT
);
624 /* font metrics on another DC should be unchanged */
625 test_font_metrics("dc2.text", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
627 SelectObject(hdc_2
, old_hfont_2
);
630 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
632 SelectObject(hdc
, old_hfont
);
635 skip("GM_ADVANCED is not supported on this platform\n");
646 SetLastError(0xdeadbeef);
647 ret
= SetWorldTransform(hdc
, &xform
);
648 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
650 test_font_metrics("xform", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
652 /* with an identity matrix */
653 memset(&gm
, 0, sizeof(gm
));
654 SetLastError(0xdeadbeef);
655 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
656 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
657 pt
.x
= width_orig
; pt
.y
= 0;
659 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
660 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
661 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
662 /* with a custom matrix */
663 memset(&gm
, 0, sizeof(gm
));
664 SetLastError(0xdeadbeef);
665 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
666 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
667 pt
.x
= width_orig
; pt
.y
= 0;
669 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
670 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
671 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
673 SetLastError(0xdeadbeef);
674 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
675 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
677 test_font_metrics("lometric", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
679 /* with an identity matrix */
680 memset(&gm
, 0, sizeof(gm
));
681 SetLastError(0xdeadbeef);
682 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
683 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
684 pt
.x
= width_orig
; pt
.y
= 0;
686 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
687 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
688 /* with a custom matrix */
689 memset(&gm
, 0, sizeof(gm
));
690 SetLastError(0xdeadbeef);
691 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
692 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
693 pt
.x
= width_orig
; pt
.y
= 0;
695 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
696 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
698 SetLastError(0xdeadbeef);
699 ret
= SetMapMode(hdc
, MM_TEXT
);
700 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
702 test_font_metrics("text", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
704 /* with an identity matrix */
705 memset(&gm
, 0, sizeof(gm
));
706 SetLastError(0xdeadbeef);
707 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
708 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
709 pt
.x
= width_orig
; pt
.y
= 0;
711 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
712 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
713 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
714 /* with a custom matrix */
715 memset(&gm
, 0, sizeof(gm
));
716 SetLastError(0xdeadbeef);
717 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
718 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
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 WORD skip_rtl
[] = {LANG_ARABIC
, LANG_HEBREW
, 0};
751 static const struct font_data
753 const char face_name
[LF_FACESIZE
];
754 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
755 int ave_char_width
, max_char_width
, dpi
;
756 BYTE first_char
, last_char
, def_char
, break_char
;
758 const WORD
*skip_lang_id
;
762 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
763 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
764 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
765 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
766 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
767 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
768 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 13 },
769 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
770 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
, 16 },
771 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
773 { "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 },
774 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
775 { "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 },
776 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
777 { "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 },
778 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
779 { "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 },
780 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
781 { "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 },
782 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
784 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
785 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
786 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
787 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
788 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
789 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
790 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
791 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
792 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
793 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
794 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
795 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
796 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
797 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
798 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
799 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
801 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
802 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
803 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
804 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
805 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
806 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
807 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
808 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
809 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
810 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
811 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
812 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
814 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
815 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
816 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
817 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
818 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
819 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
820 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
821 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
822 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
823 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
824 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
825 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
826 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
827 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
828 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
829 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
830 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
832 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
833 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
834 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
835 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
836 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
837 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
838 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
839 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
840 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
841 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
842 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
844 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
845 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
846 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
848 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
849 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
850 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
852 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
853 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
854 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
856 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
857 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
859 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
860 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
861 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
862 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
863 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
864 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
865 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
866 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
867 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
868 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
869 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
870 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
871 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
872 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
873 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
},
874 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
875 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
876 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
877 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, skip_rtl
},
878 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
879 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
881 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
882 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
883 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
884 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
885 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
886 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
887 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
888 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
889 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
890 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
891 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
892 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
894 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
895 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
896 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
898 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
900 /* FIXME: add "Terminal" */
902 static const int font_log_pixels
[] = { 96, 120 };
905 HFONT hfont
, old_hfont
;
907 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
908 char face_name
[LF_FACESIZE
];
911 trace("system language id %04x\n", system_lang_id
);
913 expected_cs
= GetACP();
914 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
916 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
919 expected_cs
= csi
.ciCharset
;
920 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
922 hdc
= CreateCompatibleDC(0);
923 ok(hdc
!= NULL
, "failed to create hdc\n");
925 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
926 GetDeviceCaps(hdc
, LOGPIXELSY
));
928 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
931 for (i
= 0; i
< ARRAY_SIZE(font_log_pixels
); i
++)
933 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
937 font_res
= font_log_pixels
[i
];
940 trace("best font resolution is %d\n", font_res
);
942 for (i
= 0; i
< ARRAY_SIZE(fd
); i
++)
946 memset(&lf
, 0, sizeof(lf
));
948 height
= fd
[i
].height
& ~FH_SCALE
;
949 lf
.lfHeight
= height
;
950 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
952 for(bit
= 0; bit
< 32; bit
++)
960 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
961 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
963 lf
.lfCharSet
= csi
.ciCharset
;
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 todo_wine_if (ret
) /* FIXME: Remove once Wine is fixed */
972 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
975 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
978 hfont
= create_font(lf
.lfFaceName
, &lf
);
979 old_hfont
= SelectObject(hdc
, hfont
);
981 SetLastError(0xdeadbeef);
982 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
983 ok(ret
, "GetTextFace error %u\n", GetLastError());
985 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
987 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
988 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
989 SelectObject(hdc
, old_hfont
);
994 memset(&gm
, 0, sizeof(gm
));
995 SetLastError(0xdeadbeef);
996 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
998 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
999 ret
= GetLastError();
1000 ok(ret
== ERROR_CAN_NOT_COMPLETE
|| ret
== 0xdeadbeef /* Win10 */, "Unexpected error %d.\n", ret
);
1002 bRet
= GetTextMetricsA(hdc
, &tm
);
1003 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
1005 SetLastError(0xdeadbeef);
1006 ret
= GetTextCharset(hdc
);
1007 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1008 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1010 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1012 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1015 if (fd
[i
].skip_lang_id
)
1019 while(!skipme
&& fd
[i
].skip_lang_id
[si
])
1020 if (fd
[i
].skip_lang_id
[si
++] == system_lang_id
)
1025 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1026 if (fd
[i
].height
& FH_SCALE
)
1027 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
);
1029 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
);
1030 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1031 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1032 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
);
1033 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
);
1034 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
);
1035 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1036 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1037 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1038 make default char test fail */
1039 if (tm
.tmCharSet
== lf
.lfCharSet
)
1040 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1041 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1042 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
);
1044 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1045 that make the max width bigger */
1046 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1047 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
);
1050 skip("Skipping font metrics test for system langid 0x%x\n",
1053 SelectObject(hdc
, old_hfont
);
1054 DeleteObject(hfont
);
1061 static void test_GdiGetCharDimensions(void)
1067 LONG avgwidth
, height
;
1068 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1070 if (!pGdiGetCharDimensions
)
1072 win_skip("GdiGetCharDimensions not available on this platform\n");
1076 hdc
= CreateCompatibleDC(NULL
);
1078 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1079 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1081 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1082 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1083 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1085 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1086 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1088 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1089 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1092 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1093 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1094 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1099 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1100 const TEXTMETRICA
*lpntme
,
1101 DWORD FontType
, LPARAM lParam
)
1103 if (FontType
& TRUETYPE_FONTTYPE
)
1107 hfont
= CreateFontIndirectA(lpelfe
);
1110 *(HFONT
*)lParam
= hfont
;
1118 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, const ABC
*base_abci
, const ABC
*base_abcw
, const ABCFLOAT
*base_abcf
)
1124 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1125 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1126 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1127 ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1128 ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1130 ret
= GetCharABCWidthsW(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 ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1134 ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1136 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1137 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1138 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1139 ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1140 ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1143 static void test_GetCharABCWidths(void)
1168 {0xffffff, 0xffffff},
1169 {0x1000000, 0x1000000},
1170 {0xffffff, 0x1000000},
1171 {0xffffffff, 0xffffffff},
1179 BOOL r
[ARRAY_SIZE(range
)];
1182 {ANSI_CHARSET
, 0x30, 0x30,
1183 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1184 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1185 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1186 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1187 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1188 {GB2312_CHARSET
, 0x8141, 0x4e04,
1189 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1190 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1191 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1195 if (!pGetCharABCWidthsFloatW
)
1197 win_skip("GetCharABCWidthsFloatW is not available on this platform\n");
1201 memset(&lf
, 0, sizeof(lf
));
1202 strcpy(lf
.lfFaceName
, "System");
1205 hfont
= CreateFontIndirectA(&lf
);
1207 hfont
= SelectObject(hdc
, hfont
);
1209 nb
= pGetGlyphIndicesW(hdc
, L
"i", 1, glyphs
, 0);
1210 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1212 ret
= GetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1213 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1215 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1216 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1218 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1219 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1221 ret
= GetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1222 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1224 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1225 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1227 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1228 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1230 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1231 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1233 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1234 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1236 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1237 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1239 hfont
= SelectObject(hdc
, hfont
);
1240 DeleteObject(hfont
);
1242 for (i
= 0; i
< ARRAY_SIZE(c
); ++i
)
1246 UINT code
= 0x41, j
;
1248 lf
.lfFaceName
[0] = '\0';
1249 lf
.lfCharSet
= c
[i
].cs
;
1250 lf
.lfPitchAndFamily
= 0;
1251 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1253 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1257 memset(a
, 0, sizeof a
);
1258 memset(w
, 0, sizeof w
);
1259 hfont
= SelectObject(hdc
, hfont
);
1260 ok(GetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) && GetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
)
1261 && !memcmp(a
, w
, sizeof(a
)),
1262 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1264 memset(a
, 0xbb, sizeof a
);
1265 ret
= GetCharABCWidthsA(hdc
, code
, code
, a
);
1266 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1267 memset(full
, 0xcc, sizeof full
);
1268 ret
= GetCharABCWidthsA(hdc
, 0x00, code
, full
);
1269 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1270 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1271 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1273 for (j
= 0; j
< ARRAY_SIZE(range
); ++j
)
1275 memset(full
, 0xdd, sizeof full
);
1276 ret
= GetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1277 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1278 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1281 UINT last
= range
[j
].last
- range
[j
].first
;
1282 ret
= GetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1283 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1284 "GetCharABCWidthsA %x should match. codepage = %u\n",
1285 range
[j
].last
, c
[i
].cs
);
1289 hfont
= SelectObject(hdc
, hfont
);
1290 DeleteObject(hfont
);
1293 memset(&lf
, 0, sizeof(lf
));
1294 strcpy(lf
.lfFaceName
, "Tahoma");
1296 hfont
= CreateFontIndirectA(&lf
);
1298 /* test empty glyph's metrics */
1299 hfont
= SelectObject(hdc
, hfont
);
1300 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1301 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1302 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1303 ret
= GetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1304 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1305 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1307 /* 1) prepare unrotated font metrics */
1308 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1309 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1310 DeleteObject(SelectObject(hdc
, hfont
));
1312 /* 2) get rotated font metrics */
1313 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1314 hfont
= CreateFontIndirectA(&lf
);
1315 hfont
= SelectObject(hdc
, hfont
);
1316 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1317 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1319 /* 3) compare ABC results */
1320 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1321 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1322 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1323 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1324 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1325 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1327 DeleteObject(SelectObject(hdc
, hfont
));
1329 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1330 in various widths. */
1331 for (i
= 1; i
<= 2; i
++)
1336 memset(&lf
, 0, sizeof(lf
));
1340 strcpy(lf
.lfFaceName
, "Tahoma");
1345 strcpy(lf
.lfFaceName
, "Times New Roman");
1349 if (!is_truetype_font_installed(lf
.lfFaceName
))
1351 skip("%s is not installed\n", lf
.lfFaceName
);
1354 for (j
= 1; j
<= 80; j
++)
1359 hfont
= CreateFontIndirectA(&lf
);
1360 hfont
= SelectObject(hdc
, hfont
);
1362 nb
= GetGlyphOutlineA(hdc
, code
, GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1363 ok(nb
, "GetGlyphOutlineA should have succeeded at width %d\n", i
);
1365 ret
= GetCharABCWidthsA(hdc
, code
, code
, abc
);
1366 ok(ret
, "GetCharABCWidthsA should have succeeded at width %d\n", i
);
1368 ok(abc
[0].abcA
== gm
.gmptGlyphOrigin
.x
,
1369 "abcA(%d) and gmptGlyphOrigin.x(%d) values are different at width %d\n",
1370 abc
[0].abcA
, gm
.gmptGlyphOrigin
.x
, i
);
1371 ok(abc
[0].abcB
== gm
.gmBlackBoxX
,
1372 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1373 abc
[0].abcB
, gm
.gmBlackBoxX
, i
);
1374 DeleteObject(SelectObject(hdc
, hfont
));
1377 ReleaseDC(NULL
, hdc
);
1379 /* ABC sign test for a variety of transforms */
1380 memset(&lf
, 0, sizeof(lf
));
1381 strcpy(lf
.lfFaceName
, "Tahoma");
1383 hfont
= CreateFontIndirectA(&lf
);
1384 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1387 SetMapMode(hdc
, MM_ANISOTROPIC
);
1388 SelectObject(hdc
, hfont
);
1390 nb
= pGetGlyphIndicesW(hdc
, L
"i", 1, glyphs
, 0);
1391 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1393 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1394 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1395 ret
= GetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1396 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1397 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1398 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1400 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
);
1401 SetWindowExtEx(hdc
, -1, -1, NULL
);
1402 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1403 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1404 SetGraphicsMode(hdc
, GM_ADVANCED
);
1405 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1406 SetWindowExtEx(hdc
, 1, 1, NULL
);
1407 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1408 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1409 SetGraphicsMode(hdc
, GM_ADVANCED
);
1410 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1412 ReleaseDC(hwnd
, hdc
);
1413 DestroyWindow(hwnd
);
1416 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1419 SetMapMode(hdc
, MM_ANISOTROPIC
);
1420 SelectObject(hdc
, hfont
);
1422 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
);
1423 SetWindowExtEx(hdc
, -1, -1, NULL
);
1424 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1425 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1426 SetGraphicsMode(hdc
, GM_ADVANCED
);
1427 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1428 SetWindowExtEx(hdc
, 1, 1, NULL
);
1429 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1430 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1431 SetGraphicsMode(hdc
, GM_ADVANCED
);
1432 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1434 ReleaseDC(hwnd
, hdc
);
1435 DestroyWindow(hwnd
);
1436 DeleteObject(hfont
);
1439 static void test_text_extents(void)
1441 static const WCHAR wt
[] = L
"One\ntwo 3";
1443 INT i
, len
, fit1
, fit2
, extents2
[3];
1452 memset(&lf
, 0, sizeof(lf
));
1453 strcpy(lf
.lfFaceName
, "Arial");
1456 hfont
= CreateFontIndirectA(&lf
);
1458 hfont
= SelectObject(hdc
, hfont
);
1459 GetTextMetricsA(hdc
, &tm
);
1460 ret
= GetTextExtentPointA(hdc
, "o", 1, &sz
);
1461 ok(ret
, "got %d\n", ret
);
1462 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1464 memset(&sz
, 0xcc, sizeof(sz
));
1465 ret
= GetTextExtentPointA(hdc
, "o", 0, &sz
);
1466 ok(ret
, "got %d\n", ret
);
1467 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1469 memset(&sz
, 0xcc, sizeof(sz
));
1470 ret
= GetTextExtentPointA(hdc
, "", 0, &sz
);
1471 ok(ret
, "got %d\n", ret
);
1472 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1474 SetLastError(0xdeadbeef);
1475 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1476 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1478 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1479 hfont
= SelectObject(hdc
, hfont
);
1480 DeleteObject(hfont
);
1485 memset(&sz
, 0xcc, sizeof(sz
));
1486 ret
= GetTextExtentPointW(hdc
, wt
, 0, &sz
);
1487 ok(ret
, "got %d\n", ret
);
1488 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1490 memset(&sz
, 0xcc, sizeof(sz
));
1491 ret
= GetTextExtentPointW(hdc
, L
"", 0, &sz
);
1492 ok(ret
, "got %d\n", ret
);
1493 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1496 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1497 extents
[0] = 1; /* So that the increasing sequence test will fail
1498 if the extents array is untouched. */
1499 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1500 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1501 ok(sz1
.cy
== sz2
.cy
,
1502 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1503 /* Because of the '\n' in the string GetTextExtentExPoint and
1504 GetTextExtentPoint return different widths under Win2k, but
1505 under WinXP they return the same width. So we don't test that
1508 for (i
= 1; i
< len
; ++i
)
1509 ok(extents
[i
-1] <= extents
[i
],
1510 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1512 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1513 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1514 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1515 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1516 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1517 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1518 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1519 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1520 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1521 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1522 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1523 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1524 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1525 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1527 /* extents functions fail with -ve counts (the interesting case being -1) */
1528 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1529 ok(ret
== FALSE
, "got %d\n", ret
);
1530 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1531 ok(ret
== FALSE
, "got %d\n", ret
);
1532 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1533 ok(ret
== FALSE
, "got %d\n", ret
);
1535 /* max_extent = 0 succeeds and returns zero */
1537 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1539 broken(ret
== FALSE
), /* NT4, 2k */
1542 broken(fit1
== -215), /* NT4, 2k */
1543 "fit = %d\n", fit1
);
1544 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1545 ok(ret
== TRUE
, "got %d\n", ret
);
1546 ok(fit2
== 0, "fit = %d\n", fit2
);
1548 /* max_extent = -1 is interpreted as a very large width that will
1549 * definitely fit our three characters */
1551 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1552 ok(ret
== TRUE
, "got %d\n", ret
);
1553 ok(fit1
== 3, "fit = %d\n", fit1
);
1554 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1555 ok(ret
== TRUE
, "got %d\n", ret
);
1556 ok(fit2
== 3, "fit = %d\n", fit2
);
1558 /* max_extent = -2 is interpreted similarly, but the Ansi version
1559 * rejects it while the Unicode one accepts it */
1561 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1562 ok(ret
== FALSE
, "got %d\n", ret
);
1563 ok(fit1
== -215, "fit = %d\n", fit1
);
1564 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1565 ok(ret
== TRUE
, "got %d\n", ret
);
1566 ok(fit2
== 3, "fit = %d\n", fit2
);
1568 hfont
= SelectObject(hdc
, hfont
);
1569 DeleteObject(hfont
);
1571 /* non-MM_TEXT mapping mode */
1573 hfont
= CreateFontIndirectA(&lf
);
1574 hfont
= SelectObject(hdc
, hfont
);
1576 SetMapMode( hdc
, MM_HIMETRIC
);
1577 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1578 ok(ret
, "got %d\n", ret
);
1579 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1581 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1582 ok(ret
, "got %d\n", ret
);
1583 ok(fit1
== 2, "got %d\n", fit1
);
1584 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1585 for(i
= 0; i
< 2; i
++)
1586 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1588 hfont
= SelectObject(hdc
, hfont
);
1589 DeleteObject(hfont
);
1590 HeapFree(GetProcessHeap(), 0, extents
);
1591 ReleaseDC(NULL
, hdc
);
1594 static void free_font(void *font
)
1596 UnmapViewOfFile(font
);
1599 static void *load_font(const char *font_name
, DWORD
*font_size
)
1601 char file_name
[MAX_PATH
];
1602 HANDLE file
, mapping
;
1605 if (font_name
[1] == ':')
1606 strcpy(file_name
, font_name
);
1609 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
1610 strcat(file_name
, "\\fonts\\");
1611 strcat(file_name
, font_name
);
1614 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
1615 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
1617 *font_size
= GetFileSize(file
, NULL
);
1619 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
1626 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
1629 CloseHandle(mapping
);
1633 static void test_GetGlyphIndices(void)
1640 WCHAR testtext
[] = L
"Test\xffff";
1641 WCHAR c
[] = { 0x25bc /* Black Down-Pointing Triangle */, 0x212a /* Kelvin Sign */ };
1642 WORD glyphs
[(sizeof(testtext
)/2)-1];
1646 DWORD ret
, font_size
, num_fonts
;
1648 char ttf_name
[MAX_PATH
];
1650 if (!pGetGlyphIndicesW
) {
1651 win_skip("GetGlyphIndicesW not available on platform\n");
1657 memset(&lf
, 0, sizeof(lf
));
1658 strcpy(lf
.lfFaceName
, "System");
1660 lf
.lfCharSet
= ANSI_CHARSET
;
1662 hfont
= CreateFontIndirectA(&lf
);
1663 ok(hfont
!= 0, "CreateFontIndirect failed\n");
1664 hOldFont
= SelectObject(hdc
, hfont
);
1665 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetrics failed\n");
1666 if (textm
.tmCharSet
== ANSI_CHARSET
)
1668 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1669 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1670 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1671 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1673 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1674 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1675 ok(glyphs
[4] == textm
.tmDefaultChar
|| glyphs
[4] == 0x20 /* CJK Windows */,
1676 "GetGlyphIndicesW should have returned a %04x not %04x\n", textm
.tmDefaultChar
, glyphs
[4]);
1679 /* FIXME: Write tests for non-ANSI charsets. */
1680 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1682 DeleteObject(SelectObject(hdc
, hOldFont
));
1684 memset(&lf
, 0, sizeof(lf
));
1685 strcpy(lf
.lfFaceName
, "MS Sans Serif");
1687 lf
.lfCharSet
= DEFAULT_CHARSET
;
1688 hfont
= CreateFontIndirectA(&lf
);
1689 ok(hfont
!= 0, "CreateFontIndirect failed\n");
1690 hOldFont
= SelectObject(hdc
, hfont
);
1691 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetrics failed\n");
1693 glyphs
[0] = glyphs
[1] = 0;
1694 charcount
= GetGlyphIndicesW(hdc
, c
, ARRAY_SIZE(c
), glyphs
, GGI_MARK_NONEXISTING_GLYPHS
);
1695 ok(charcount
== ARRAY_SIZE(c
), "got %u\n", charcount
);
1696 ok(glyphs
[0] == 0x001f || glyphs
[0] == 0xffff /* Vista */, "got %#x\n", glyphs
[0]);
1697 ok(glyphs
[1] == 0x001f || glyphs
[1] == 0xffff /* Vista */, "got %#x\n", glyphs
[1]);
1699 glyphs
[0] = glyphs
[1] = 0;
1700 charcount
= GetGlyphIndicesW(hdc
, c
, ARRAY_SIZE(c
), glyphs
, 0);
1701 ok(charcount
== ARRAY_SIZE(c
), "got %u\n", charcount
);
1702 ok(glyphs
[0] == textm
.tmDefaultChar
|| glyphs
[0] == 0x20 /* CJK Windows */, "got %#x\n", glyphs
[0]);
1703 ok(glyphs
[1] == textm
.tmDefaultChar
|| glyphs
[1] == 0x20 /* CJK Windows */, "got %#x\n", glyphs
[1]);
1705 DeleteObject(SelectObject(hdc
, hOldFont
));
1707 if(!is_font_installed("Tahoma"))
1709 skip("Tahoma is not installed so skipping this test\n");
1713 memset(&lf
, 0, sizeof(lf
));
1714 strcpy(lf
.lfFaceName
, "Tahoma");
1717 hfont
= CreateFontIndirectA(&lf
);
1718 hOldFont
= SelectObject(hdc
, hfont
);
1719 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1720 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1721 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1722 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1723 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1725 testtext
[0] = textm
.tmDefaultChar
;
1726 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1727 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1728 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1729 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1730 DeleteObject(SelectObject(hdc
, hOldFont
));
1732 ret
= write_ttf_file("wine_nul.ttf", ttf_name
);
1733 ok(ret
, "Failed to create test font file.\n");
1734 font
= load_font(ttf_name
, &font_size
);
1735 ok(font
!= NULL
, "Failed to map font file.\n");
1737 rsrc
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
1738 ok(ret
!= 0, "Failed to add resource, %d.\n", GetLastError());
1739 ok(num_fonts
== 1, "Unexpected number of fonts %u.\n", num_fonts
);
1741 memset(&lf
, 0, sizeof(lf
));
1742 strcpy(lf
.lfFaceName
, "wine_nul");
1745 hfont
= CreateFontIndirectA(&lf
);
1746 hOldFont
= SelectObject(hdc
, hfont
);
1747 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1749 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1750 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1751 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1752 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1753 DeleteObject(SelectObject(hdc
, hOldFont
));
1757 ret
= pRemoveFontMemResourceEx(rsrc
);
1758 ok(ret
, "RemoveFontMemResourceEx error %d\n", GetLastError());
1760 ret
= DeleteFileA(ttf_name
);
1761 ok(ret
, "Failed to delete font file, %d.\n", GetLastError());
1764 static void test_GetKerningPairs(void)
1766 static const struct kerning_data
1768 const char face_name
[LF_FACESIZE
];
1770 /* some interesting fields from OUTLINETEXTMETRIC */
1771 LONG tmHeight
, tmAscent
, tmDescent
;
1776 UINT otmsCapEmHeight
;
1781 UINT otmusMinimumPPEM
;
1782 /* small subset of kerning pairs to test */
1783 DWORD total_kern_pairs
;
1784 const KERNINGPAIR kern_pair
[26];
1787 {"Arial", 12, 12, 9, 3,
1788 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1791 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1792 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1793 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1794 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1795 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1796 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1797 {933,970,+1},{933,972,-1}
1800 {"Arial", -34, 39, 32, 7,
1801 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1804 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1805 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1806 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1807 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1808 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1809 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1810 {933,970,+2},{933,972,-3}
1813 { "Arial", 120, 120, 97, 23,
1814 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1817 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1818 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1819 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1820 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1821 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1822 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1823 {933,970,+6},{933,972,-10}
1826 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1827 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1828 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1831 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1832 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1833 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1834 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1835 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1836 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1837 {933,970,+54},{933,972,-83}
1843 HFONT hfont
, hfont_old
;
1844 KERNINGPAIR
*kern_pair
;
1846 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1850 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1851 * which may render this test unusable, so we're trying to avoid that.
1853 SetLastError(0xdeadbeef);
1854 GetKerningPairsW(hdc
, 0, NULL
);
1855 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1857 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1862 for (i
= 0; i
< ARRAY_SIZE(kd
); i
++)
1864 OUTLINETEXTMETRICW otm
;
1867 if (!is_font_installed(kd
[i
].face_name
))
1869 skip("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1873 memset(&lf
, 0, sizeof(lf
));
1874 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1875 lf
.lfHeight
= kd
[i
].height
;
1876 hfont
= CreateFontIndirectA(&lf
);
1877 ok(hfont
!= NULL
, "failed to create a font, name %s\n", kd
[i
].face_name
);
1879 hfont_old
= SelectObject(hdc
, hfont
);
1881 SetLastError(0xdeadbeef);
1882 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1883 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1884 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1886 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1887 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1888 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1889 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1890 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1891 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1893 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1894 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1895 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1896 kd
[i
].otmAscent
, otm
.otmAscent
);
1897 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1898 kd
[i
].otmDescent
, otm
.otmDescent
);
1899 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1900 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1901 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1902 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1903 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1904 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1906 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1907 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1909 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1910 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1911 ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1912 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1914 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1915 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1917 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1918 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1920 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1923 SetLastError(0xdeadbeef);
1924 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1925 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1926 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1927 ok(ret
== 0, "got %u, expected 0\n", ret
);
1929 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1930 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1932 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1933 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1935 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1936 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1940 for (n
= 0; n
< ret
; n
++)
1944 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1946 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1947 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1949 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1950 "pair %d:%d got %d, expected %d\n",
1951 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1952 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1958 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1959 matches
, kd
[i
].total_kern_pairs
);
1961 HeapFree(GetProcessHeap(), 0, kern_pair
);
1963 SelectObject(hdc
, hfont_old
);
1964 DeleteObject(hfont
);
1972 const char face_name
[LF_FACESIZE
];
1973 int requested_height
;
1974 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1978 static void test_height( HDC hdc
, const struct font_data
*fd
)
1981 HFONT hfont
, old_hfont
;
1985 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1987 if (!is_truetype_font_installed(fd
[i
].face_name
))
1989 skip("%s is not installed\n", fd
[i
].face_name
);
1993 memset(&lf
, 0, sizeof(lf
));
1994 lf
.lfHeight
= fd
[i
].requested_height
;
1995 lf
.lfWeight
= fd
[i
].weight
;
1996 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1998 hfont
= CreateFontIndirectA(&lf
);
1999 ok(hfont
!= NULL
, "failed to create a font, name %s\n", fd
[i
].face_name
);
2001 old_hfont
= SelectObject(hdc
, hfont
);
2002 ret
= GetTextMetricsA(hdc
, &tm
);
2003 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
2004 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
2006 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
);
2007 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
);
2008 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
);
2009 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
);
2010 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
);
2011 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
);
2014 SelectObject(hdc
, old_hfont
);
2015 /* force GDI to use new font, otherwise Windows leaks the font reference */
2016 GetTextMetricsA(hdc
, &tm
);
2017 DeleteObject(hfont
);
2021 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
2023 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
2024 DWORD
*table
= (DWORD
*)ttf
+ 3;
2026 for (i
= 0; i
< num_tables
; i
++)
2028 if (table
[0] == tag
)
2029 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
2035 static void test_height_selection_vdmx( HDC hdc
)
2037 static const struct font_data charset_0
[] = /* doesn't use VDMX */
2039 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2040 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2041 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2042 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2043 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2044 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
2045 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2046 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
2047 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
2048 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
2049 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
2050 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
2051 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
2052 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
2053 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2054 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
2055 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
2056 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
2057 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2058 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2059 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2060 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2061 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
2062 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2063 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
2064 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2065 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2066 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2067 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2068 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2069 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
2070 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
2071 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
2072 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
2073 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
2074 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
2075 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2076 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
2077 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
2078 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2079 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2080 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2081 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2082 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
2083 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
2084 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
2085 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
2086 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
2087 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
2088 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2089 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
2090 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2091 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2094 static const struct font_data charset_1
[] = /* Uses VDMX */
2096 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2097 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2098 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2099 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2100 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2101 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2102 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2103 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2104 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2105 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2106 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2107 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2108 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2109 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2110 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2111 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2112 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2113 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2114 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2115 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2116 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2117 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2118 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2119 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
2120 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
2121 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
2122 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2123 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2124 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2125 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2126 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2127 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2128 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2129 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2130 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2131 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2132 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2133 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2134 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2135 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2136 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2137 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
2138 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
2139 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
2140 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
2141 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
2142 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
2143 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
2144 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
2145 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
2146 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
2147 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
2148 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2151 static const struct vdmx_data
2155 const struct font_data
*fd
;
2158 { 0, 0, charset_0
},
2159 { 0, 1, charset_1
},
2160 { 1, 0, charset_0
},
2167 char ttf_name
[MAX_PATH
];
2171 if (!pAddFontResourceExA
)
2173 win_skip("AddFontResourceExA unavailable\n");
2177 for (i
= 0; i
< ARRAY_SIZE(data
); i
++)
2179 res
= get_res_data( "wine_vdmx.ttf", &size
);
2181 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2182 memcpy( copy
, res
, size
);
2183 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2184 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2185 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2186 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2187 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2188 ratio_rec
[0] = data
[i
].bCharSet
;
2190 write_tmp_file( copy
, &size
, ttf_name
);
2191 HeapFree( GetProcessHeap(), 0, copy
);
2193 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2194 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2195 if (!num
) win_skip("Unable to add ttf font resource\n");
2198 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2199 test_height( hdc
, data
[i
].fd
);
2200 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2202 ret
= DeleteFileA( ttf_name
);
2203 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
),
2204 "DeleteFile error %d\n", GetLastError());
2208 static void test_height_selection(void)
2210 static const struct font_data tahoma
[] =
2212 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2213 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2214 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2215 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2216 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2217 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2218 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2219 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2220 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2221 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2222 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2224 HDC hdc
= CreateCompatibleDC(0);
2225 ok(hdc
!= NULL
, "failed to create hdc\n");
2227 test_height( hdc
, tahoma
);
2228 test_height_selection_vdmx( hdc
);
2233 static UINT
get_font_fsselection(LOGFONTA
*lf
)
2235 OUTLINETEXTMETRICA
*otm
;
2236 HFONT hfont
, hfont_old
;
2237 DWORD ret
, otm_size
;
2242 hfont
= CreateFontIndirectA(lf
);
2243 ok(hfont
!= NULL
, "failed to create a font\n");
2245 hfont_old
= SelectObject(hdc
, hfont
);
2247 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2248 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2249 otm
->otmSize
= sizeof(*otm
);
2250 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2251 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2252 fsSelection
= otm
->otmfsSelection
;
2253 HeapFree(GetProcessHeap(), 0, otm
);
2254 SelectObject(hdc
, hfont_old
);
2255 DeleteObject(hfont
);
2261 static void test_GetOutlineTextMetrics(void)
2263 OUTLINETEXTMETRICA
*otm
;
2265 HFONT hfont
, hfont_old
;
2267 DWORD ret
, otm_size
;
2271 /* check fsSelection field with bold simulation */
2272 memset(&lf
, 0, sizeof(lf
));
2273 strcpy(lf
.lfFaceName
, "Wingdings");
2274 lf
.lfCharSet
= SYMBOL_CHARSET
;
2277 fsSelection
= get_font_fsselection(&lf
);
2278 ok((fsSelection
& (1 << 5)) == 0, "got 0x%x\n", fsSelection
);
2280 /* face with bold simulation */
2281 lf
.lfWeight
= FW_BOLD
;
2282 fsSelection
= get_font_fsselection(&lf
);
2283 ok((fsSelection
& (1 << 5)) != 0, "got 0x%x\n", fsSelection
);
2285 /* check fsSelection field with oblique simulation */
2286 memset(&lf
, 0, sizeof(lf
));
2287 strcpy(lf
.lfFaceName
, "Tahoma");
2289 lf
.lfWeight
= FW_NORMAL
;
2290 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2291 lf
.lfQuality
= PROOF_QUALITY
;
2294 fsSelection
= get_font_fsselection(&lf
);
2295 ok((fsSelection
& 1) == 0, "got 0x%x\n", fsSelection
);
2298 /* face with oblique simulation */
2299 fsSelection
= get_font_fsselection(&lf
);
2300 ok((fsSelection
& 1) == 1, "got 0x%x\n", fsSelection
);
2302 if (!is_font_installed("Arial"))
2304 skip("Arial is not installed\n");
2310 memset(&lf
, 0, sizeof(lf
));
2311 strcpy(lf
.lfFaceName
, "Arial");
2313 lf
.lfWeight
= FW_NORMAL
;
2314 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2315 lf
.lfQuality
= PROOF_QUALITY
;
2316 hfont
= CreateFontIndirectA(&lf
);
2317 ok(hfont
!= NULL
, "failed to create a font\n");
2319 hfont_old
= SelectObject(hdc
, hfont
);
2320 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2322 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2324 memset(otm
, 0xAA, otm_size
);
2325 SetLastError(0xdeadbeef);
2326 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2327 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2328 ok(ret
== 1 /* Win9x */ ||
2329 ret
== otm
->otmSize
/* XP*/,
2330 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2331 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2333 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2334 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2335 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2336 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2339 memset(otm
, 0xAA, otm_size
);
2340 SetLastError(0xdeadbeef);
2341 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2342 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2343 ok(ret
== 1 /* Win9x */ ||
2344 ret
== otm
->otmSize
/* XP*/,
2345 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2346 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2348 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2349 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2350 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2351 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2354 /* ask about truncated data */
2355 memset(otm
, 0xAA, otm_size
);
2356 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2357 SetLastError(0xdeadbeef);
2358 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2359 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2360 ok(ret
== 1 /* Win9x */ ||
2361 ret
== otm
->otmSize
/* XP*/,
2362 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2363 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2365 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2366 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2367 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2369 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2371 /* check handling of NULL pointer */
2372 SetLastError(0xdeadbeef);
2373 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, NULL
);
2374 ok(ret
== otm_size
, "expected %u, got %u, error %d\n", otm_size
, ret
, GetLastError());
2376 HeapFree(GetProcessHeap(), 0, otm
);
2378 SelectObject(hdc
, hfont_old
);
2379 DeleteObject(hfont
);
2384 static void testJustification(const char *context
, HDC hdc
, PCSTR str
, RECT
*clientArea
)
2388 areaWidth
= clientArea
->right
- clientArea
->left
,
2390 const char *pFirstChar
, *pLastChar
;
2397 int GetTextExtentExPointWWidth
;
2400 GetTextMetricsA(hdc
, &tm
);
2401 y
= clientArea
->top
;
2404 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2410 /* if not at the end of the string, ... */
2411 if (*str
== '\0') break;
2412 /* ... add the next word to the current extent */
2413 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2415 SetTextJustification(hdc
, 0, 0);
2416 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2417 } while ((int) size
.cx
< areaWidth
);
2419 /* ignore trailing break chars */
2421 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2427 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2429 SetTextJustification(hdc
, 0, 0);
2430 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2432 /* do not justify the last extent */
2433 if (*str
!= '\0' && breakCount
> 0)
2435 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2436 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2437 if (size
.cx
!= areaWidth
&& nErrors
< ARRAY_SIZE(error
) - 1)
2439 error
[nErrors
].start
= pFirstChar
;
2440 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2441 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2448 } while (*str
&& y
< clientArea
->bottom
);
2450 for (e
= 0; e
< nErrors
; e
++)
2452 /* The width returned by GetTextExtentPoint32() is exactly the same
2453 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2454 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2455 "%s: GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2456 context
, error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2460 static void test_SetTextJustification(void)
2470 static const char testText
[] =
2471 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2472 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2473 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2474 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2475 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2476 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2477 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2479 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2480 GetClientRect( hwnd
, &clientArea
);
2481 hdc
= GetDC( hwnd
);
2483 if (!is_font_installed("Times New Roman"))
2485 skip("Times New Roman is not installed\n");
2489 memset(&lf
, 0, sizeof lf
);
2490 lf
.lfCharSet
= ANSI_CHARSET
;
2491 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2492 lf
.lfWeight
= FW_DONTCARE
;
2494 lf
.lfQuality
= DEFAULT_QUALITY
;
2495 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2496 hfont
= create_font("Times New Roman", &lf
);
2497 SelectObject(hdc
, hfont
);
2499 testJustification("default", hdc
, testText
, &clientArea
);
2501 if (!pGetTextExtentExPointI
) goto done
;
2502 GetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2504 SetTextJustification(hdc
, 0, 0);
2505 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2506 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2507 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2508 SetTextJustification(hdc
, 4, 1);
2509 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2510 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2511 SetTextJustification(hdc
, 9, 2);
2512 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2513 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2514 SetTextJustification(hdc
, 7, 3);
2515 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2516 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2517 SetTextJustification(hdc
, 7, 3);
2518 SetTextCharacterExtra(hdc
, 2 );
2519 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2520 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2521 SetTextJustification(hdc
, 0, 0);
2522 SetTextCharacterExtra(hdc
, 0);
2523 size
.cx
= size
.cy
= 1234;
2524 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2525 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
2526 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2527 SetTextJustification(hdc
, 5, 1);
2528 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2529 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2530 SetTextJustification(hdc
, 0, 0);
2532 SetMapMode( hdc
, MM_ANISOTROPIC
);
2533 SetWindowExtEx( hdc
, 2, 2, NULL
);
2534 GetClientRect( hwnd
, &clientArea
);
2535 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2536 testJustification("2x2", hdc
, testText
, &clientArea
);
2538 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2539 for (i
= 0; i
< 10; i
++)
2541 SetTextCharacterExtra(hdc
, i
);
2542 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2543 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2545 SetTextCharacterExtra(hdc
, 0);
2546 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2547 for (i
= 0; i
< 10; i
++)
2549 SetTextCharacterExtra(hdc
, i
);
2550 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2551 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2553 SetTextCharacterExtra(hdc
, 0);
2555 SetViewportExtEx( hdc
, 3, 3, NULL
);
2556 GetClientRect( hwnd
, &clientArea
);
2557 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2558 testJustification("3x3", hdc
, testText
, &clientArea
);
2560 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2561 for (i
= 0; i
< 10; i
++)
2563 SetTextCharacterExtra(hdc
, i
);
2564 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2565 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2569 DeleteObject(hfont
);
2570 ReleaseDC(hwnd
, hdc
);
2571 DestroyWindow(hwnd
);
2574 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2578 HFONT hfont
, hfont_old
;
2585 assert(count
<= 128);
2587 memset(&lf
, 0, sizeof(lf
));
2589 lf
.lfCharSet
= charset
;
2591 lstrcpyA(lf
.lfFaceName
, "Arial");
2592 SetLastError(0xdeadbeef);
2593 hfont
= CreateFontIndirectA(&lf
);
2594 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2597 hfont_old
= SelectObject(hdc
, hfont
);
2599 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2600 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2602 SetLastError(0xdeadbeef);
2603 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2604 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
2606 if (charset
== SYMBOL_CHARSET
)
2608 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2609 ok(fs
.fsCsb
[0] & (1u << 31), "symbol encoding should be available\n");
2613 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2614 ok(!(fs
.fsCsb
[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2617 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2619 trace("Can't find codepage for charset %d\n", cs
);
2623 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2625 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2627 skip("Font code page %d, looking for code page %d\n",
2628 pGdiGetCodePage(hdc
), code_page
);
2636 WCHAR unicode_buf
[128];
2638 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2640 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2642 SetLastError(0xdeadbeef);
2643 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2644 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2645 count
, ret
, GetLastError());
2651 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2653 SetLastError(0xdeadbeef);
2654 ret
= GetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2655 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2656 count
, ret
, GetLastError());
2659 SelectObject(hdc
, hfont_old
);
2660 DeleteObject(hfont
);
2667 static void test_font_charset(void)
2669 static struct charset_data
2673 WORD font_idxA
[128], font_idxW
[128];
2676 { ANSI_CHARSET
, 1252 },
2677 { RUSSIAN_CHARSET
, 1251 },
2678 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2682 if (!pGetGlyphIndicesW
)
2684 win_skip("Skipping the font charset test on a Win9x platform\n");
2688 if (!is_font_installed("Arial"))
2690 skip("Arial is not installed\n");
2694 for (i
= 0; i
< ARRAY_SIZE(cd
); i
++)
2696 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2698 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2700 skip("Symbol or Wingdings is not installed\n");
2704 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2705 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2706 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2709 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2712 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2713 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2716 skip("Symbol or Wingdings is not installed\n");
2719 static void test_GdiGetCodePage(void)
2721 static const struct _matching_data
2723 UINT current_codepage
;
2726 UINT expected_codepage
;
2727 } matching_data
[] = {
2728 {1251, "Arial", ANSI_CHARSET
, 1252},
2729 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2731 {1252, "Arial", ANSI_CHARSET
, 1252},
2732 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2734 {1253, "Arial", ANSI_CHARSET
, 1252},
2735 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2737 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2738 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2739 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2741 { 936, "Arial", ANSI_CHARSET
, 936},
2742 { 936, "Tahoma", ANSI_CHARSET
, 936},
2743 { 936, "Simsun", ANSI_CHARSET
, 936},
2745 { 949, "Arial", ANSI_CHARSET
, 949},
2746 { 949, "Tahoma", ANSI_CHARSET
, 949},
2747 { 949, "Gulim", ANSI_CHARSET
, 949},
2749 { 950, "Arial", ANSI_CHARSET
, 950},
2750 { 950, "Tahoma", ANSI_CHARSET
, 950},
2751 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2760 if (!pGdiGetCodePage
)
2762 skip("GdiGetCodePage not available on this platform\n");
2768 for (i
= 0; i
< ARRAY_SIZE(matching_data
); i
++)
2770 /* only test data matched current locale codepage */
2771 if (matching_data
[i
].current_codepage
!= acp
)
2774 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2776 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2782 memset(&lf
, 0, sizeof(lf
));
2784 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2785 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2786 hfont
= CreateFontIndirectA(&lf
);
2787 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2789 hfont
= SelectObject(hdc
, hfont
);
2790 codepage
= pGdiGetCodePage(hdc
);
2791 ok(codepage
== matching_data
[i
].expected_codepage
,
2792 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2794 hfont
= SelectObject(hdc
, hfont
);
2795 DeleteObject(hfont
);
2797 /* CLIP_DFA_DISABLE turns off the font association */
2798 lf
.lfClipPrecision
= CLIP_DFA_DISABLE
;
2799 hfont
= CreateFontIndirectA(&lf
);
2800 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2802 hfont
= SelectObject(hdc
, hfont
);
2803 codepage
= pGdiGetCodePage(hdc
);
2804 ok(codepage
== 1252, "GdiGetCodePage returned %d\n", codepage
);
2806 hfont
= SelectObject(hdc
, hfont
);
2807 DeleteObject(hfont
);
2809 ReleaseDC(NULL
, hdc
);
2813 static void test_GetFontUnicodeRanges(void)
2817 HFONT hfont
, hfont_old
;
2821 if (!pGetFontUnicodeRanges
)
2823 win_skip("GetFontUnicodeRanges not available before W2K\n");
2827 memset(&lf
, 0, sizeof(lf
));
2828 lstrcpyA(lf
.lfFaceName
, "Arial");
2829 hfont
= create_font("Arial", &lf
);
2832 hfont_old
= SelectObject(hdc
, hfont
);
2834 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2835 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2837 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2838 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2840 gs
= heap_alloc_zero(size
);
2842 size
= pGetFontUnicodeRanges(hdc
, gs
);
2843 ok(size
, "GetFontUnicodeRanges failed\n");
2844 ok(gs
->cRanges
, "Unexpected ranges count.\n");
2848 SelectObject(hdc
, hfont_old
);
2849 DeleteObject(hfont
);
2850 ReleaseDC(NULL
, hdc
);
2853 struct enum_font_data
2859 struct enum_fullname_data
2865 struct enum_fullname_data_w
2871 struct enum_font_dataW
2877 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2879 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2880 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2882 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2884 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2886 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2888 if (efd
->total
>= efd
->size
)
2890 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2891 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2892 if (!efd
->lf
) return 0;
2894 efd
->lf
[efd
->total
++] = *lf
;
2899 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2901 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2902 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2904 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2906 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2908 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2910 if (efd
->total
>= efd
->size
)
2912 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2913 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2914 if (!efd
->lf
) return 0;
2916 efd
->lf
[efd
->total
++] = *lf
;
2921 static void get_charset_stats(struct enum_font_data
*efd
,
2922 int *ansi_charset
, int *symbol_charset
,
2923 int *russian_charset
)
2928 *symbol_charset
= 0;
2929 *russian_charset
= 0;
2931 for (i
= 0; i
< efd
->total
; i
++)
2933 switch (efd
->lf
[i
].lfCharSet
)
2938 case SYMBOL_CHARSET
:
2939 (*symbol_charset
)++;
2941 case RUSSIAN_CHARSET
:
2942 (*russian_charset
)++;
2948 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2949 int *ansi_charset
, int *symbol_charset
,
2950 int *russian_charset
)
2955 *symbol_charset
= 0;
2956 *russian_charset
= 0;
2958 for (i
= 0; i
< efd
->total
; i
++)
2960 switch (efd
->lf
[i
].lfCharSet
)
2965 case SYMBOL_CHARSET
:
2966 (*symbol_charset
)++;
2968 case RUSSIAN_CHARSET
:
2969 (*russian_charset
)++;
2975 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2977 struct enum_font_data efd
;
2978 struct enum_font_dataW efdw
;
2981 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2983 if (*font_name
&& !is_truetype_font_installed(font_name
))
2985 skip("%s is not installed\n", font_name
);
2988 memset( &efd
, 0, sizeof(efd
) );
2989 memset( &efdw
, 0, sizeof(efdw
) );
2993 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2994 * while EnumFontFamiliesEx doesn't.
2996 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2999 * Use EnumFontFamiliesW since win98 crashes when the
3000 * second parameter is NULL using EnumFontFamilies
3003 SetLastError(0xdeadbeef);
3004 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
3005 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
3008 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3009 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
3010 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
3011 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3012 ok(russian_charset
> 0 ||
3013 broken(russian_charset
== 0), /* NT4 */
3014 "NULL family should enumerate RUSSIAN_CHARSET\n");
3018 SetLastError(0xdeadbeef);
3019 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
3020 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
3023 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3024 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
3025 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
3026 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3027 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
3032 SetLastError(0xdeadbeef);
3033 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
3034 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
3035 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3037 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3039 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
3040 for (i
= 0; i
< efd
.total
; i
++)
3042 /* FIXME: remove completely once Wine is fixed */
3043 todo_wine_if(efd
.lf
[i
].lfCharSet
!= font_charset
)
3044 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3045 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3046 font_name
, efd
.lf
[i
].lfFaceName
);
3049 memset(&lf
, 0, sizeof(lf
));
3050 lf
.lfCharSet
= ANSI_CHARSET
;
3051 strcpy(lf
.lfFaceName
, font_name
);
3053 SetLastError(0xdeadbeef);
3054 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3055 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3056 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3057 if (font_charset
== SYMBOL_CHARSET
)
3060 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
3062 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3066 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
3067 for (i
= 0; i
< efd
.total
; i
++)
3069 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3071 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3072 font_name
, efd
.lf
[i
].lfFaceName
);
3076 /* DEFAULT_CHARSET should enumerate all available charsets */
3077 memset(&lf
, 0, sizeof(lf
));
3078 lf
.lfCharSet
= DEFAULT_CHARSET
;
3079 strcpy(lf
.lfFaceName
, font_name
);
3081 SetLastError(0xdeadbeef);
3082 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3083 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3084 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3085 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
3086 for (i
= 0; i
< efd
.total
; i
++)
3089 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3090 font_name
, efd
.lf
[i
].lfFaceName
);
3094 switch (font_charset
)
3097 ok(ansi_charset
> 0,
3098 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3100 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
3101 ok(russian_charset
> 0,
3102 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3104 case SYMBOL_CHARSET
:
3106 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
3108 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3109 ok(!russian_charset
,
3110 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3112 case DEFAULT_CHARSET
:
3113 ok(ansi_charset
> 0,
3114 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3115 ok(symbol_charset
> 0,
3116 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3117 ok(russian_charset
> 0,
3118 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3124 ok(ansi_charset
> 0,
3125 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3126 ok(symbol_charset
> 0,
3127 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3128 ok(russian_charset
> 0,
3129 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3132 memset(&lf
, 0, sizeof(lf
));
3133 lf
.lfCharSet
= SYMBOL_CHARSET
;
3134 strcpy(lf
.lfFaceName
, font_name
);
3136 SetLastError(0xdeadbeef);
3137 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3138 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3139 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3140 if (*font_name
&& font_charset
== ANSI_CHARSET
)
3141 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
3144 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
3145 for (i
= 0; i
< efd
.total
; i
++)
3147 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3149 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3150 font_name
, efd
.lf
[i
].lfFaceName
);
3154 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3155 ok(symbol_charset
> 0,
3156 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3157 ok(!russian_charset
,
3158 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3163 heap_free( efd
.lf
);
3164 heap_free( efdw
.lf
);
3167 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
3169 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
3170 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
3171 const DWORD valid_bits
= 0x003f01ff;
3175 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
3177 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
3178 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
3179 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
3188 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3190 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
3192 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3194 if (efd
->total
>= efd
->size
)
3196 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
3197 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
3198 if (!efd
->lf
) return 0;
3200 efd
->lf
[efd
->total
++] = *lf
;
3205 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3207 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
3209 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3211 if (efnd
->total
>= efnd
->size
)
3213 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3214 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3215 if (!efnd
->elf
) return 0;
3217 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
3222 static INT CALLBACK
enum_fullname_data_proc_w( const LOGFONTW
*lf
, const TEXTMETRICW
*ntm
, DWORD type
, LPARAM lParam
)
3224 struct enum_fullname_data_w
*efnd
= (struct enum_fullname_data_w
*)lParam
;
3226 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3228 if (efnd
->total
>= efnd
->size
)
3230 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3231 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3232 if (!efnd
->elf
) return 0;
3234 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTW
*)lf
;
3239 static void test_EnumFontFamiliesEx_default_charset(void)
3241 struct enum_font_data efd
;
3242 LOGFONTA target
, enum_font
;
3248 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3249 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3254 memset(&enum_font
, 0, sizeof(enum_font
));
3255 enum_font
.lfCharSet
= csi
.ciCharset
;
3256 target
.lfFaceName
[0] = '\0';
3257 target
.lfCharSet
= csi
.ciCharset
;
3258 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3259 if (target
.lfFaceName
[0] == '\0') {
3260 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3263 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3264 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3265 target
.lfCharSet
= ANSI_CHARSET
;
3268 memset(&efd
, 0, sizeof(efd
));
3269 memset(&enum_font
, 0, sizeof(enum_font
));
3270 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3271 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3272 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3276 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3278 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3279 "(%s) got charset %d expected %d\n",
3280 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3286 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3288 HFONT hfont
, hfont_prev
;
3290 GLYPHMETRICS gm1
, gm2
;
3294 /* negative widths are handled just as positive ones */
3295 lf2
.lfWidth
= -lf
->lfWidth
;
3297 SetLastError(0xdeadbeef);
3298 hfont
= CreateFontIndirectA(lf
);
3299 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3300 check_font("original", lf
, hfont
);
3302 hfont_prev
= SelectObject(hdc
, hfont
);
3304 ret
= GetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3305 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3307 SelectObject(hdc
, hfont_prev
);
3308 DeleteObject(hfont
);
3309 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3313 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3314 memset(&gm1
, 0xab, sizeof(gm1
));
3315 SetLastError(0xdeadbeef);
3316 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3317 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3319 SelectObject(hdc
, hfont_prev
);
3320 DeleteObject(hfont
);
3322 SetLastError(0xdeadbeef);
3323 hfont
= CreateFontIndirectA(&lf2
);
3324 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3325 check_font("negative width", &lf2
, hfont
);
3327 hfont_prev
= SelectObject(hdc
, hfont
);
3329 memset(&gm2
, 0xbb, sizeof(gm2
));
3330 SetLastError(0xdeadbeef);
3331 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3332 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3334 SelectObject(hdc
, hfont_prev
);
3335 DeleteObject(hfont
);
3337 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3338 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3339 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3340 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3341 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3342 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3343 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3344 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3345 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3346 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3347 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3350 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3351 #include "pshpack2.h"
3355 SHORT xAvgCharWidth
;
3356 USHORT usWeightClass
;
3357 USHORT usWidthClass
;
3359 SHORT ySubscriptXSize
;
3360 SHORT ySubscriptYSize
;
3361 SHORT ySubscriptXOffset
;
3362 SHORT ySubscriptYOffset
;
3363 SHORT ySuperscriptXSize
;
3364 SHORT ySuperscriptYSize
;
3365 SHORT ySuperscriptXOffset
;
3366 SHORT ySuperscriptYOffset
;
3367 SHORT yStrikeoutSize
;
3368 SHORT yStrikeoutPosition
;
3371 ULONG ulUnicodeRange1
;
3372 ULONG ulUnicodeRange2
;
3373 ULONG ulUnicodeRange3
;
3374 ULONG ulUnicodeRange4
;
3377 USHORT usFirstCharIndex
;
3378 USHORT usLastCharIndex
;
3379 /* According to the Apple spec, original version didn't have the below fields,
3380 * version numbers were taken from the OpenType spec.
3382 /* version 0 (TrueType 1.5) */
3383 USHORT sTypoAscender
;
3384 USHORT sTypoDescender
;
3385 USHORT sTypoLineGap
;
3387 USHORT usWinDescent
;
3388 /* version 1 (TrueType 1.66) */
3389 ULONG ulCodePageRange1
;
3390 ULONG ulCodePageRange2
;
3391 /* version 2 (OpenType 1.2) */
3394 USHORT usDefaultChar
;
3396 USHORT usMaxContext
;
3397 /* version 4 (OpenType 1.6) */
3398 USHORT usLowerOpticalPointSize
;
3399 USHORT usUpperOpticalPointSize
;
3401 #include "poppack.h"
3403 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3416 } cmap_encoding_record
;
3424 BYTE glyph_ids
[256];
3434 USHORT search_range
;
3435 USHORT entry_selector
;
3438 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3441 USHORT start_count[seg_countx2 / 2];
3442 USHORT id_delta[seg_countx2 / 2];
3443 USHORT id_range_offset[seg_countx2 / 2];
3453 USHORT id_range_offset
;
3454 } cmap_format_4_seg
;
3456 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V4
*os2
, WORD family
, const char *name
)
3458 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3459 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3460 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3461 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3462 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3465 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3468 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3472 for(i
= 0; i
< 256; i
++)
3474 if(cmap
->glyph_ids
[i
] == 0) continue;
3476 if(*first
== 256) *first
= i
;
3478 if(*first
== 256) return FALSE
;
3482 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3484 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3485 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3486 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3487 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3488 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3491 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3494 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3495 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3499 for(i
= 0; i
< seg_count
; i
++)
3501 cmap_format_4_seg seg
;
3503 get_seg4(cmap
, i
, &seg
);
3505 if(seg
.start_count
> 0xfffe) break;
3507 if(*first
== 0x10000) *first
= seg
.start_count
;
3509 *last
= min(seg
.end_count
, 0xfffe);
3512 if(*first
== 0x10000) return FALSE
;
3516 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3519 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3521 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3523 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3524 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3537 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3540 cmap_header
*header
;
3545 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3546 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3547 if(size
== GDI_ERROR
) return FALSE
;
3549 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3550 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3551 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3552 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3554 cmap
= get_cmap(header
, 3, 1);
3556 *cmap_type
= cmap_ms_unicode
;
3559 cmap
= get_cmap(header
, 3, 0);
3560 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3564 *cmap_type
= cmap_none
;
3568 format
= GET_BE_WORD(*(WORD
*)cmap
);
3572 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3575 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3578 skip("unhandled cmap format %d\n", format
);
3583 HeapFree(GetProcessHeap(), 0, header
);
3587 #define TT_PLATFORM_APPLE_UNICODE 0
3588 #define TT_PLATFORM_MACINTOSH 1
3589 #define TT_PLATFORM_MICROSOFT 3
3590 #define TT_APPLE_ID_DEFAULT 0
3591 #define TT_APPLE_ID_ISO_10646 2
3592 #define TT_APPLE_ID_UNICODE_2_0 3
3593 #define TT_MS_ID_SYMBOL_CS 0
3594 #define TT_MS_ID_UNICODE_CS 1
3595 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3596 #define TT_NAME_ID_FONT_FAMILY 1
3597 #define TT_NAME_ID_FONT_SUBFAMILY 2
3598 #define TT_NAME_ID_UNIQUE_ID 3
3599 #define TT_NAME_ID_FULL_NAME 4
3600 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3602 typedef struct sfnt_name
3612 static const LANGID mac_langid_table
[] =
3614 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
3615 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
3616 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
3617 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
3618 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
3619 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
3620 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
3621 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
3622 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
3623 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
3624 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
3625 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
3626 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
3627 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
3628 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
3629 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
3630 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
3631 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
3632 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
3633 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3634 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
3635 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
3636 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
3637 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
3638 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
3639 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
3640 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
3641 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
3642 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
3643 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
3644 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
3645 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
3646 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
3647 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3648 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
3649 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
3650 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
3651 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
3652 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
3653 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
3654 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
3655 0, /* TT_MAC_LANGID_YIDDISH */
3656 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
3657 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
3658 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
3659 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
3660 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
3661 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
3662 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
3663 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
3664 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3665 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
3666 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
3667 0, /* TT_MAC_LANGID_MOLDAVIAN */
3668 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
3669 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
3670 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
3671 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
3672 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3673 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
3674 0, /* TT_MAC_LANGID_KURDISH */
3675 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
3676 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
3677 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
3678 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
3679 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
3680 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
3681 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
3682 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
3683 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
3684 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
3685 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
3686 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
3687 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
3688 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
3689 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
3690 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
3691 0, /* TT_MAC_LANGID_BURMESE */
3692 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
3693 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
3694 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
3695 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
3696 0, /* TT_MAC_LANGID_TAGALOG */
3697 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3698 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3699 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
3700 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
3701 0, /* TT_MAC_LANGID_GALLA */
3702 0, /* TT_MAC_LANGID_SOMALI */
3703 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
3704 0, /* TT_MAC_LANGID_RUANDA */
3705 0, /* TT_MAC_LANGID_RUNDI */
3706 0, /* TT_MAC_LANGID_CHEWA */
3707 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
3708 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
3709 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3710 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3711 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
3712 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
3713 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
3714 0, /* TT_MAC_LANGID_LATIN */
3715 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
3716 0, /* TT_MAC_LANGID_GUARANI */
3717 0, /* TT_MAC_LANGID_AYMARA */
3718 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
3719 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
3720 0, /* TT_MAC_LANGID_DZONGKHA */
3721 0, /* TT_MAC_LANGID_JAVANESE */
3722 0, /* TT_MAC_LANGID_SUNDANESE */
3723 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
3724 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
3725 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
3726 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
3727 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3728 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
3729 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
3730 0, /* TT_MAC_LANGID_TONGAN */
3731 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3732 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
3733 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3736 static inline WORD
get_mac_code_page( const sfnt_name
*name
)
3738 if (GET_BE_WORD(name
->encoding_id
) == TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
3739 return 10000 + GET_BE_WORD(name
->encoding_id
);
3742 static int match_name_table_language( const sfnt_name
*name
, LANGID lang
)
3747 switch (GET_BE_WORD(name
->platform_id
))
3749 case TT_PLATFORM_MICROSOFT
:
3750 res
+= 5; /* prefer the Microsoft name */
3751 switch (GET_BE_WORD(name
->encoding_id
))
3753 case TT_MS_ID_UNICODE_CS
:
3754 case TT_MS_ID_SYMBOL_CS
:
3755 name_lang
= GET_BE_WORD(name
->language_id
);
3761 case TT_PLATFORM_MACINTOSH
:
3762 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
3763 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3764 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3766 case TT_PLATFORM_APPLE_UNICODE
:
3767 res
+= 2; /* prefer Unicode encodings */
3768 switch (GET_BE_WORD(name
->encoding_id
))
3770 case TT_APPLE_ID_DEFAULT
:
3771 case TT_APPLE_ID_ISO_10646
:
3772 case TT_APPLE_ID_UNICODE_2_0
:
3773 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3774 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3783 if (name_lang
== lang
) res
+= 30;
3784 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
3785 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
3789 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3791 struct sfnt_name_header
3794 USHORT number_of_record
;
3795 USHORT storage_offset
;
3799 LONG size
, offset
, length
;
3804 int res
, best_lang
= 0, best_index
= -1;
3806 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3807 ok(size
!= GDI_ERROR
, "no name table found\n");
3808 if(size
== GDI_ERROR
) return FALSE
;
3810 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3811 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3812 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3814 header
= (void *)data
;
3815 header
->format
= GET_BE_WORD(header
->format
);
3816 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3817 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3818 if (header
->format
!= 0)
3820 skip("got format %u\n", header
->format
);
3823 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3825 skip("number records out of range: %d\n", header
->number_of_record
);
3828 if (header
->storage_offset
>= size
)
3830 skip("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3834 entry
= (void *)&header
[1];
3835 for (i
= 0; i
< header
->number_of_record
; i
++)
3837 if (GET_BE_WORD(entry
[i
].name_id
) != name_id
) continue;
3838 res
= match_name_table_language( &entry
[i
], language_id
);
3839 if (res
> best_lang
)
3846 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[best_index
].offset
);
3847 length
= GET_BE_WORD(entry
[best_index
].length
);
3848 if (offset
+ length
> size
)
3850 skip("entry %d is out of range\n", best_index
);
3853 if (length
>= out_size
)
3855 skip("buffer too small for entry %d\n", best_index
);
3859 name
= (WCHAR
*)(data
+ offset
);
3860 for (c
= 0; c
< length
/ 2; c
++)
3861 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3867 HeapFree(GetProcessHeap(), 0, data
);
3871 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3874 HFONT hfont
, hfont_old
;
3878 const char *font_name
= lf
->lfFaceName
;
3879 DWORD cmap_first
= 0, cmap_last
= 0;
3880 UINT ascent
, descent
, cell_height
;
3881 cmap_type cmap_type
;
3882 BOOL sys_lang_non_english
;
3884 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3887 SetLastError(0xdeadbeef);
3888 hfont
= CreateFontIndirectA(lf
);
3889 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3891 hfont_old
= SelectObject(hdc
, hfont
);
3893 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3894 if (size
== GDI_ERROR
)
3896 trace("OS/2 chunk was not found\n");
3899 if (size
> sizeof(tt_os2
))
3901 trace("got too large OS/2 chunk of size %u\n", size
);
3902 size
= sizeof(tt_os2
);
3905 memset(&tt_os2
, 0, sizeof(tt_os2
));
3906 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3907 ok(ret
>= TT_OS2_V0_SIZE
&& ret
<= size
, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE
,
3910 SetLastError(0xdeadbeef);
3911 ret
= GetTextMetricsA(hdc
, &tmA
);
3912 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3914 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3916 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3920 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3921 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3922 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3926 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3927 descent
= abs((SHORT
)GET_BE_WORD(tt_os2
.usWinDescent
));
3928 cell_height
= ascent
+ descent
;
3929 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3930 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3932 /* NEWTEXTMETRIC's scaling method is different from TEXTMETRIC's */
3933 #define SCALE_NTM(value) (MulDiv(ntm->tmHeight, (value), cell_height))
3934 size
= MulDiv(32, ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
3935 ok(ntm
->tmHeight
== size
, "%s: ntm->tmHeight %d != %d (%u/%u)\n",
3936 font_name
, ntm
->tmHeight
, size
, ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
3937 size
= SCALE_NTM(ntm
->ntmAvgWidth
);
3938 ok(ntm
->tmAveCharWidth
== size
, "%s: ntm->tmAveCharWidth %d != %d (%u/%u,%d)\n",
3939 font_name
, ntm
->tmAveCharWidth
, size
, ntm
->ntmAvgWidth
, cell_height
, ntm
->tmHeight
);
3940 size
= SCALE_NTM(ascent
);
3941 ok(ntm
->tmAscent
== size
, "%s: ntm->tmAscent %d != %d (%u/%u,%d)\n",
3942 font_name
, ntm
->tmAscent
, size
, ascent
, cell_height
, ntm
->tmHeight
);
3943 size
= ntm
->tmHeight
- ntm
->tmAscent
;
3944 ok(ntm
->tmDescent
== size
, "%s: ntm->tmDescent %d != %d (%u/%u,%d)\n",
3945 font_name
, ntm
->tmDescent
, size
, descent
, cell_height
, ntm
->tmHeight
);
3946 size
= SCALE_NTM(cell_height
- ntm
->ntmSizeEM
);
3947 ok(ntm
->tmInternalLeading
== size
, "%s: ntm->tmInternalLeading %d != %d (%u/%u,%d)\n",
3948 font_name
, ntm
->tmInternalLeading
, size
, cell_height
- ntm
->ntmSizeEM
, cell_height
, ntm
->tmHeight
);
3951 version
= GET_BE_WORD(tt_os2
.version
);
3953 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3954 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3955 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3956 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3958 if (winetest_debug
> 1)
3959 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3960 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3961 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3963 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3968 case 1255: /* Hebrew */
3969 expect_last_W
= 0xf896;
3971 case 1257: /* Baltic */
3972 expect_last_W
= 0xf8fd;
3975 expect_last_W
= 0xf0ff;
3977 expect_break_W
= 0x20;
3978 expect_default_W
= expect_break_W
- 1;
3979 expect_first_A
= 0x1e;
3980 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3984 expect_first_W
= cmap_first
;
3985 expect_last_W
= cmap_last
;
3986 if(os2_first_char
<= 1)
3987 expect_break_W
= os2_first_char
+ 2;
3988 else if(os2_first_char
> 0xff)
3989 expect_break_W
= 0x20;
3991 expect_break_W
= os2_first_char
;
3992 expect_default_W
= expect_break_W
- 1;
3993 expect_first_A
= expect_default_W
- 1;
3994 expect_last_A
= min(expect_last_W
, 0xff);
3996 expect_break_A
= expect_break_W
;
3997 expect_default_A
= expect_default_W
;
3999 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
4000 todo_wine_if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
4001 ok(tmA
.tmFirstChar
== expect_first_A
||
4002 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
4003 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
4004 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
4005 ok(tmA
.tmLastChar
== expect_last_A
||
4006 tmA
.tmLastChar
== 0xff /* win9x */,
4007 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
4009 skip("tmLastChar is DBCS lead byte\n");
4010 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
4011 font_name
, tmA
.tmBreakChar
, expect_break_A
);
4012 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
4013 "A: tmDefaultChar for %s got %02x expected %02x\n",
4014 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
4017 SetLastError(0xdeadbeef);
4018 ret
= GetTextMetricsW(hdc
, &tmW
);
4019 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
4020 "GetTextMetricsW error %u\n", GetLastError());
4023 /* Wine uses the os2 first char */
4024 todo_wine_if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
4025 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
4026 font_name
, tmW
.tmFirstChar
, expect_first_W
);
4028 /* Wine uses the os2 last char */
4029 todo_wine_if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
4030 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
4031 font_name
, tmW
.tmLastChar
, expect_last_W
);
4032 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
4033 font_name
, tmW
.tmBreakChar
, expect_break_W
);
4034 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
4035 "W: tmDefaultChar for %s got %02x expected %02x\n",
4036 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
4038 /* Test the aspect ratio while we have tmW */
4039 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
4040 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
4041 tmW
.tmDigitizedAspectX
, ret
);
4042 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
4043 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
4044 tmW
.tmDigitizedAspectX
, ret
);
4048 /* test FF_ values */
4049 switch(tt_os2
.panose
.bFamilyType
)
4053 case PAN_FAMILY_TEXT_DISPLAY
:
4054 case PAN_FAMILY_PICTORIAL
:
4056 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
4057 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
4059 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
4062 switch(tt_os2
.panose
.bSerifStyle
)
4067 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
4070 case PAN_SERIF_COVE
:
4071 case PAN_SERIF_OBTUSE_COVE
:
4072 case PAN_SERIF_SQUARE_COVE
:
4073 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
4074 case PAN_SERIF_SQUARE
:
4075 case PAN_SERIF_THIN
:
4076 case PAN_SERIF_BONE
:
4077 case PAN_SERIF_EXAGGERATED
:
4078 case PAN_SERIF_TRIANGLE
:
4079 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
4082 case PAN_SERIF_NORMAL_SANS
:
4083 case PAN_SERIF_OBTUSE_SANS
:
4084 case PAN_SERIF_PERP_SANS
:
4085 case PAN_SERIF_FLARED
:
4086 case PAN_SERIF_ROUNDED
:
4087 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
4092 case PAN_FAMILY_SCRIPT
:
4093 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
4096 case PAN_FAMILY_DECORATIVE
:
4097 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
4101 test_negative_width(hdc
, lf
);
4104 SelectObject(hdc
, hfont_old
);
4105 DeleteObject(hfont
);
4110 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4112 INT
*enumed
= (INT
*)lParam
;
4114 if (type
== TRUETYPE_FONTTYPE
)
4117 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
4122 static void test_GetTextMetrics(void)
4130 memset(&lf
, 0, sizeof(lf
));
4131 lf
.lfCharSet
= DEFAULT_CHARSET
;
4133 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
4138 static void test_nonexistent_font(void)
4146 { "Times New Roman Baltic", 186 },
4147 { "Times New Roman CE", 238 },
4148 { "Times New Roman CYR", 204 },
4149 { "Times New Roman Greek", 161 },
4150 { "Times New Roman TUR", 162 }
4158 { "MS Shell Dlg", 186 },
4159 { "MS Shell Dlg", 238 },
4160 { "MS Shell Dlg", 204 },
4161 { "MS Shell Dlg", 161 },
4162 { "MS Shell Dlg", 162 }
4168 INT cs
, expected_cs
, i
, ret
;
4169 char buf
[LF_FACESIZE
];
4171 expected_cs
= GetACP();
4172 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
4174 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
4177 expected_cs
= csi
.ciCharset
;
4178 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
4180 hdc
= CreateCompatibleDC(0);
4182 for (i
= 0; i
< ARRAY_SIZE(shell_subst
); i
++)
4184 ret
= is_font_installed(shell_subst
[i
].name
);
4185 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4186 ret
= is_truetype_font_installed(shell_subst
[i
].name
);
4187 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4189 memset(&lf
, 0, sizeof(lf
));
4191 lf
.lfWeight
= FW_REGULAR
;
4192 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4193 hfont
= CreateFontIndirectA(&lf
);
4194 hfont
= SelectObject(hdc
, hfont
);
4195 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4196 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4197 cs
= GetTextCharset(hdc
);
4198 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, shell_subst
[i
].name
);
4200 DeleteObject(SelectObject(hdc
, hfont
));
4202 memset(&lf
, 0, sizeof(lf
));
4204 lf
.lfWeight
= FW_DONTCARE
;
4205 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4206 hfont
= CreateFontIndirectA(&lf
);
4207 hfont
= SelectObject(hdc
, hfont
);
4208 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4209 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4210 cs
= GetTextCharset(hdc
);
4211 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, shell_subst
[i
].name
);
4212 DeleteObject(SelectObject(hdc
, hfont
));
4215 if (!is_truetype_font_installed("Arial") ||
4216 !is_truetype_font_installed("Times New Roman"))
4219 skip("Arial or Times New Roman not installed\n");
4223 memset(&lf
, 0, sizeof(lf
));
4225 lf
.lfWeight
= FW_REGULAR
;
4226 lf
.lfCharSet
= ANSI_CHARSET
;
4227 lf
.lfPitchAndFamily
= FF_SWISS
;
4228 strcpy(lf
.lfFaceName
, "Nonexistent font");
4229 hfont
= CreateFontIndirectA(&lf
);
4230 hfont
= SelectObject(hdc
, hfont
);
4231 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4232 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
4233 cs
= GetTextCharset(hdc
);
4234 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4235 DeleteObject(SelectObject(hdc
, hfont
));
4237 memset(&lf
, 0, sizeof(lf
));
4239 lf
.lfWeight
= FW_DONTCARE
;
4240 strcpy(lf
.lfFaceName
, "Nonexistent font");
4241 hfont
= CreateFontIndirectA(&lf
);
4242 hfont
= SelectObject(hdc
, hfont
);
4243 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4244 todo_wine
/* Wine uses Arial for all substitutions */
4245 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
4246 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
4247 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4249 cs
= GetTextCharset(hdc
);
4250 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
4251 DeleteObject(SelectObject(hdc
, hfont
));
4253 memset(&lf
, 0, sizeof(lf
));
4255 lf
.lfWeight
= FW_REGULAR
;
4256 strcpy(lf
.lfFaceName
, "Nonexistent font");
4257 hfont
= CreateFontIndirectA(&lf
);
4258 hfont
= SelectObject(hdc
, hfont
);
4259 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4260 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4261 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
4262 cs
= GetTextCharset(hdc
);
4263 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4264 DeleteObject(SelectObject(hdc
, hfont
));
4266 memset(&lf
, 0, sizeof(lf
));
4268 lf
.lfWeight
= FW_DONTCARE
;
4269 strcpy(lf
.lfFaceName
, "Times New Roman");
4270 hfont
= CreateFontIndirectA(&lf
);
4271 hfont
= SelectObject(hdc
, hfont
);
4272 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4273 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
4274 cs
= GetTextCharset(hdc
);
4275 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4276 DeleteObject(SelectObject(hdc
, hfont
));
4278 for (i
= 0; i
< ARRAY_SIZE(font_subst
); i
++)
4280 ret
= is_font_installed(font_subst
[i
].name
);
4282 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4283 "%s should be enumerated\n", font_subst
[i
].name
);
4284 ret
= is_truetype_font_installed(font_subst
[i
].name
);
4286 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4287 "%s should be enumerated\n", font_subst
[i
].name
);
4289 memset(&lf
, 0, sizeof(lf
));
4291 lf
.lfWeight
= FW_REGULAR
;
4292 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4293 hfont
= CreateFontIndirectA(&lf
);
4294 hfont
= SelectObject(hdc
, hfont
);
4295 cs
= GetTextCharset(hdc
);
4296 if (font_subst
[i
].charset
== expected_cs
)
4298 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4299 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4300 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
4304 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
4305 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4306 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4307 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
4309 DeleteObject(SelectObject(hdc
, hfont
));
4311 memset(&lf
, 0, sizeof(lf
));
4313 lf
.lfWeight
= FW_DONTCARE
;
4314 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4315 hfont
= CreateFontIndirectA(&lf
);
4316 hfont
= SelectObject(hdc
, hfont
);
4317 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4318 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
4319 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
4320 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
4321 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4322 "got %s for font %s\n", buf
, font_subst
[i
].name
);
4323 cs
= GetTextCharset(hdc
);
4324 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4325 DeleteObject(SelectObject(hdc
, hfont
));
4331 struct font_realization_info
4346 WCHAR path
[MAX_PATH
];
4349 static void test_RealizationInfo(void)
4351 struct realization_info_t
4358 struct file_info file_info
;
4360 DWORD info
[4], info2
[32], read
;
4361 HFONT hfont
, hfont_old
;
4365 BYTE file
[16], data
[14];
4370 if(!pGdiRealizationInfo
)
4372 win_skip("GdiRealizationInfo not available\n");
4378 memset(info
, 0xcc, sizeof(info
));
4379 r
= pGdiRealizationInfo(hdc
, info
);
4380 ok(r
!= 0, "ret 0\n");
4381 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
4382 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4384 if (!is_truetype_font_installed("Tahoma"))
4386 skip("skipping GdiRealizationInfo with truetype font\n");
4390 memset(&lf
, 0, sizeof(lf
));
4391 strcpy(lf
.lfFaceName
, "Tahoma");
4393 lf
.lfWeight
= FW_BOLD
;
4395 hfont
= CreateFontIndirectA(&lf
);
4396 hfont_old
= SelectObject(hdc
, hfont
);
4398 memset(info
, 0xcc, sizeof(info
));
4399 r
= pGdiRealizationInfo(hdc
, info
);
4400 ok(r
!= 0, "ret 0\n");
4401 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
4402 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4404 if (pGetFontRealizationInfo
)
4406 struct font_realization_info
*fri
= (struct font_realization_info
*)info2
;
4407 struct realization_info_t
*ri
= (struct realization_info_t
*)info
;
4409 /* The first DWORD represents a struct size. On a
4410 newly rebooted system setting this to < 16 results
4411 in GetFontRealizationInfo failing. However there
4412 appears to be some caching going on which results
4413 in calls after a successful call also succeeding even
4414 if the size < 16. This means we can't reliably test
4417 memset(info2
, 0xcc, sizeof(info2
));
4419 r
= pGetFontRealizationInfo(hdc
, info2
);
4420 ok(r
!= 0, "ret 0\n");
4421 /* We may get the '24' version here if that has been previously
4423 ok(fri
->size
== 16 || fri
->size
== 24, "got %d\n", info2
[0]);
4424 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4425 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4426 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4427 ok(info2
[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2
[6]);
4429 memset(info2
, 0xcc, sizeof(info2
));
4431 r
= pGetFontRealizationInfo(hdc
, info2
);
4432 ok(r
== FALSE
, "got %d\n", r
);
4434 memset(info2
, 0xcc, sizeof(info2
));
4436 r
= pGetFontRealizationInfo(hdc
, info2
);
4437 ok(r
!= 0, "ret 0\n");
4438 ok(fri
->size
== 24, "got %d\n", fri
->size
);
4439 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4440 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4441 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4442 ok(fri
->simulations
== 0x2, "got simulations flags 0x%04x\n", fri
->simulations
);
4443 ok(fri
->face_index
== 0, "got wrong face index %u\n", fri
->face_index
);
4444 ok(info2
[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4446 /* Test GetFontFileInfo() */
4447 /* invalid font id */
4448 SetLastError(0xdeadbeef);
4449 r
= pGetFontFileInfo(0xabababab, 0, &file_info
, sizeof(file_info
), &needed
);
4450 ok(r
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "ret %d gle %d\n", r
, GetLastError());
4453 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, sizeof(file_info
), &needed
);
4454 ok(r
!= 0, "Failed to get font file info, error %d.\n", GetLastError());
4458 ok(needed
> 0 && needed
< sizeof(file_info
), "Unexpected required size.\n");
4460 h
= CreateFileW(file_info
.path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
4461 ok(h
!= INVALID_HANDLE_VALUE
, "Unable to open file %d\n", GetLastError());
4463 GetFileTime(h
, NULL
, NULL
, &time
);
4464 ok(!CompareFileTime(&file_info
.time
, &time
), "time mismatch\n");
4465 GetFileSizeEx(h
, &size
);
4466 ok(file_info
.size
.QuadPart
== size
.QuadPart
, "size mismatch\n");
4468 /* Read first 16 bytes from the file */
4469 ReadFile(h
, file
, sizeof(file
), &read
, NULL
);
4472 /* shorter buffer */
4473 SetLastError(0xdeadbeef);
4474 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, needed
- 1, &needed
);
4475 ok(r
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "ret %d gle %d\n", r
, GetLastError());
4478 /* Get bytes 2 - 16 using GetFontFileData */
4479 r
= pGetFontFileData(fri
->instance_id
, 0, 2, data
, sizeof(data
));
4480 ok(r
!= 0, "ret 0 gle %d\n", GetLastError());
4482 ok(!memcmp(data
, file
+ 2, sizeof(data
)), "mismatch\n");
4485 DeleteObject(SelectObject(hdc
, hfont_old
));
4491 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4492 the nul in the count of characters copied when the face name buffer is not
4493 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4494 always includes it. */
4495 static void test_GetTextFace(void)
4497 static const char faceA
[] = "Tahoma";
4498 static const WCHAR faceW
[] = L
"Tahoma";
4501 char bufA
[LF_FACESIZE
];
4502 WCHAR bufW
[LF_FACESIZE
];
4507 if(!is_font_installed("Tahoma"))
4509 skip("Tahoma is not installed so skipping this test\n");
4514 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
4515 f
= CreateFontIndirectA(&fA
);
4516 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
4519 g
= SelectObject(dc
, f
);
4520 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
4521 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
4522 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
4524 /* Play with the count arg. */
4526 n
= GetTextFaceA(dc
, 0, bufA
);
4527 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4528 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4531 n
= GetTextFaceA(dc
, 1, bufA
);
4532 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4533 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4535 bufA
[0] = 'x'; bufA
[1] = 'y';
4536 n
= GetTextFaceA(dc
, 2, bufA
);
4537 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
4538 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
4540 n
= GetTextFaceA(dc
, 0, NULL
);
4541 ok(n
== sizeof faceA
||
4542 broken(n
== 0), /* win98, winMe */
4543 "GetTextFaceA returned %d\n", n
);
4545 DeleteObject(SelectObject(dc
, g
));
4546 ReleaseDC(NULL
, dc
);
4549 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
4550 SetLastError(0xdeadbeef);
4551 f
= CreateFontIndirectW(&fW
);
4552 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4554 win_skip("CreateFontIndirectW is not implemented\n");
4557 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
4560 g
= SelectObject(dc
, f
);
4561 n
= GetTextFaceW(dc
, ARRAY_SIZE(bufW
), bufW
);
4562 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4563 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
4565 /* Play with the count arg. */
4567 n
= GetTextFaceW(dc
, 0, bufW
);
4568 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
4569 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4572 n
= GetTextFaceW(dc
, 1, bufW
);
4573 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
4574 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4576 bufW
[0] = 'x'; bufW
[1] = 'y';
4577 n
= GetTextFaceW(dc
, 2, bufW
);
4578 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4579 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4581 n
= GetTextFaceW(dc
, 0, NULL
);
4582 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4584 DeleteObject(SelectObject(dc
, g
));
4585 ReleaseDC(NULL
, dc
);
4588 static void test_orientation(void)
4590 static const char test_str
[11] = "Test String";
4593 HFONT hfont
, old_hfont
;
4596 if (!is_truetype_font_installed("Arial"))
4598 skip("Arial is not installed\n");
4602 hdc
= CreateCompatibleDC(0);
4603 memset(&lf
, 0, sizeof(lf
));
4604 lstrcpyA(lf
.lfFaceName
, "Arial");
4606 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4607 hfont
= create_font("orientation", &lf
);
4608 old_hfont
= SelectObject(hdc
, hfont
);
4609 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4610 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4611 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4612 SelectObject(hdc
, old_hfont
);
4613 DeleteObject(hfont
);
4617 static void test_oemcharset(void)
4621 HFONT hfont
, old_hfont
;
4624 hdc
= CreateCompatibleDC(0);
4625 ZeroMemory(&lf
, sizeof(lf
));
4627 lf
.lfCharSet
= OEM_CHARSET
;
4628 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4629 lstrcpyA(lf
.lfFaceName
, "Terminal");
4630 hfont
= CreateFontIndirectA(&lf
);
4631 old_hfont
= SelectObject(hdc
, hfont
);
4632 charset
= GetTextCharset(hdc
);
4634 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4635 hfont
= SelectObject(hdc
, old_hfont
);
4636 GetObjectA(hfont
, sizeof(clf
), &clf
);
4637 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4638 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4639 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4640 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4641 DeleteObject(hfont
);
4645 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4646 const TEXTMETRICA
*lpntme
,
4647 DWORD FontType
, LPARAM lParam
)
4649 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4651 LOGFONTA lf
= *lpelfe
;
4655 /* skip bitmap, proportional or vertical font */
4656 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4657 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4658 lf
.lfFaceName
[0] == '@')
4661 /* skip linked font */
4662 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4663 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4666 /* skip linked font, like SimSun-ExtB */
4667 switch (lpelfe
->lfCharSet
) {
4668 case SHIFTJIS_CHARSET
:
4669 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4671 case GB2312_CHARSET
:
4672 case CHINESEBIG5_CHARSET
:
4673 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4675 case HANGEUL_CHARSET
:
4676 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4679 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4685 /* test with an odd height */
4688 hfont
= CreateFontIndirectA(&lf
);
4691 *(HFONT
*)lParam
= hfont
;
4697 static void test_GetGlyphOutline(void)
4700 GLYPHMETRICS gm
, gm2
;
4702 HFONT hfont
, old_hfont
;
4704 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4705 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4713 {ANSI_CHARSET
, 0x30, 0x30},
4714 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4715 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4716 {GB2312_CHARSET
, 0x8141, 0x4e04},
4717 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4721 if (!is_truetype_font_installed("Tahoma"))
4723 skip("Tahoma is not installed\n");
4727 hdc
= CreateCompatibleDC(0);
4728 memset(&lf
, 0, sizeof(lf
));
4730 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4731 SetLastError(0xdeadbeef);
4732 hfont
= CreateFontIndirectA(&lf
);
4733 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4734 old_hfont
= SelectObject(hdc
, hfont
);
4736 memset(&gm
, 0, sizeof(gm
));
4737 SetLastError(0xdeadbeef);
4738 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4739 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4741 memset(&gm
, 0, sizeof(gm
));
4742 SetLastError(0xdeadbeef);
4743 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4744 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4745 ok(GetLastError() == 0xdeadbeef ||
4746 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4747 "expected 0xdeadbeef, got %u\n", GetLastError());
4749 memset(&gm
, 0, sizeof(gm
));
4750 SetLastError(0xdeadbeef);
4751 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4752 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4753 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4755 memset(&gm
, 0, sizeof(gm
));
4756 SetLastError(0xdeadbeef);
4757 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4758 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4760 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4761 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4764 /* test for needed buffer size request on space char */
4765 memset(&gm
, 0, sizeof(gm
));
4766 SetLastError(0xdeadbeef);
4767 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4768 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4770 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4771 ok(gm
.gmBlackBoxX
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxX
);
4772 ok(gm
.gmBlackBoxY
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxY
);
4775 /* requesting buffer size for space char + error */
4776 memset(&gm
, 0, sizeof(gm
));
4777 SetLastError(0xdeadbeef);
4778 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4779 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4781 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4782 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4783 ok(gm
.gmBlackBoxX
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxX
);
4784 ok(gm
.gmBlackBoxY
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxY
);
4787 /* test GetGlyphOutline with a buffer too small */
4788 SetLastError(0xdeadbeef);
4789 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_NATIVE
, &gm
, sizeof(i
), &i
, &mat
);
4790 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4791 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4793 for (i
= 0; i
< ARRAY_SIZE(fmt
); ++i
)
4797 memset(&gm
, 0xab, sizeof(gm
));
4798 SetLastError(0xdeadbeef);
4799 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4800 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4802 if (fmt
[i
] == GGO_METRICS
)
4803 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4805 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4806 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4807 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4810 memset(&gm
, 0xab, sizeof(gm
));
4811 SetLastError(0xdeadbeef);
4812 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4813 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4815 if (fmt
[i
] == GGO_METRICS
)
4816 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4818 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4819 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4820 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4823 memset(&gm
, 0xab, sizeof(gm
));
4824 SetLastError(0xdeadbeef);
4825 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4826 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4828 if (fmt
[i
] == GGO_METRICS
)
4829 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4831 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4832 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4833 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4836 memset(&gm
, 0xab, sizeof(gm
));
4837 SetLastError(0xdeadbeef);
4838 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4839 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4841 if (fmt
[i
] == GGO_METRICS
) {
4842 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4843 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4844 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4848 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4849 memset(&gm2
, 0xab, sizeof(gm2
));
4850 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4851 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4856 SelectObject(hdc
, old_hfont
);
4857 DeleteObject(hfont
);
4859 for (i
= 0; i
< ARRAY_SIZE(c
); ++i
)
4861 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4864 lf
.lfFaceName
[0] = '\0';
4865 lf
.lfCharSet
= c
[i
].cs
;
4866 lf
.lfPitchAndFamily
= 0;
4867 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4869 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4873 old_hfont
= SelectObject(hdc
, hfont
);
4875 /* expected to ignore superfluous bytes (single-byte character) */
4876 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4877 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4878 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4880 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4881 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4882 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4884 /* expected to ignore superfluous bytes (double-byte character) */
4885 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4886 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4887 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4888 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4890 /* expected to match wide-char version results */
4891 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4892 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4894 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4896 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4899 DeleteObject(SelectObject(hdc
, hfont
));
4902 DeleteObject(SelectObject(hdc
, old_hfont
));
4906 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4907 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4909 ret
= GetTextMetricsA(hdc
, &tm
);
4910 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4911 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4912 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4913 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4914 "expected %d, got %d (%s:%d)\n",
4915 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4917 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4918 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4919 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4920 "expected %d, got %d (%s:%d)\n",
4921 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4924 hfont
= CreateFontIndirectA(&lf
);
4925 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4926 DeleteObject(SelectObject(hdc
, hfont
));
4927 ret
= GetTextMetricsA(hdc
, &tm
);
4928 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4929 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4930 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4931 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4932 "expected %d, got %d (%s:%d)\n",
4933 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4935 lf
.lfItalic
= FALSE
;
4936 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4937 hfont
= CreateFontIndirectA(&lf
);
4938 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4939 DeleteObject(SelectObject(hdc
, hfont
));
4940 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4941 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4942 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4943 "expected %d, got %d (%s:%d)\n",
4944 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4946 hfont
= SelectObject(hdc
, old_hfont
);
4947 DeleteObject(hfont
);
4953 /* bug #9995: there is a limit to the character width that can be specified */
4954 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4960 int ave_width
, height
, width
, ratio
;
4962 if (!is_truetype_font_installed( fontname
)) {
4963 skip("%s is not installed\n", fontname
);
4966 hdc
= CreateCompatibleDC(0);
4967 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4968 /* select width = 0 */
4969 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4970 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4971 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4973 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4974 of
= SelectObject( hdc
, hf
);
4975 ret
= GetTextMetricsA( hdc
, &tm
);
4976 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4977 height
= tm
.tmHeight
;
4978 ave_width
= tm
.tmAveCharWidth
;
4979 SelectObject( hdc
, of
);
4982 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4984 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4985 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4986 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4987 ok(hf
!= 0, "CreateFont failed\n");
4988 of
= SelectObject(hdc
, hf
);
4989 ret
= GetTextMetricsA(hdc
, &tm
);
4990 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4991 SelectObject(hdc
, of
);
4994 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
5000 ratio
= width
/ height
;
5002 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
5005 static void test_GetCharacterPlacement(void)
5007 GCP_RESULTSA result
;
5013 hdc
= CreateCompatibleDC(0);
5014 ok(!!hdc
, "CreateCompatibleDC failed\n");
5016 memset(&result
, 0, sizeof(result
));
5017 result
.lStructSize
= sizeof(result
);
5018 result
.lpCaretPos
= pos
;
5019 result
.lpGlyphs
= glyphs
;
5020 result
.nGlyphs
= 20;
5024 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, &result
, 0);
5025 ok(size
, "GetCharacterPlacementA failed!\n");
5026 ok(result
.nGlyphs
== 9, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5027 ok(glyphs
[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5028 ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
5032 result
.nGlyphs
= 20;
5033 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 0, 0, &result
, 0);
5034 ok(!size2
, "Expected GetCharacterPlacementA to fail\n");
5035 ok(result
.nGlyphs
== 20, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5036 ok(glyphs
[0] == '!', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5037 ok(pos
[0] == -1, "Unexpected caret position %d\n", pos
[0]);
5039 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, NULL
, 0);
5040 ok(size2
, "GetCharacterPlacementA failed!\n");
5041 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
5043 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, NULL
, GCP_REORDER
);
5044 ok(size2
, "GetCharacterPlacementA failed!\n");
5045 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
5049 result
.nGlyphs
= 20;
5050 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, &result
, GCP_REORDER
);
5051 ok(size
, "GetCharacterPlacementA failed!\n");
5052 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
5053 ok(result
.nGlyphs
== 9, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5054 ok(glyphs
[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5055 todo_wine
ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
5060 static void test_CreateFontIndirect(void)
5062 LOGFONTA lf
, getobj_lf
;
5065 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
5067 memset(&lf
, 0, sizeof(lf
));
5068 lf
.lfCharSet
= ANSI_CHARSET
;
5069 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5072 lf
.lfQuality
= DEFAULT_QUALITY
;
5073 lf
.lfItalic
= FALSE
;
5074 lf
.lfWeight
= FW_DONTCARE
;
5076 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5078 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5079 hfont
= CreateFontIndirectA(&lf
);
5080 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5081 SetLastError(0xdeadbeef);
5082 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
5083 ok(ret
, "GetObject failed: %d\n", GetLastError());
5084 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
5085 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
5086 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
5087 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
5088 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
5089 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
5090 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
5091 DeleteObject(hfont
);
5095 static void test_CreateFontIndirectEx(void)
5097 ENUMLOGFONTEXDVA lfex
;
5100 if (!pCreateFontIndirectExA
)
5102 win_skip("CreateFontIndirectExA is not available\n");
5106 if (!is_truetype_font_installed("Arial"))
5108 skip("Arial is not installed\n");
5112 SetLastError(0xdeadbeef);
5113 hfont
= pCreateFontIndirectExA(NULL
);
5114 ok(hfont
== NULL
, "got %p\n", hfont
);
5115 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
5117 memset(&lfex
, 0, sizeof(lfex
));
5118 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
5119 hfont
= pCreateFontIndirectExA(&lfex
);
5120 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
5122 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
5123 DeleteObject(hfont
);
5126 static void test_realization_info(const char *name
, DWORD size
, BOOL is_memory_resource
)
5128 struct font_realization_info info
;
5129 struct file_info file_info
;
5130 HFONT hfont
, hfont_prev
;
5137 if (!pGetFontRealizationInfo
)
5140 memset(&lf
, 0, sizeof(lf
));
5142 strcpy(lf
.lfFaceName
, name
);
5144 hfont
= CreateFontIndirectA(&lf
);
5145 ok(hfont
!= 0, "Failed to create a font, %u.\n", GetLastError());
5149 hfont_prev
= SelectObject(hdc
, hfont
);
5150 ok(hfont_prev
!= NULL
, "Failed to select font.\n");
5152 memset(&info
, 0xcc, sizeof(info
));
5153 info
.size
= sizeof(info
);
5154 ret
= pGetFontRealizationInfo(hdc
, (DWORD
*)&info
);
5155 ok(ret
!= 0, "Unexpected return value %d.\n", ret
);
5157 ok((info
.flags
& 0xf) == 0x3, "Unexpected flags %#x.\n", info
.flags
);
5158 ok(info
.cache_num
!= 0, "Unexpected cache num %u.\n", info
.cache_num
);
5159 ok(info
.instance_id
!= 0, "Unexpected instance id %u.\n", info
.instance_id
);
5160 ok(info
.simulations
== 0, "Unexpected simulations %#x.\n", info
.simulations
);
5161 ok(info
.face_index
== 0, "Unexpected face index %u.\n", info
.face_index
);
5163 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, NULL
);
5164 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5165 ret
, GetLastError());
5168 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, &needed
);
5169 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5170 ret
, GetLastError());
5172 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, 0, NULL
);
5173 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5174 ret
, GetLastError());
5176 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
- 1, NULL
);
5177 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5178 ret
, GetLastError());
5180 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
, NULL
);
5181 ok(ret
!= 0, "Failed to get font file info, ret %d gle %d.\n", ret
, GetLastError());
5183 memset(&file_info
, 0xcc, sizeof(file_info
));
5184 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, sizeof(file_info
), NULL
);
5185 ok(ret
!= 0, "Failed to get font file info, ret %d gle %d.\n", ret
, GetLastError());
5188 ok(is_memory_resource
? file_info
.size
.QuadPart
== size
: file_info
.size
.QuadPart
> 0, "Unexpected file size.\n");
5189 ok(is_memory_resource
? !file_info
.path
[0] : file_info
.path
[0], "Unexpected file path %s.\n",
5190 wine_dbgstr_w(file_info
.path
));
5193 size
= file_info
.size
.LowPart
;
5194 data
= HeapAlloc(GetProcessHeap(), 0, size
+ 16);
5196 memset(data
, 0xcc, size
);
5197 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
);
5198 ok(ret
!= 0, "Failed to get font file data, %d\n", GetLastError());
5199 ok(*(DWORD
*)data
== 0x00000100, "Unexpected sfnt header version %#x.\n", *(DWORD
*)data
);
5200 ok(*(WORD
*)(data
+ 4) == 0x0e00, "Unexpected table count %#x.\n", *(WORD
*)(data
+ 4));
5202 /* Larger than font data size. */
5203 memset(data
, 0xcc, size
);
5204 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
+ 16);
5205 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %d\n",
5206 ret
, GetLastError());
5207 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5210 memset(data
, 0xcc, size
);
5211 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
- 16);
5212 ok(ret
!= 0, "Failed to get font file data, %d\n", GetLastError());
5213 ok(*(DWORD
*)data
== 0x1000000, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5215 memset(data
, 0xcc, size
);
5216 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
);
5217 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %d\n",
5218 ret
, GetLastError());
5219 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5221 /* Zero buffer size. */
5222 memset(data
, 0xcc, size
);
5223 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, 0);
5225 ok(ret
== 0 && GetLastError() == ERROR_NOACCESS
, "Unexpected return value %d, error %d\n", ret
, GetLastError());
5226 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5228 HeapFree(GetProcessHeap(), 0, data
);
5230 SelectObject(hdc
, hfont_prev
);
5231 DeleteObject(hfont
);
5232 ReleaseDC(NULL
, hdc
);
5235 static void test_AddFontMemResource(void)
5237 char ttf_name
[MAX_PATH
];
5239 DWORD font_size
, num_fonts
;
5243 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
5245 win_skip("AddFontMemResourceEx is not available on this platform\n");
5249 SetLastError(0xdeadbeef);
5250 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
5251 ok(!ret
, "AddFontMemResourceEx should fail\n");
5252 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5253 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5256 SetLastError(0xdeadbeef);
5257 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
5258 ok(!ret
, "AddFontMemResourceEx should fail\n");
5259 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5260 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5263 SetLastError(0xdeadbeef);
5264 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
5265 ok(!ret
, "AddFontMemResourceEx should fail\n");
5266 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5267 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5270 SetLastError(0xdeadbeef);
5271 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
5272 ok(!ret
, "AddFontMemResourceEx should fail\n");
5273 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5274 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5277 /* Now with scalable font */
5278 bRet
= write_ttf_file("wine_test.ttf", ttf_name
);
5279 ok(bRet
, "Failed to create test font file.\n");
5281 font
= load_font(ttf_name
, &font_size
);
5282 ok(font
!= NULL
, "Failed to map font file.\n");
5284 bRet
= is_truetype_font_installed("wine_test");
5285 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5288 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5289 ok(ret
!= 0, "Failed to add resource, %d.\n", GetLastError());
5290 ok(num_fonts
== 1, "Unexpected number of fonts %u.\n", num_fonts
);
5292 bRet
= is_truetype_font_installed("wine_test");
5294 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5296 test_realization_info("wine_test", font_size
, TRUE
);
5298 bRet
= pRemoveFontMemResourceEx(ret
);
5299 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
5303 bRet
= DeleteFileA(ttf_name
);
5304 ok(bRet
, "Failed to delete font file, %d.\n", GetLastError());
5306 font
= load_font("sserife.fon", &font_size
);
5309 skip("Unable to locate and load font sserife.fon\n");
5313 SetLastError(0xdeadbeef);
5314 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
5315 ok(!ret
, "AddFontMemResourceEx should fail\n");
5316 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5317 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5320 SetLastError(0xdeadbeef);
5321 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
5322 ok(!ret
, "AddFontMemResourceEx should fail\n");
5323 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5324 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5327 num_fonts
= 0xdeadbeef;
5328 SetLastError(0xdeadbeef);
5329 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
5330 ok(!ret
, "AddFontMemResourceEx should fail\n");
5331 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5332 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5334 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5336 if (0) /* hangs under windows 2000 */
5338 num_fonts
= 0xdeadbeef;
5339 SetLastError(0xdeadbeef);
5340 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
5341 ok(!ret
, "AddFontMemResourceEx should fail\n");
5342 ok(GetLastError() == 0xdeadbeef,
5343 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5345 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5348 num_fonts
= 0xdeadbeef;
5349 SetLastError(0xdeadbeef);
5350 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5351 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
5352 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5353 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
5357 SetLastError(0xdeadbeef);
5358 bRet
= pRemoveFontMemResourceEx(ret
);
5359 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
5361 /* test invalid pointer to number of loaded fonts */
5362 font
= load_font("sserife.fon", &font_size
);
5363 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
5365 SetLastError(0xdeadbeef);
5366 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
5367 ok(!ret
, "AddFontMemResourceEx should fail\n");
5368 ok(GetLastError() == 0xdeadbeef,
5369 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5372 SetLastError(0xdeadbeef);
5373 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
5374 ok(!ret
, "AddFontMemResourceEx should fail\n");
5375 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5376 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5382 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5386 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5388 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5390 lf
= (LOGFONTA
*)lparam
;
5395 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5400 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5402 lf
= (LOGFONTA
*)lparam
;
5403 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
5406 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5413 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5418 static void test_EnumFonts(void)
5424 if (!is_truetype_font_installed("Arial"))
5426 skip("Arial is not installed\n");
5430 /* Windows uses localized font face names, so Arial Bold won't be found */
5431 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
5433 skip("User locale is not English, skipping the test\n");
5437 hdc
= CreateCompatibleDC(0);
5439 /* check that the enumproc's retval is returned */
5440 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
5441 ok(ret
== 0xcafe, "got %08x\n", ret
);
5443 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
5444 ok(!ret
, "font Arial is not enumerated\n");
5445 ret
= strcmp(lf
.lfFaceName
, "Arial");
5446 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5447 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5449 strcpy(lf
.lfFaceName
, "Arial");
5450 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5451 ok(!ret
, "font Arial is not enumerated\n");
5452 ret
= strcmp(lf
.lfFaceName
, "Arial");
5453 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5454 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5456 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5457 ok(!ret
, "font Arial Bold is not enumerated\n");
5458 ret
= strcmp(lf
.lfFaceName
, "Arial");
5459 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5460 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5462 strcpy(lf
.lfFaceName
, "Arial Bold");
5463 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5464 ok(ret
, "font Arial Bold should not be enumerated\n");
5466 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
5467 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
5468 ret
= strcmp(lf
.lfFaceName
, "Arial");
5469 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5470 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5472 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
5473 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5474 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
5476 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5477 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5479 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
5480 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5481 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5486 static INT CALLBACK
enum_ms_shell_dlg_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5488 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5490 if (0) /* Disabled to limit console spam */
5491 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5492 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5494 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5495 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg") != 0) return 1;
5497 if (efnd
->total
>= efnd
->size
)
5499 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5500 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5501 if (!efnd
->elf
) return 0;
5503 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5507 static INT CALLBACK
enum_ms_shell_dlg2_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5509 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5511 if (0) /* Disabled to limit console spam */
5512 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5513 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5515 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5516 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg 2") != 0) return 1;
5518 if (efnd
->total
>= efnd
->size
)
5520 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5521 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5522 if (!efnd
->elf
) return 0;
5524 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5528 static void test_EnumFonts_subst(void)
5533 struct enum_fullname_data efnd
;
5535 ret
= is_font_installed("MS Shell Dlg");
5536 ok(ret
, "MS Shell Dlg should be enumerated\n");
5537 ret
= is_truetype_font_installed("MS Shell Dlg");
5538 ok(ret
, "MS Shell Dlg should be enumerated as a TrueType font\n");
5540 ret
= is_font_installed("MS Shell Dlg 2");
5541 ok(ret
, "MS Shell Dlg 2 should be enumerated\n");
5542 ret
= is_truetype_font_installed("MS Shell Dlg 2");
5543 ok(ret
, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5545 hdc
= CreateCompatibleDC(0);
5547 memset(&efnd
, 0, sizeof(efnd
));
5548 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5549 ok(ret
, "MS Shell Dlg should not be enumerated\n");
5550 ok(!efnd
.total
, "MS Shell Dlg should not be enumerated\n");
5552 memset(&lf
, 0, sizeof(lf
));
5553 lf
.lfCharSet
= DEFAULT_CHARSET
;
5556 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
5557 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5558 ok(!ret
, "MS Shell Dlg should be enumerated\n");
5559 ok(efnd
.total
> 0, "MS Shell Dlg should be enumerated\n");
5562 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
5563 ok(!ret
, "expected MS Shell Dlg, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5564 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
5565 ok(ret
, "did not expect MS Shell Dlg\n");
5569 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5570 ok(ret
, "MS Shell Dlg 2 should not be enumerated\n");
5571 ok(!efnd
.total
, "MS Shell Dlg 2 should not be enumerated\n");
5574 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
5575 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5576 ok(!ret
, "MS Shell Dlg 2 should be enumerated\n");
5577 ok(efnd
.total
> 0, "MS Shell Dlg 2 should be enumerated\n");
5580 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
5581 ok(!ret
, "expected MS Shell Dlg 2, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5582 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
5583 ok(ret
, "did not expect MS Shell Dlg 2\n");
5586 heap_free(efnd
.elf
);
5590 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5592 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
5593 const char *fullname
= (const char *)lParam
;
5595 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
5600 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
5605 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
5612 static void test_fullname(void)
5614 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5615 WCHAR bufW
[LF_FULLFACESIZE
];
5616 char bufA
[LF_FULLFACESIZE
];
5623 hdc
= CreateCompatibleDC(0);
5624 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5626 memset(&lf
, 0, sizeof(lf
));
5627 lf
.lfCharSet
= ANSI_CHARSET
;
5628 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5631 lf
.lfQuality
= DEFAULT_QUALITY
;
5632 lf
.lfItalic
= FALSE
;
5633 lf
.lfWeight
= FW_DONTCARE
;
5635 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5637 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
5639 skip("%s is not installed\n", TestName
[i
]);
5643 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5644 hfont
= CreateFontIndirectA(&lf
);
5645 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5647 of
= SelectObject(hdc
, hfont
);
5650 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5651 ok(ret
, "face full name could not be read\n");
5652 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
5653 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
5654 SelectObject(hdc
, of
);
5655 DeleteObject(hfont
);
5660 static WCHAR
*prepend_at(WCHAR
*family
)
5665 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
5670 static void test_fullname2_helper(const char *Family
)
5672 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
5673 struct enum_fullname_data efnd
;
5680 DWORD otm_size
, ret
, buf_size
;
5681 OUTLINETEXTMETRICA
*otm
;
5682 BOOL want_vertical
, get_vertical
;
5683 want_vertical
= ( Family
[0] == '@' );
5685 hdc
= CreateCompatibleDC(0);
5686 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5688 memset(&lf
, 0, sizeof(lf
));
5689 lf
.lfCharSet
= DEFAULT_CHARSET
;
5690 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5693 lf
.lfQuality
= DEFAULT_QUALITY
;
5694 lf
.lfItalic
= FALSE
;
5695 lf
.lfWeight
= FW_DONTCARE
;
5696 strcpy(lf
.lfFaceName
, Family
);
5697 memset(&efnd
, 0, sizeof(efnd
));
5698 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
5699 if (efnd
.total
== 0)
5700 skip("%s is not installed\n", lf
.lfFaceName
);
5702 for (i
= 0; i
< efnd
.total
; i
++)
5704 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
5705 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
5706 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
5708 get_vertical
= ( FamilyName
[0] == '@' );
5709 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
5711 lstrcpyA(lf
.lfFaceName
, FaceName
);
5712 hfont
= CreateFontIndirectA(&lf
);
5713 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5715 of
= SelectObject(hdc
, hfont
);
5716 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
5717 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
5718 if (buf_size
== GDI_ERROR
) continue;
5720 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5721 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5723 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5724 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5725 memset(otm
, 0, otm_size
);
5726 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
5727 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
5728 if (ret
== 0) continue;
5732 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5733 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5734 ok(ret
, "%s: FAMILY (family name) could not be read\n", FamilyName
);
5735 if (want_vertical
) bufW
= prepend_at(bufW
);
5736 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5737 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
5738 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
5739 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
5743 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
5744 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5745 ok(ret
, "FULL_NAME (face name) could not be read\n");
5746 if (want_vertical
) bufW
= prepend_at(bufW
);
5747 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5748 ok(!lstrcmpA(FaceName
, bufA
), "%s: font face names don't match: returned %s, expect %s\n", FamilyName
, FaceName
, bufA
);
5749 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
5750 ok(!lstrcmpA(FaceName
, otmStr
), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName
, FaceName
, otmStr
);
5754 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5755 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5756 ok(ret
, "%s: SUBFAMILY (style name) could not be read\n", FamilyName
);
5757 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5758 ok(!lstrcmpA(StyleName
, bufA
), "%s: style names don't match: returned %s, expect %s\n", FamilyName
, StyleName
, bufA
);
5759 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
5760 ok(!lstrcmpA(StyleName
, otmStr
), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName
, StyleName
, otmStr
);
5764 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
5765 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5766 ok(ret
, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName
);
5767 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5768 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
5769 ok(!lstrcmpA(otmStr
, bufA
), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName
, otmStr
, bufA
);
5771 SelectObject(hdc
, of
);
5772 DeleteObject(hfont
);
5774 HeapFree(GetProcessHeap(), 0, otm
);
5775 HeapFree(GetProcessHeap(), 0, bufW
);
5776 HeapFree(GetProcessHeap(), 0, bufA
);
5778 heap_free(efnd
.elf
);
5782 static void test_fullname2(void)
5784 test_fullname2_helper("Arial");
5785 test_fullname2_helper("DejaVu Sans");
5786 test_fullname2_helper("Lucida Sans");
5787 test_fullname2_helper("Tahoma");
5788 test_fullname2_helper("Webdings");
5789 test_fullname2_helper("Wingdings");
5790 test_fullname2_helper("SimSun");
5791 test_fullname2_helper("NSimSun");
5792 test_fullname2_helper("MingLiu");
5793 test_fullname2_helper("PMingLiu");
5794 test_fullname2_helper("WenQuanYi Micro Hei");
5795 test_fullname2_helper("MS UI Gothic");
5796 test_fullname2_helper("Ume UI Gothic");
5797 test_fullname2_helper("MS Gothic");
5798 test_fullname2_helper("Ume Gothic");
5799 test_fullname2_helper("MS PGothic");
5800 test_fullname2_helper("Ume P Gothic");
5801 test_fullname2_helper("Gulim");
5802 test_fullname2_helper("Batang");
5803 test_fullname2_helper("UnBatang");
5804 test_fullname2_helper("UnDotum");
5805 test_fullname2_helper("@SimSun");
5806 test_fullname2_helper("@NSimSun");
5807 test_fullname2_helper("@MingLiu");
5808 test_fullname2_helper("@PMingLiu");
5809 test_fullname2_helper("@WenQuanYi Micro Hei");
5810 test_fullname2_helper("@MS UI Gothic");
5811 test_fullname2_helper("@Ume UI Gothic");
5812 test_fullname2_helper("@MS Gothic");
5813 test_fullname2_helper("@Ume Gothic");
5814 test_fullname2_helper("@MS PGothic");
5815 test_fullname2_helper("@Ume P Gothic");
5816 test_fullname2_helper("@Gulim");
5817 test_fullname2_helper("@Batang");
5818 test_fullname2_helper("@UnBatang");
5819 test_fullname2_helper("@UnDotum");
5823 static void test_GetGlyphOutline_empty_contour(void)
5827 HFONT hfont
, hfont_prev
;
5828 TTPOLYGONHEADER
*header
;
5833 memset(&lf
, 0, sizeof(lf
));
5835 lstrcpyA(lf
.lfFaceName
, "wine_test");
5837 hfont
= CreateFontIndirectA(&lf
);
5838 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5842 hfont_prev
= SelectObject(hdc
, hfont
);
5843 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5845 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5846 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5848 header
= (TTPOLYGONHEADER
*)buf
;
5849 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5850 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5851 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5852 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5853 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5854 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5855 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5856 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5858 SelectObject(hdc
, hfont_prev
);
5859 DeleteObject(hfont
);
5860 ReleaseDC(NULL
, hdc
);
5863 static void test_GetGlyphOutline_metric_clipping(void)
5867 HFONT hfont
, hfont_prev
;
5873 memset(&lf
, 0, sizeof(lf
));
5875 lstrcpyA(lf
.lfFaceName
, "wine_test");
5877 SetLastError(0xdeadbeef);
5878 hfont
= CreateFontIndirectA(&lf
);
5879 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5883 hfont_prev
= SelectObject(hdc
, hfont
);
5884 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5886 SetLastError(0xdeadbeef);
5887 ret
= GetTextMetricsA(hdc
, &tm
);
5888 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5890 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5891 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5892 "Glyph top(%d) exceeds ascent(%d)\n",
5893 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5894 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5895 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5896 "Glyph bottom(%d) exceeds descent(%d)\n",
5897 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5899 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5900 GetTextMetricsW(hdc
, &tmW
);
5902 ok( tmW
.tmLastChar
== 0xfffe, "got %04x\n", tmW
.tmLastChar
);
5904 SelectObject(hdc
, hfont_prev
);
5905 DeleteObject(hfont
);
5906 ReleaseDC(NULL
, hdc
);
5909 static void test_GetGlyphOutline_character(void)
5911 HFONT hfont
, hfont_old
;
5915 GLYPHMETRICS gm1
, gm2
, gmn
;
5916 char test_chars
[] = { 'A', 'D', '!', '\0' };
5919 memset(&lf
, 0, sizeof(lf
));
5921 lstrcpyA(lf
.lfFaceName
, "wine_test");
5923 hfont
= CreateFontIndirectA(&lf
);
5924 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5928 hfont_old
= SelectObject(hdc
, hfont
);
5929 ok(hfont_old
!= NULL
, "SelectObject failed\n");
5931 ret
= GetGlyphOutlineW(hdc
, 'Z', GGO_METRICS
, &gmn
, 0, NULL
, &mat
);
5932 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed to default to .notdef for character 'Z'\n");
5934 for (current_char
= test_chars
; *current_char
!= '\0'; current_char
++)
5936 ret
= GetGlyphOutlineW(hdc
, *current_char
, GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
5937 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for '%c'\n", *current_char
);
5938 ok(memcmp(&gm1
, &gmn
, sizeof(gmn
)) != 0, "the test character '%c' matches .notdef\n", *current_char
);
5940 ret
= GetGlyphOutlineW(hdc
, 0x10000 + *current_char
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
5941 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for 0x10000 + '%c'\n", *current_char
);
5942 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for character 0x10000 + '%c'\n", *current_char
);
5945 ret
= GetGlyphOutlineW(hdc
, 0x3, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm1
, 0, NULL
, &mat
);
5946 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for glyph index 0x3\n");
5948 ret
= GetGlyphOutlineW(hdc
, 0xFFFF, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5949 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW for nonexistent glyph index 0xFFFF has succeeded\n");
5951 ret
= GetGlyphOutlineW(hdc
, 0x10003, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5952 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW for index 0x10003 has failed\n");
5953 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for glyph 0x10003\n");
5955 SelectObject(hdc
, hfont_old
);
5956 DeleteObject(hfont
);
5957 ReleaseDC(NULL
, hdc
);
5960 static void test_fstype_fixup(void)
5964 HFONT hfont
, hfont_prev
;
5966 OUTLINETEXTMETRICA
*otm
;
5969 memset(&lf
, 0, sizeof(lf
));
5971 lstrcpyA(lf
.lfFaceName
, "wine_test");
5973 SetLastError(0xdeadbeef);
5974 hfont
= CreateFontIndirectA(&lf
);
5975 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5979 hfont_prev
= SelectObject(hdc
, hfont
);
5980 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5982 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5983 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5984 otm
->otmSize
= sizeof(*otm
);
5985 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
5986 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
5988 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5989 valid bits are 1, 2, 3, 8, 9. */
5990 ok((otm
->otmfsType
& ~0x30e) == 0, "fsType %#x\n", otm
->otmfsType
);
5992 HeapFree(GetProcessHeap(), 0, otm
);
5994 SelectObject(hdc
, hfont_prev
);
5995 DeleteObject(hfont
);
5996 ReleaseDC(NULL
, hdc
);
5999 static void test_CreateScalableFontResource(void)
6001 char ttf_name
[MAX_PATH
];
6002 char tmp_path
[MAX_PATH
];
6003 char fot_name
[MAX_PATH
];
6008 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
6010 win_skip("AddFontResourceExA is not available on this platform\n");
6014 if (!write_ttf_file("wine_test.ttf", ttf_name
))
6016 skip("Failed to create ttf file for testing\n");
6020 trace("created %s\n", ttf_name
);
6022 ret
= is_truetype_font_installed("wine_test");
6023 ok(!ret
, "font wine_test should not be enumerated\n");
6025 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
6026 ok(ret
, "GetTempPath() error %d\n", GetLastError());
6027 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
6028 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
6030 ret
= GetFileAttributesA(fot_name
);
6031 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
6033 SetLastError(0xdeadbeef);
6034 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
6035 ok(!ret
, "CreateScalableFontResource() should fail\n");
6036 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
6038 SetLastError(0xdeadbeef);
6039 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
6040 ok(!ret
, "CreateScalableFontResource() should fail\n");
6041 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
6043 file_part
= strrchr(ttf_name
, '\\');
6044 SetLastError(0xdeadbeef);
6045 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
6046 ok(!ret
, "CreateScalableFontResource() should fail\n");
6047 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
6049 SetLastError(0xdeadbeef);
6050 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
6051 ok(!ret
, "CreateScalableFontResource() should fail\n");
6052 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
6054 SetLastError(0xdeadbeef);
6055 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
6056 ok(!ret
, "CreateScalableFontResource() should fail\n");
6057 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
6059 ret
= DeleteFileA(fot_name
);
6060 ok(ret
, "DeleteFile() error %d\n", GetLastError());
6062 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6063 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6065 /* test public font resource */
6066 SetLastError(0xdeadbeef);
6067 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
6068 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
6070 ret
= is_truetype_font_installed("wine_test");
6071 ok(!ret
, "font wine_test should not be enumerated\n");
6073 SetLastError(0xdeadbeef);
6074 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6075 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6077 ret
= is_truetype_font_installed("wine_test");
6078 ok(ret
, "font wine_test should be enumerated\n");
6080 test_GetGlyphOutline_empty_contour();
6081 test_GetGlyphOutline_metric_clipping();
6082 test_GetGlyphOutline_character();
6083 test_fstype_fixup();
6085 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6086 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
6088 SetLastError(0xdeadbeef);
6089 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6090 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6092 ret
= is_truetype_font_installed("wine_test");
6093 ok(!ret
, "font wine_test should not be enumerated\n");
6095 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6096 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6098 /* test refcounting */
6099 for (i
= 0; i
< 5; i
++)
6101 SetLastError(0xdeadbeef);
6102 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6103 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6105 for (i
= 0; i
< 5; i
++)
6107 SetLastError(0xdeadbeef);
6108 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6109 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6111 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6112 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6114 DeleteFileA(fot_name
);
6116 /* test hidden font resource */
6117 SetLastError(0xdeadbeef);
6118 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
6119 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
6121 ret
= is_truetype_font_installed("wine_test");
6122 ok(!ret
, "font wine_test should not be enumerated\n");
6124 SetLastError(0xdeadbeef);
6125 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6126 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6128 ret
= is_truetype_font_installed("wine_test");
6130 ok(!ret
, "font wine_test should not be enumerated\n");
6132 /* XP allows removing a private font added with 0 flags */
6133 SetLastError(0xdeadbeef);
6134 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6135 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6137 ret
= is_truetype_font_installed("wine_test");
6138 ok(!ret
, "font wine_test should not be enumerated\n");
6140 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6141 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6143 DeleteFileA(fot_name
);
6144 DeleteFileA(ttf_name
);
6147 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
6150 HFONT hfont
, hfont_prev
;
6154 static const WCHAR str
[] = { 0x2025 };
6156 *installed
= is_truetype_font_installed(name
);
6160 lf
.lfEscapement
= 0;
6161 lf
.lfOrientation
= 0;
6162 lf
.lfWeight
= FW_DONTCARE
;
6166 lf
.lfCharSet
= DEFAULT_CHARSET
;
6167 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
6168 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6169 lf
.lfQuality
= DEFAULT_QUALITY
;
6170 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
6171 strcpy(lf
.lfFaceName
, name
);
6173 hfont
= CreateFontIndirectA(&lf
);
6174 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
6178 hfont_prev
= SelectObject(hdc
, hfont
);
6179 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
6181 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
6182 ok(ret
, "GetTextFaceA failed\n");
6183 *selected
= !strcmp(facename
, name
);
6185 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
6186 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6188 memset(gm
, 0, sizeof *gm
);
6190 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
6191 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
6193 SelectObject(hdc
, hfont_prev
);
6194 DeleteObject(hfont
);
6195 ReleaseDC(NULL
, hdc
);
6198 static void check_vertical_metrics(const char *face
)
6201 HFONT hfont
, hfont_prev
;
6204 GLYPHMETRICS rgm
, vgm
;
6205 const UINT code
= 0x5EAD, height
= 1000;
6208 OUTLINETEXTMETRICA otm
;
6209 USHORT numOfLongVerMetrics
;
6213 memset(&lf
, 0, sizeof(lf
));
6214 strcpy(lf
.lfFaceName
, face
);
6215 lf
.lfHeight
= -height
;
6216 lf
.lfCharSet
= DEFAULT_CHARSET
;
6217 lf
.lfEscapement
= lf
.lfOrientation
= 900;
6218 hfont
= CreateFontIndirectA(&lf
);
6219 hfont_prev
= SelectObject(hdc
, hfont
);
6220 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
6221 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6222 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
6223 ok(ret
, "GetCharABCWidthsW failed\n");
6224 DeleteObject(SelectObject(hdc
, hfont_prev
));
6226 memset(&lf
, 0, sizeof(lf
));
6227 strcpy(lf
.lfFaceName
, "@");
6228 strcat(lf
.lfFaceName
, face
);
6229 lf
.lfHeight
= -height
;
6230 lf
.lfCharSet
= DEFAULT_CHARSET
;
6231 hfont
= CreateFontIndirectA(&lf
);
6232 hfont_prev
= SelectObject(hdc
, hfont
);
6233 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
6234 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6235 ret
= GetCharABCWidthsW(hdc
, code
, code
, &vabc
);
6236 ok(ret
, "GetCharABCWidthsW failed\n");
6237 ok(vabc
.abcA
== vgm
.gmptGlyphOrigin
.x
, "expected %d, got %d\n",
6238 vabc
.abcA
, vgm
.gmptGlyphOrigin
.x
);
6239 ok(vabc
.abcB
== vgm
.gmBlackBoxX
, "expected %d, got %d\n",
6240 vabc
.abcB
, vgm
.gmBlackBoxX
);
6241 ok(vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
== vgm
.gmCellIncX
,
6242 "expected %d, got %d\n",
6243 vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
, vgm
.gmCellIncX
);
6245 memset(&otm
, 0, sizeof(otm
));
6246 otm
.otmSize
= sizeof(otm
);
6247 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
6248 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
6250 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
6251 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
6253 SHORT topSideBearing
;
6255 if (!pGetGlyphIndicesW
) {
6256 win_skip("GetGlyphIndices is not available on this platform\n");
6259 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
6260 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
6261 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
6262 if (numOfLongVerMetrics
> idx
)
6263 offset
= idx
* 2 + 1;
6265 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
6266 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
6267 &topSideBearing
, sizeof(SHORT
));
6268 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
6269 topSideBearing
= GET_BE_WORD(topSideBearing
);
6270 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
6271 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
6272 "expected %d, got %d\n",
6273 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
6278 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
6279 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
6280 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
6283 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
6284 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
6285 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6286 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
6288 DeleteObject(SelectObject(hdc
, hfont_prev
));
6289 ReleaseDC(NULL
, hdc
);
6292 static void test_vertical_font(void)
6294 char ttf_name
[MAX_PATH
];
6296 BOOL ret
, installed
, selected
;
6299 const char* face_list
[] = {
6300 "@WineTestVertical", /* has vmtx table */
6301 "@Ume Gothic", /* doesn't have vmtx table */
6302 "@MS UI Gothic", /* has vmtx table, available on native */
6305 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
6307 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
6311 if (!write_ttf_file("vertical.ttf", ttf_name
))
6313 skip("Failed to create ttf file for testing\n");
6317 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6318 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6320 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
6321 ok(installed
, "WineTestVertical is not installed\n");
6322 ok(selected
, "WineTestVertical is not selected\n");
6323 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6324 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6325 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6327 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
6328 ok(installed
, "@WineTestVertical is not installed\n");
6329 ok(selected
, "@WineTestVertical is not selected\n");
6330 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6331 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6332 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6334 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
6336 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++) {
6337 const char* face
= face_list
[i
];
6338 if (!is_truetype_font_installed(face
)) {
6339 skip("%s is not installed\n", face
);
6342 check_vertical_metrics(&face
[1]);
6345 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6346 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6348 DeleteFileA(ttf_name
);
6351 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
6352 DWORD type
, LPARAM lParam
)
6354 if (lf
->lfFaceName
[0] == '@') {
6360 static void test_east_asian_font_selection(void)
6363 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
6364 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
6369 for (i
= 0; i
< ARRAY_SIZE(charset
); i
++)
6373 char face_name
[LF_FACESIZE
];
6376 memset(&lf
, 0, sizeof lf
);
6377 lf
.lfFaceName
[0] = '\0';
6378 lf
.lfCharSet
= charset
[i
];
6380 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
6382 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
6386 hfont
= CreateFontIndirectA(&lf
);
6387 hfont
= SelectObject(hdc
, hfont
);
6388 memset(face_name
, 0, sizeof face_name
);
6389 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6390 ok(ret
&& face_name
[0] != '@',
6391 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6392 DeleteObject(SelectObject(hdc
, hfont
));
6394 memset(&lf
, 0, sizeof lf
);
6395 strcpy(lf
.lfFaceName
, "@");
6396 lf
.lfCharSet
= charset
[i
];
6397 hfont
= CreateFontIndirectA(&lf
);
6398 hfont
= SelectObject(hdc
, hfont
);
6399 memset(face_name
, 0, sizeof face_name
);
6400 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6401 ok(ret
&& face_name
[0] == '@',
6402 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6403 DeleteObject(SelectObject(hdc
, hfont
));
6405 ReleaseDC(NULL
, hdc
);
6408 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
6410 HDC hdc
= CreateCompatibleDC(0);
6415 hfont
= CreateFontIndirectA(lf
);
6416 ok(hfont
!= 0, "CreateFontIndirect failed\n");
6418 SelectObject(hdc
, hfont
);
6419 ret
= GetTextMetricsA(hdc
, &tm
);
6420 ok(ret
, "GetTextMetrics failed\n");
6421 ret
= tm
.tmDigitizedAspectX
;
6422 if (height
) *height
= tm
.tmHeight
;
6425 DeleteObject(hfont
);
6430 static void test_stock_fonts(void)
6432 static const int font
[] =
6434 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
6435 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6437 static const struct test_data
6439 int charset
, weight
, height
, height_pixels
, dpi
;
6440 const char face_name
[LF_FACESIZE
];
6444 { /* ANSI_FIXED_FONT */
6445 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_ARABIC
},
6446 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_HEBREW
},
6447 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
6448 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
6451 { /* ANSI_VAR_FONT */
6452 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
6453 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
6457 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6458 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6459 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6460 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6461 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6462 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6465 { /* DEVICE_DEFAULT_FONT */
6466 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6467 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6468 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6469 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6470 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6471 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6474 { /* DEFAULT_GUI_FONT */
6475 { SHIFTJIS_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6476 { SHIFTJIS_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6477 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
6478 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
6479 { HANGEUL_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6480 { HANGEUL_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6481 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
6482 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
6483 { GB2312_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6484 { GB2312_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6485 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
6486 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
6487 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
6488 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
6489 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6490 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6496 for (i
= 0; i
< ARRAY_SIZE(font
); i
++)
6502 hfont
= GetStockObject(font
[i
]);
6503 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
6505 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
6506 if (ret
!= sizeof(lf
))
6509 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
6513 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
6515 if ((lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
) ||
6516 (system_lang_id
!= td
[i
][j
].lang_id
&& td
[i
][j
].lang_id
!= LANG_NEUTRAL
) ||
6517 (td
[i
][j
].face_name
[0] != '?' && strcmp(lf
.lfFaceName
, td
[i
][j
].face_name
)))
6522 ret
= get_font_dpi(&lf
, &height
);
6523 if (ret
!= td
[i
][j
].dpi
)
6525 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6526 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
6530 /* FIXME: Remove once Wine is fixed */
6531 todo_wine_if (td
[i
][j
].dpi
!= 96 &&
6532 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6533 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
6534 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6535 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
6536 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
6538 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
6539 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
6540 if (td
[i
][j
].face_name
[0] == '?')
6542 /* Wine doesn't have this font, skip this case for now.
6543 Actually, the face name is localized on Windows and varies
6544 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6545 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
6549 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
);
6556 static void test_max_height(void)
6560 HFONT hfont
, hfont_old
;
6561 TEXTMETRICA tm1
, tm
;
6563 LONG invalid_height
[] = { -65536, -123456, 123456 };
6566 memset(&tm1
, 0, sizeof(tm1
));
6567 memset(&lf
, 0, sizeof(lf
));
6568 strcpy(lf
.lfFaceName
, "Tahoma");
6573 /* get 1 ppem value */
6574 hfont
= CreateFontIndirectA(&lf
);
6575 hfont_old
= SelectObject(hdc
, hfont
);
6576 r
= GetTextMetricsA(hdc
, &tm1
);
6577 ok(r
, "GetTextMetrics failed\n");
6578 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6579 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6580 DeleteObject(SelectObject(hdc
, hfont_old
));
6582 /* test the largest value */
6583 lf
.lfHeight
= -((1 << 16) - 1);
6584 hfont
= CreateFontIndirectA(&lf
);
6585 hfont_old
= SelectObject(hdc
, hfont
);
6586 memset(&tm
, 0, sizeof(tm
));
6587 r
= GetTextMetricsA(hdc
, &tm
);
6588 ok(r
, "GetTextMetrics failed\n");
6589 ok(tm
.tmHeight
> tm1
.tmHeight
,
6590 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6591 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
6592 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6593 DeleteObject(SelectObject(hdc
, hfont_old
));
6595 /* test an invalid value */
6596 for (i
= 0; i
< ARRAY_SIZE(invalid_height
); i
++) {
6597 lf
.lfHeight
= invalid_height
[i
];
6598 hfont
= CreateFontIndirectA(&lf
);
6599 hfont_old
= SelectObject(hdc
, hfont
);
6600 memset(&tm
, 0, sizeof(tm
));
6601 r
= GetTextMetricsA(hdc
, &tm
);
6602 ok(r
, "GetTextMetrics failed\n");
6603 ok(tm
.tmHeight
== tm1
.tmHeight
,
6604 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6605 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
6606 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6607 DeleteObject(SelectObject(hdc
, hfont_old
));
6610 ReleaseDC(NULL
, hdc
);
6614 static void test_vertical_order(void)
6616 struct enum_font_data efd
;
6621 hdc
= CreateCompatibleDC(0);
6622 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6624 memset(&lf
, 0, sizeof(lf
));
6625 lf
.lfCharSet
= DEFAULT_CHARSET
;
6626 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6629 lf
.lfQuality
= DEFAULT_QUALITY
;
6630 lf
.lfItalic
= FALSE
;
6631 lf
.lfWeight
= FW_DONTCARE
;
6632 memset( &efd
, 0, sizeof(efd
) );
6633 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
6634 for (i
= 0; i
< efd
.total
; i
++)
6636 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
6637 for (j
= 0; j
< efd
.total
; j
++)
6639 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
6641 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
6646 heap_free( efd
.lf
);
6650 static void test_GetCharWidth32(void)
6660 if (!pGetCharWidth32W
)
6662 win_skip("GetCharWidth32W not available on this platform\n");
6666 memset(&lf
, 0, sizeof(lf
));
6667 strcpy(lf
.lfFaceName
, "System");
6670 hfont
= CreateFontIndirectA(&lf
);
6672 hfont
= SelectObject(hdc
, hfont
);
6674 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6675 ok(ret
, "GetCharWidth32W should have succeeded\n");
6676 ret
= GetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
6677 ok(ret
, "GetCharWidth32A should have succeeded\n");
6678 ok (bufferA
== bufferW
, "Widths should be the same\n");
6679 ok (bufferA
> 0," Width should be greater than zero\n");
6681 hfont
= SelectObject(hdc
, hfont
);
6682 DeleteObject(hfont
);
6683 ReleaseDC(NULL
, hdc
);
6685 memset(&lf
, 0, sizeof(lf
));
6686 strcpy(lf
.lfFaceName
, "Tahoma");
6689 hfont
= CreateFontIndirectA(&lf
);
6690 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
6693 SetMapMode( hdc
, MM_ANISOTROPIC
);
6694 SelectObject(hdc
, hfont
);
6696 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6697 ok(ret
, "GetCharWidth32W should have succeeded\n");
6698 ok (bufferW
> 0," Width should be greater than zero\n");
6699 SetWindowExtEx(hdc
, -1,-1,NULL
);
6700 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6701 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6702 ok(ret
, "GetCharWidth32W should have succeeded\n");
6703 ok (bufferW
> 0," Width should be greater than zero\n");
6704 SetGraphicsMode(hdc
, GM_ADVANCED
);
6705 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6706 ok(ret
, "GetCharWidth32W should have succeeded\n");
6707 ok (bufferW
> 0," Width should be greater than zero\n");
6708 SetWindowExtEx(hdc
, 1,1,NULL
);
6709 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6710 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6711 ok(ret
, "GetCharWidth32W should have succeeded\n");
6712 ok (bufferW
> 0," Width should be greater than zero\n");
6713 SetGraphicsMode(hdc
, GM_ADVANCED
);
6714 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6715 ok(ret
, "GetCharWidth32W should have succeeded\n");
6716 ok (bufferW
> 0," Width should be greater than zero\n");
6718 ReleaseDC(hwnd
, hdc
);
6719 DestroyWindow(hwnd
);
6721 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
6724 SetMapMode( hdc
, MM_ANISOTROPIC
);
6725 SelectObject(hdc
, hfont
);
6727 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6728 ok(ret
, "GetCharWidth32W should have succeeded\n");
6729 ok (bufferW
> 0," Width should be greater than zero\n");
6730 SetWindowExtEx(hdc
, -1,-1,NULL
);
6731 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6732 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6733 ok(ret
, "GetCharWidth32W should have succeeded\n");
6734 ok (bufferW
> 0," Width should be greater than zero\n");
6735 SetGraphicsMode(hdc
, GM_ADVANCED
);
6736 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6737 ok(ret
, "GetCharWidth32W should have succeeded\n");
6738 ok (bufferW
> 0," Width should be greater than zero\n");
6739 SetWindowExtEx(hdc
, 1,1,NULL
);
6740 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6741 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6742 ok(ret
, "GetCharWidth32W should have succeeded\n");
6743 ok (bufferW
> 0," Width should be greater than zero\n");
6744 SetGraphicsMode(hdc
, GM_ADVANCED
);
6745 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6746 ok(ret
, "GetCharWidth32W should have succeeded\n");
6747 ok (bufferW
> 0," Width should be greater than zero\n");
6749 ReleaseDC(hwnd
, hdc
);
6750 DestroyWindow(hwnd
);
6751 DeleteObject(hfont
);
6754 static void test_fake_bold_font(void)
6756 static const MAT2 x2_mat
= { {0,2}, {0,0}, {0,0}, {0,2} };
6769 /* Test outline font */
6770 memset(&lf
, 0, sizeof(lf
));
6771 strcpy(lf
.lfFaceName
, "Wingdings");
6772 lf
.lfCharSet
= SYMBOL_CHARSET
;
6776 for (i
= 0; i
<= 1; i
++)
6778 HFONT hfont
, hfont_old
;
6780 lf
.lfWeight
= i
? FW_BOLD
: FW_NORMAL
;
6781 hfont
= CreateFontIndirectA(&lf
);
6782 hfont_old
= SelectObject(hdc
, hfont
);
6784 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6785 ok(ret
, "got %d\n", ret
);
6786 ret
= GetCharABCWidthsA(hdc
, 0x76, 0x76, &data
[i
].abc
);
6787 ok(ret
, "got %d\n", ret
);
6788 data
[i
].w
= data
[i
].abc
.abcA
+ data
[i
].abc
.abcB
+ data
[i
].abc
.abcC
;
6789 r
= GetGlyphOutlineA(hdc
, 0x76, GGO_METRICS
, &data
[i
].gm
, 0, NULL
, &x2_mat
);
6790 ok(r
!= GDI_ERROR
, "got %d\n", ret
);
6792 SelectObject(hdc
, hfont_old
);
6793 DeleteObject(hfont
);
6795 ReleaseDC(NULL
, hdc
);
6797 /* compare results (outline) */
6798 ok(data
[0].tm
.tmHeight
== data
[1].tm
.tmHeight
,
6799 "expected %d, got %d\n", data
[0].tm
.tmHeight
, data
[1].tm
.tmHeight
);
6800 ok(data
[0].tm
.tmAscent
== data
[1].tm
.tmAscent
,
6801 "expected %d, got %d\n", data
[0].tm
.tmAscent
, data
[1].tm
.tmAscent
);
6802 ok(data
[0].tm
.tmDescent
== data
[1].tm
.tmDescent
,
6803 "expected %d, got %d\n", data
[0].tm
.tmDescent
, data
[1].tm
.tmDescent
);
6804 ok(data
[0].tm
.tmAveCharWidth
+ 1 == data
[1].tm
.tmAveCharWidth
,
6805 "expected %d, got %d\n", data
[0].tm
.tmAveCharWidth
+ 1, data
[1].tm
.tmAveCharWidth
);
6806 ok(data
[0].tm
.tmMaxCharWidth
+ 1 == data
[1].tm
.tmMaxCharWidth
,
6807 "expected %d, got %d\n", data
[0].tm
.tmMaxCharWidth
+ 1, data
[1].tm
.tmMaxCharWidth
);
6808 ok(data
[0].tm
.tmOverhang
== data
[1].tm
.tmOverhang
,
6809 "expected %d, got %d\n", data
[0].tm
.tmOverhang
, data
[1].tm
.tmOverhang
);
6810 ok(data
[0].w
+ 1 == data
[1].w
,
6811 "expected %d, got %d\n", data
[0].w
+ 1, data
[1].w
);
6813 ok(data
[0].gm
.gmCellIncX
+ 1 == data
[1].gm
.gmCellIncX
,
6814 "expected %d, got %d\n", data
[0].gm
.gmCellIncX
+ 1, data
[1].gm
.gmCellIncX
);
6815 ok(data
[0].gm
.gmCellIncY
== data
[1].gm
.gmCellIncY
,
6816 "expected %d, got %d\n", data
[0].gm
.gmCellIncY
, data
[1].gm
.gmCellIncY
);
6818 /* Test bitmap font */
6819 memset(&data
, 0xaa, sizeof(data
));
6820 memset(&lf
, 0, sizeof(lf
));
6821 strcpy(lf
.lfFaceName
, "Courier");
6822 lf
.lfCharSet
= ANSI_CHARSET
;
6826 for (i
= 0; i
< 4; i
++)
6828 HFONT hfont
, hfont_old
;
6830 lf
.lfWeight
= (i
% 2) ? FW_BOLD
: FW_NORMAL
;
6831 lf
.lfHeight
= (i
> 1) ? data
[0].tm
.tmHeight
* x2_mat
.eM11
.value
: 0;
6832 hfont
= CreateFontIndirectA(&lf
);
6833 hfont_old
= SelectObject(hdc
, hfont
);
6835 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6836 ok(ret
, "got %d\n", ret
);
6837 ret
= GetCharWidth32A(hdc
, 0x76, 0x76, &data
[i
].w
);
6838 ok(ret
, "got %d\n", ret
);
6840 SelectObject(hdc
, hfont_old
);
6841 DeleteObject(hfont
);
6843 ReleaseDC(NULL
, hdc
);
6845 /* compare results (bitmap) */
6846 for (i
= 0; i
< 4; i
+=2)
6848 int diff
= (i
> 1) ? x2_mat
.eM11
.value
: 1;
6849 if (data
[i
].tm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
6851 skip("TrueType font is selected (expected a bitmap one)\n");
6854 ok(data
[i
].tm
.tmHeight
== data
[i
+1].tm
.tmHeight
,
6855 "expected %d, got %d\n", data
[i
].tm
.tmHeight
, data
[i
+1].tm
.tmHeight
);
6856 ok(data
[i
].tm
.tmAscent
== data
[i
+1].tm
.tmAscent
,
6857 "expected %d, got %d\n", data
[i
].tm
.tmAscent
, data
[i
+1].tm
.tmAscent
);
6858 ok(data
[i
].tm
.tmDescent
== data
[i
+1].tm
.tmDescent
,
6859 "expected %d, got %d\n", data
[i
].tm
.tmDescent
, data
[i
+1].tm
.tmDescent
);
6860 ok(data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
== diff
,
6861 "expected %d, got %d\n", diff
, data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
);
6862 ok(data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
== diff
,
6863 "expected %d, got %d\n", diff
, data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
);
6864 ok(data
[i
].tm
.tmOverhang
== 0,
6865 "expected 0, got %d\n", data
[i
].tm
.tmOverhang
);
6866 ok(data
[i
+1].tm
.tmOverhang
== 1,
6867 "expected 1, got %d\n", data
[i
+1].tm
.tmOverhang
);
6868 ok(data
[i
].w
+ 1 == data
[i
+1].w
,
6869 "expected %d, got %d\n", data
[i
].w
+ 1, data
[i
+1].w
);
6873 static void test_bitmap_font_glyph_index(void)
6875 const WCHAR text
[] = L
"#!/bin/sh";
6879 } bitmap_font_list
[] = {
6880 { "Courier", ANSI_CHARSET
},
6881 { "Small Fonts", ANSI_CHARSET
},
6882 { "Fixedsys", DEFAULT_CHARSET
},
6883 { "System", DEFAULT_CHARSET
}
6888 CHAR facename
[LF_FACESIZE
];
6899 if (!pGetGlyphIndicesW
) {
6900 win_skip("GetGlyphIndices is unavailable\n");
6904 hdc
= CreateCompatibleDC(0);
6905 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6907 memset(&bmi
, 0, sizeof(bmi
));
6908 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
6909 bmi
.bmiHeader
.biBitCount
= 32;
6910 bmi
.bmiHeader
.biPlanes
= 1;
6911 bmi
.bmiHeader
.biWidth
= 128;
6912 bmi
.bmiHeader
.biHeight
= 32;
6913 bmi
.bmiHeader
.biCompression
= BI_RGB
;
6915 for (i
= 0; i
< ARRAY_SIZE(bitmap_font_list
); i
++) {
6916 memset(&lf
, 0, sizeof(lf
));
6917 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
6918 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
6919 hFont
= CreateFontIndirectA(&lf
);
6920 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
6921 hFont
= SelectObject(hdc
, hFont
);
6922 ret
= GetTextMetricsA(hdc
, &tm
);
6923 ok(ret
, "GetTextMetric failed\n");
6924 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
6925 ok(ret
, "GetTextFace failed\n");
6926 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
6927 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
6930 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
6931 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
6935 for (j
= 0; j
< 2; j
++) {
6937 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
6938 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
6939 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6942 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
6946 int len
= lstrlenW(text
);
6947 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
6948 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
6949 ok(ret
, "GetGlyphIndices failed\n");
6950 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
6951 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
6952 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
6953 HeapFree(GetProcessHeap(), 0, indices
);
6957 ok(ret
, "ExtTextOutW failed\n");
6958 SelectObject(hdc
, hBmpPrev
);
6961 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
6962 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6963 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6965 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
6967 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6970 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
6971 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
6975 for (j
= 0; j
< 2; j
++) {
6978 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6981 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6984 ret
= GetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6985 ok(ret
, "GetGlyphIndices failed\n");
6986 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6987 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6990 ok(ret
, "ExtTextOutA failed\n");
6991 SelectObject(hdc
, hBmpPrev
);
6994 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6995 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6997 for (j
= 0; j
< 2; j
++)
6998 DeleteObject(hBmp
[j
]);
6999 hFont
= SelectObject(hdc
, hFont
);
7000 DeleteObject(hFont
);
7006 static void test_GetCharWidthI(void)
7008 static const char *teststr
= "wine ";
7009 HFONT hfont
, prev_hfont
;
7019 memset(&lf
, 0, sizeof(lf
));
7020 strcpy(lf
.lfFaceName
, "Tahoma");
7025 hfont
= CreateFontIndirectA(&lf
);
7026 prev_hfont
= SelectObject(hdc
, hfont
);
7028 len
= strlen(teststr
);
7029 nb
= GetGlyphIndicesA(hdc
, teststr
, len
, glyphs
, 0);
7030 ok(nb
== len
, "\n");
7032 memset(abc
, 0xcc, sizeof(abc
));
7033 ret
= GetCharABCWidthsI(hdc
, 0, len
, glyphs
, abc
);
7034 ok(ret
, "GetCharABCWidthsI failed\n");
7036 memset(widths
, 0xcc, sizeof(widths
));
7037 ret
= GetCharWidthI(hdc
, 0, len
, glyphs
, widths
);
7038 ok(ret
, "GetCharWidthI failed\n");
7040 for (i
= 0; i
< len
; i
++)
7041 ok(widths
[i
] == abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
, "%u, glyph %u, got width %d\n",
7042 i
, glyphs
[i
], widths
[i
]);
7044 DeleteObject(SelectObject(hdc
, prev_hfont
));
7048 static INT CALLBACK
long_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lparam
)
7050 BOOL
*found_font
= (BOOL
*)lparam
;
7055 static void test_long_names(void)
7057 char ttf_name
[MAX_PATH
];
7058 LOGFONTA font
= {0};
7064 if (!write_ttf_file("wine_longname.ttf", ttf_name
))
7066 skip("Failed to create ttf file for testing\n");
7072 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7073 ok(ret
, "AddFontResourceEx() failed\n");
7075 strcpy(font
.lfFaceName
, "wine_3_this_is_a_very_long_name");
7077 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7078 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7080 strcpy(font
.lfFaceName
, "wine_2_this_is_a_very_long_name");
7082 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7083 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7085 strcpy(font
.lfFaceName
, "wine_1_this_is_a_very_long_name");
7087 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7088 ok(found_font
== FALSE
, "EnumFontFamiliesExA must not find font.\n");
7090 handle_font
= CreateFontIndirectA(&font
);
7091 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7092 DeleteObject(handle_font
);
7094 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7095 ok(ret
, "RemoveFontResourceEx() failed\n");
7097 DeleteFileA(ttf_name
);
7098 ReleaseDC(NULL
, dc
);
7101 static void test_ttf_names(void)
7103 struct enum_fullname_data efnd
;
7104 char ttf_name
[MAX_PATH
], ttf_name_bold
[MAX_PATH
];
7105 LOGFONTA font
= {0};
7110 if (!write_ttf_file("wine_ttfnames.ttf", ttf_name
))
7112 skip("Failed to create ttf file for testing\n");
7116 if (!write_ttf_file("wine_ttfnames_bold.ttf", ttf_name_bold
))
7118 skip("Failed to create ttf file for testing\n");
7119 DeleteFileA(ttf_name
);
7123 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7124 ok(ret
, "AddFontResourceEx() failed\n");
7126 ret
= AddFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7127 ok(ret
, "AddFontResourceEx() failed\n");
7131 strcpy(font
.lfFaceName
, "Wine_TTF_Names_Long_Family1_Con");
7132 memset(&efnd
, 0, sizeof(efnd
));
7133 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7134 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7136 /* Windows doesn't match with Typographic/Preferred Family tags */
7137 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1");
7138 memset(&efnd
, 0, sizeof(efnd
));
7139 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7140 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7142 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Ext");
7143 memset(&efnd
, 0, sizeof(efnd
));
7144 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7145 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7147 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Con");
7148 memset(&efnd
, 0, sizeof(efnd
));
7149 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7150 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7152 handle_font
= CreateFontIndirectA(&font
);
7153 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7154 DeleteObject(handle_font
);
7156 ret
= RemoveFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7157 ok(ret
, "RemoveFontResourceEx() failed\n");
7159 DeleteFileA(ttf_name_bold
);
7161 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7162 ok(ret
, "RemoveFontResourceEx() failed\n");
7164 DeleteFileA(ttf_name
);
7165 ReleaseDC(NULL
, dc
);
7168 static void test_lang_names(void)
7170 static const WCHAR name_cond_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja)";
7171 static const WCHAR name_cond_ja_reg_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg";
7172 static const WCHAR name_cond_ja_reg_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg (ja)";
7173 static const WCHAR name_wws_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d WWS (ja)";
7175 struct enum_fullname_data efnd
;
7176 struct enum_fullname_data_w efnd_w
;
7177 char ttf_name
[MAX_PATH
], ttf_name2
[MAX_PATH
], ttf_name3
[MAX_PATH
];
7178 LOGFONTA font
= {0};
7179 LOGFONTW font_w
= {0};
7182 const WCHAR
*primary_family
, *primary_fullname
;
7184 if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
&& PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE
)
7186 skip( "Primary language is neither English nor Japanese, skipping test\n" );
7190 if (!write_ttf_file( "wine_langnames.ttf", ttf_name
))
7192 skip( "Failed to create ttf file for testing\n" );
7196 if (!write_ttf_file( "wine_langnames2.ttf", ttf_name2
))
7198 skip( "Failed to create ttf file for testing\n" );
7199 DeleteFileA( ttf_name
);
7203 if (!write_ttf_file( "wine_langnames3.ttf", ttf_name3
))
7205 skip( "Failed to create ttf file for testing\n" );
7206 DeleteFileA( ttf_name2
);
7207 DeleteFileA( ttf_name
);
7211 ret
= AddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7212 ok( ret
, "AddFontResourceEx() failed\n" );
7216 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7218 primary_family
= L
"Wine Lang Cond (en)";
7219 primary_fullname
= L
"Wine Lang Cond Reg (en)";
7223 primary_family
= name_cond_ja_w
;
7224 primary_fullname
= name_cond_ja_reg_w
;
7227 for (i
= 0; i
< 3; ++i
)
7229 /* check that lookup by preferred or WWS family / full names or postscript FontName doesn't work */
7231 strcpy( font
.lfFaceName
, "Wine Lang (en)" );
7232 memset( &efnd
, 0, sizeof(efnd
) );
7233 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7234 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7236 strcpy( font
.lfFaceName
, "Wine Lang Condensed Bold (ko)" );
7237 memset( &efnd
, 0, sizeof(efnd
) );
7238 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7239 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7241 wcscpy( font_w
.lfFaceName
, name_wws_ja_w
);
7242 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7243 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7244 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7246 strcpy( font
.lfFaceName
, "Reg WWS (zh-tw)" );
7247 memset( &efnd
, 0, sizeof(efnd
) );
7248 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7249 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7251 strcpy( font
.lfFaceName
, "Wine Lang (en) Reg WWS (en)" );
7252 memset( &efnd
, 0, sizeof(efnd
) );
7253 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7254 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7256 strcpy( font
.lfFaceName
, "WineLangNamesRegular" );
7257 memset( &efnd
, 0, sizeof(efnd
) );
7258 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7259 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7261 /* then, the primary ttf family name always works */
7263 wcscpy( font_w
.lfFaceName
, primary_family
);
7264 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7265 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7266 ok( efnd_w
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7268 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7270 wcscpy( font_w
.lfFaceName
, name_cond_ja_w
);
7271 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7272 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7273 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7276 /* if there is no primary ttf family name, the english ttf name, or postscript FamilyName are used instead */
7278 strcpy( font
.lfFaceName
, "Wine_Lang_Names" );
7279 memset( &efnd
, 0, sizeof(efnd
) );
7280 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7282 ok( efnd
.total
== 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7284 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7286 /* same goes for ttf full names */
7288 wcscpy( font_w
.lfFaceName
, primary_fullname
);
7289 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7290 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7291 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7293 if (efnd_w
.total
>= 1)
7295 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
, primary_family
),
7296 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
) );
7297 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfFullName
, primary_fullname
),
7298 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfFullName
) );
7299 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
? L
"Reg (en)" : L
"Reg (ja)" ),
7300 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfStyle
) );
7303 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7305 wcscpy( font_w
.lfFaceName
, name_cond_ja_reg_w
);
7306 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7307 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7308 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7311 wcscpy( font_w
.lfFaceName
, L
"Wine_Lang_Names_Regular" );
7312 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7313 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7314 ok( efnd_w
.total
== i
, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7316 while (efnd_w
.total
--)
7318 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
, efnd_w
.total
== 1 ? L
"Wine_Lang_Names" : primary_family
),
7319 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
) );
7320 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
, L
"Wine_Lang_Names_Regular" ),
7321 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
) );
7322 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7323 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
, efnd_w
.total
== 1 ? L
"Regular" : L
"Reg (en)" ),
7324 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
) );
7326 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, L
"Reg (ja)" ),
7327 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfStyle
) );
7330 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7332 wcscpy( font_w
.lfFaceName
, name_cond_ja_reg_ja_w
);
7333 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7334 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7335 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7338 /* another language can also be used for lookup, if the primary langid isn't english, then
7339 english seems to have priority, otherwise or if english is already the primary langid,
7340 the family name with the smallest langid is used as secondary lookup language. */
7342 strcpy( font
.lfFaceName
, "Wine Lang Cond (zh-tw)" );
7343 memset( &efnd
, 0, sizeof(efnd
) );
7344 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7345 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7346 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7347 else /* (zh-tw) doesn't match here probably because there's an (en) name too */
7348 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7350 strcpy( font
.lfFaceName
, "Wine Lang Cond (en)" );
7351 memset( &efnd
, 0, sizeof(efnd
) );
7352 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7353 /* either because it's the primary language, or because it's a secondary */
7354 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7356 wcscpy( font_w
.lfFaceName
, L
"Wine Police d'\xe9" "criture (fr)" );
7357 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7358 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7359 /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */
7360 if (i
== 2) ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7361 else ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7363 /* case matching should not depend on the current locale */
7366 wcscpy( font_w
.lfFaceName
, L
"Wine POLICE D'\xc9" "CRITURE (fr)" );
7367 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7368 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7369 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7372 strcpy( font
.lfFaceName
, "Wine Lang Cond (ko)" );
7373 memset( &efnd
, 0, sizeof(efnd
) );
7374 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7375 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7377 /* that doesn't apply to full names */
7379 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (zh-tw)" );
7380 memset( &efnd
, 0, sizeof(efnd
) );
7381 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7382 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7384 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (fr)" );
7385 memset( &efnd
, 0, sizeof(efnd
) );
7386 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7387 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7391 ret
= AddFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7392 ok( ret
, "AddFontResourceEx() failed\n" );
7396 ret
= AddFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7397 ok( ret
, "AddFontResourceEx() failed\n" );
7401 ret
= RemoveFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7402 ok( ret
, "RemoveFontResourceEx() failed\n" );
7404 DeleteFileA( ttf_name3
);
7406 ret
= RemoveFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7407 ok( ret
, "RemoveFontResourceEx() failed\n" );
7409 DeleteFileA( ttf_name2
);
7411 ret
= RemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7412 ok( ret
, "RemoveFontResourceEx() failed\n" );
7414 DeleteFileA( ttf_name
);
7415 ReleaseDC( NULL
, dc
);
7420 USHORT majorVersion
;
7421 USHORT minorVersion
;
7425 USHORT advanceWidthMax
;
7426 SHORT minLeftSideBearing
;
7427 SHORT minRightSideBearing
;
7429 SHORT caretSlopeRise
;
7430 SHORT caretSlopeRun
;
7433 SHORT metricDataFormat
;
7434 SHORT numberOfHMetrics
;
7437 static void test_GetCharWidthInfo(void)
7440 HFONT hfont
, hfont_prev
;
7444 OUTLINETEXTMETRICA otm
;
7445 TT_Hori_Header hhea
;
7446 struct char_width_info
7450 SHORT minLeftSideBearing
, minRightSideBearing
;
7452 const char* face_list
[] = { "Symbol", "Ume Gothic", "MS Gothic" };
7454 if (!pGetCharWidthInfo
)
7456 win_skip("GetCharWidthInfo is unavailable\n");
7462 /* test default (System) font */
7463 memset(&info
, 0xaa, sizeof(info
));
7464 r
= pGetCharWidthInfo(hdc
, &info
);
7465 if (r
) /* win10 1803 succeeds */
7467 ok(info
.lsb
== 0, "expected 0, got %d\n", info
.lsb
);
7468 ok(info
.rsb
== 0, "expected 0, got %d\n", info
.rsb
);
7469 ok(info
.unk
== 0, "expected 0, got %d\n", info
.unk
);
7472 memset(&lf
, 0, sizeof(lf
));
7473 lf
.lfWeight
= FW_NORMAL
;
7474 lf
.lfCharSet
= ANSI_CHARSET
;
7475 strcpy(lf
.lfFaceName
, "Tahoma");
7476 hfont
= CreateFontIndirectA(&lf
);
7477 hfont_prev
= SelectObject(hdc
, hfont
);
7478 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7480 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
7481 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
7482 DeleteObject(SelectObject(hdc
, hfont_prev
));
7484 /* test Tahoma at the em square size */
7485 lf
.lfHeight
= -(int)otm
.otmEMSquare
;
7486 hfont
= CreateFontIndirectA(&lf
);
7487 hfont_prev
= SelectObject(hdc
, hfont
);
7488 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7490 ret
= GetFontData(hdc
, MS_MAKE_TAG('h','h','e','a'), 0, &hhea
, sizeof(hhea
));
7491 ok(ret
== sizeof(hhea
), "got %u\n", ret
);
7492 minLeftSideBearing
= GET_BE_WORD(hhea
.minLeftSideBearing
);
7493 minRightSideBearing
= GET_BE_WORD(hhea
.minRightSideBearing
);
7495 memset(&info
, 0xaa, sizeof(info
));
7496 r
= pGetCharWidthInfo(hdc
, &info
);
7497 ok(r
, "GetCharWidthInfo failed\n");
7498 ok(info
.lsb
== minLeftSideBearing
, "expected %d, got %d\n", minLeftSideBearing
, info
.lsb
);
7499 ok(info
.rsb
== minRightSideBearing
, "expected %d, got %d\n", minRightSideBearing
, info
.rsb
);
7501 DeleteObject(SelectObject(hdc
, hfont_prev
));
7503 /* these values are scaled, try with smaller size */
7505 hfont
= CreateFontIndirectA(&lf
);
7506 hfont_prev
= SelectObject(hdc
, hfont
);
7507 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7509 memset(&info2
, 0xaa, sizeof(info2
));
7510 r
= pGetCharWidthInfo(hdc
, &info2
);
7511 ok(r
, "pGetCharWidthInfo failed\n");
7512 ok(info2
.lsb
== info
.lsb
/3, "expected %d, got %d\n", info
.lsb
/3, info2
.lsb
);
7513 ok(info2
.rsb
== info
.rsb
/3, "expected %d, got %d\n", info
.rsb
/3, info2
.rsb
);
7515 DeleteObject(SelectObject(hdc
, hfont_prev
));
7516 ReleaseDC(NULL
, hdc
);
7518 /* test with another mapping mode */
7520 SetMapMode(hdc
, MM_ISOTROPIC
);
7521 SetWindowExtEx(hdc
, 2, 2, NULL
);
7522 SetViewportExtEx(hdc
, 1, 1, NULL
);
7524 memset(pt
, 0, sizeof(pt
));
7525 pt
[0].y
= otm
.otmEMSquare
;
7528 memset(&lf
, 0, sizeof(lf
));
7529 lf
.lfWeight
= FW_NORMAL
;
7530 lf
.lfCharSet
= ANSI_CHARSET
;
7531 lf
.lfHeight
= -abs(pt
[0].y
);
7532 strcpy(lf
.lfFaceName
, "Tahoma");
7533 hfont
= CreateFontIndirectA(&lf
);
7534 hfont_prev
= SelectObject(hdc
, hfont
);
7535 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7537 memset(&info2
, 0xaa, sizeof(info2
));
7538 r
= pGetCharWidthInfo(hdc
, &info2
);
7539 ok(r
, "GetCharWidthInfo failed\n");
7540 pt
[0].x
= info
.lsb
; pt
[0].y
= 0;
7541 pt
[1].x
= info
.rsb
; pt
[1].y
= 0;
7543 ok(pt
[0].x
== info2
.lsb
, "expected %d, got %d\n", pt
[0].x
, info2
.lsb
);
7544 ok(pt
[1].x
== info2
.rsb
, "expected %d, got %d\n", pt
[1].x
, info2
.rsb
);
7546 DeleteObject(SelectObject(hdc
, hfont_prev
));
7547 ReleaseDC(NULL
, hdc
);
7549 /* test with synthetic fonts */
7551 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++)
7553 const char* face
= face_list
[i
];
7554 if (!is_truetype_font_installed(face
))
7556 skip("%s is not installed\n", face
);
7559 memset(&lf
, 0, sizeof(lf
));
7560 lf
.lfWeight
= FW_NORMAL
;
7561 lf
.lfItalic
= FALSE
;
7562 lf
.lfCharSet
= DEFAULT_CHARSET
;
7564 strcpy(lf
.lfFaceName
, face
);
7565 hfont
= CreateFontIndirectA(&lf
);
7566 hfont_prev
= SelectObject(hdc
, hfont
);
7568 memset(&info
, 0xaa, sizeof(info
));
7569 r
= pGetCharWidthInfo(hdc
, &info
);
7570 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7572 /* test with synthetic bold */
7573 lf
.lfWeight
= FW_BOLD
;
7574 lf
.lfItalic
= FALSE
;
7575 hfont
= CreateFontIndirectA(&lf
);
7576 DeleteObject(SelectObject(hdc
, hfont
));
7578 memset(&info2
, 0xaa, sizeof(info2
));
7579 r
= pGetCharWidthInfo(hdc
, &info2
);
7580 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7581 ok(info
.lsb
== info2
.lsb
, "%s: expected %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7582 ok(info
.rsb
== info2
.rsb
, "%s: expected %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7584 /* test with synthetic italic */
7585 lf
.lfWeight
= FW_NORMAL
;
7587 hfont
= CreateFontIndirectA(&lf
);
7588 DeleteObject(SelectObject(hdc
, hfont
));
7590 memset(&info2
, 0xaa, sizeof(info2
));
7591 r
= pGetCharWidthInfo(hdc
, &info2
);
7592 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7593 todo_wine
ok(info
.lsb
> info2
.lsb
, "%s: expected less than %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7594 todo_wine
ok(info
.rsb
> info2
.rsb
, "%s: expected less than %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7595 DeleteObject(SelectObject(hdc
, hfont_prev
));
7598 ReleaseDC(NULL
, hdc
);
7601 static int CALLBACK
get_char_width_proc(const LOGFONTA
*lf
,
7602 const TEXTMETRICA
*tm
, DWORD type
, LPARAM ctx
)
7604 HFONT font
= CreateFontIndirectA(lf
);
7605 HDC dc
= GetDC(NULL
);
7613 SelectObject(dc
, font
);
7615 ret
= GetCharWidthFloatA(dc
, c
, c
, &f
);
7616 ok(ret
, "%s: GetCharWidthFloat() failed\n", lf
->lfFaceName
);
7617 ret
= GetCharWidth32A(dc
, c
, c
, &i32
);
7618 ok(ret
, "%s: GetCharWidth32A() failed\n", lf
->lfFaceName
);
7619 ret
= GetCharWidthA(dc
, c
, c
, &i
);
7620 ok(ret
, "%s: GetCharWidthA() failed\n", lf
->lfFaceName
);
7621 ok(i
== i32
, "%s: mismatched widths %d/%d\n", lf
->lfFaceName
, i
, i32
);
7622 ok((float)i
/ 16.0f
== f
, "%s: mismatched widths %d/%.8e\n", lf
->lfFaceName
, i
, f
);
7624 ret
= GetCharABCWidthsFloatA(dc
, c
, c
, &abcf
);
7625 ok(ret
, "%s: GetCharABCWidths() failed\n", lf
->lfFaceName
);
7626 if (GetCharABCWidthsA(dc
, c
, c
, &abc
))
7627 ok((float)abc
.abcB
== abcf
.abcfB
, "%s: mismatched widths %d/%.8e\n",
7628 lf
->lfFaceName
, abc
.abcB
, abcf
.abcfB
);
7630 ReleaseDC(NULL
, dc
);
7635 static void test_char_width(void)
7637 HDC dc
= GetDC(NULL
);
7640 lf
.lfCharSet
= DEFAULT_CHARSET
;
7641 EnumFontFamiliesExA(dc
, &lf
, get_char_width_proc
, 0, 0);
7643 ReleaseDC(NULL
, dc
);
7646 static void test_GetCharacterPlacement_kerning(void)
7649 HFONT hfont
, hfont_old
;
7652 DWORD count
, ret
, i
, size
, width
, width_kern
, idx
;
7654 GCP_RESULTSW result
;
7655 int kern
[30], pos
[30], pos_kern
[30], dx
[30], dx_kern
[30], kern_amount
;
7657 if (!is_font_installed("Arial"))
7659 skip("Arial is not installed, skipping the test\n");
7665 memset(&lf
, 0, sizeof(lf
));
7666 strcpy(lf
.lfFaceName
, "Arial");
7668 hfont
= CreateFontIndirectA(&lf
);
7669 ok(hfont
!= NULL
, "CreateFontIndirect failed\n");
7671 hfont_old
= SelectObject(hdc
, hfont
);
7673 count
= GetKerningPairsW(hdc
, 0, NULL
);
7674 kp
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*kp
));
7676 ret
= GetKerningPairsW(hdc
, count
, kp
);
7677 ok(ret
== count
, "got %u, expected %u\n", ret
, count
);
7679 size
= kern_amount
= idx
= 0;
7680 for (i
= 0; i
< count
; i
++)
7682 if (kp
[i
].wFirst
>= 'A' && kp
[i
].wFirst
<= 'z' &&
7683 kp
[i
].wSecond
>= 'A' && kp
[i
].wSecond
<= 'z')
7685 str
[size
++] = kp
[i
].wFirst
;
7686 str
[size
++] = kp
[i
].wSecond
;
7688 kern
[idx
] = kp
[i
].iKernAmount
;
7690 kern_amount
+= kp
[i
].iKernAmount
;
7691 if (size
>= ARRAY_SIZE(str
)) break;
7695 HeapFree(GetProcessHeap(), 0, kp
);
7699 memset(&result
, 0, sizeof(result
));
7700 result
.lStructSize
= sizeof(result
);
7701 result
.lpCaretPos
= pos
;
7703 result
.nGlyphs
= count
;
7704 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, 0);
7705 ok(ret
, "GetCharacterPlacement failed\n");
7706 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7707 width
= LOWORD(ret
);
7709 memset(&result
, 0, sizeof(result
));
7710 result
.lStructSize
= sizeof(result
);
7711 result
.lpCaretPos
= pos_kern
;
7712 result
.lpDx
= dx_kern
;
7713 result
.nGlyphs
= count
;
7714 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, GCP_USEKERNING
);
7715 ok(ret
, "GetCharacterPlacement failed\n");
7716 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7717 width_kern
= LOWORD(ret
);
7719 if (width
== width_kern
)
7721 win_skip("GCP_USEKERNING is broken on this platform\n");
7725 ok(width
+ kern_amount
== width_kern
, "%d + %d != %d\n", width
, kern_amount
, width_kern
);
7727 kern_amount
= idx
= 0;
7728 for (i
= 0; i
< count
; i
+= 3, idx
++)
7730 ok(pos
[i
] + kern_amount
== pos_kern
[i
], "%d: %d + %d != %d\n", i
, pos
[i
], kern_amount
, pos_kern
[i
]);
7731 kern_amount
+= kern
[idx
];
7732 ok(pos
[i
+1] + kern_amount
== pos_kern
[i
+1], "%d: %d + %d != %d\n", i
, pos
[i
+1], kern_amount
, pos_kern
[i
+1]);
7733 ok(pos
[i
+2] + kern_amount
== pos_kern
[i
+2], "%d: %d + %d != %d\n", i
, pos
[i
+2], kern_amount
, pos_kern
[i
+2]);
7735 ok(dx
[i
] + kern
[idx
] == dx_kern
[i
], "%d: %d + %d != %d\n", i
, dx
[i
], kern
[idx
], dx_kern
[i
]);
7736 ok(dx
[i
+1] == dx_kern
[i
+1], "%d: %d != %d\n", i
, dx
[i
+1], dx_kern
[i
+1]);
7737 ok(dx
[i
+2] == dx_kern
[i
+2], "%d: %d != %d\n", i
, dx
[i
+2], dx_kern
[i
+2]);
7741 SelectObject(hdc
, hfont_old
);
7742 DeleteObject(hfont
);
7746 static void test_select_object(void)
7748 HFONT hfont
, old_font
;
7751 memset(&lf
, 0, sizeof lf
);
7753 lf
.lfCharSet
= ANSI_CHARSET
;
7754 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
7755 lf
.lfWeight
= FW_DONTCARE
;
7758 lf
.lfQuality
= DEFAULT_QUALITY
;
7760 lstrcpyA(lf
.lfFaceName
, "Arial");
7761 hfont
= create_font("Arial", &lf
);
7763 SetLastError(0xdeadbeef);
7764 old_font
= SelectObject(NULL
, hfont
);
7765 ok(!old_font
, "SelectObject returned %p\n", old_font
);
7766 ok(GetLastError() == ERROR_INVALID_HANDLE
, "GetLastError() = %u\n",
7769 DeleteObject(hfont
);
7774 static const char *test_names
[] =
7776 "AddFontMemResource",
7778 char path_name
[MAX_PATH
];
7779 STARTUPINFOA startup
;
7785 argc
= winetest_get_mainargs(&argv
);
7788 if (!strcmp(argv
[2], "AddFontMemResource"))
7789 test_AddFontMemResource();
7796 test_outline_font();
7797 test_bitmap_font_metrics();
7798 test_GdiGetCharDimensions();
7799 test_GetCharABCWidths();
7800 test_text_extents();
7801 test_GetGlyphIndices();
7802 test_GetKerningPairs();
7803 test_GetOutlineTextMetrics();
7804 test_SetTextJustification();
7805 test_font_charset();
7806 test_GdiGetCodePage();
7807 test_GetFontUnicodeRanges();
7808 test_nonexistent_font();
7810 test_height_selection();
7812 test_EnumFonts_subst();
7814 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
7815 * I'd like to avoid them in this test.
7817 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
7818 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
7819 if (is_truetype_font_installed("Arial Black") &&
7820 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
7822 test_EnumFontFamilies("", ANSI_CHARSET
);
7823 test_EnumFontFamilies("", SYMBOL_CHARSET
);
7824 test_EnumFontFamilies("", DEFAULT_CHARSET
);
7827 skip("Arial Black or Symbol/Wingdings is not installed\n");
7828 test_EnumFontFamiliesEx_default_charset();
7829 test_GetTextMetrics();
7830 test_RealizationInfo();
7832 test_GetGlyphOutline();
7833 test_GetTextMetrics2("Tahoma", -11);
7834 test_GetTextMetrics2("Tahoma", -55);
7835 test_GetTextMetrics2("Tahoma", -110);
7836 test_GetTextMetrics2("Arial", -11);
7837 test_GetTextMetrics2("Arial", -55);
7838 test_GetTextMetrics2("Arial", -110);
7839 test_GetCharacterPlacement();
7840 test_GetCharacterPlacement_kerning();
7841 test_GetCharWidthInfo();
7842 test_CreateFontIndirect();
7843 test_CreateFontIndirectEx();
7847 test_east_asian_font_selection();
7849 test_vertical_order();
7850 test_GetCharWidth32();
7851 test_fake_bold_font();
7852 test_bitmap_font_glyph_index();
7853 test_GetCharWidthI();
7858 test_select_object();
7860 /* These tests should be last test until RemoveFontResource
7861 * is properly implemented.
7863 test_vertical_font();
7864 test_CreateScalableFontResource();
7866 winetest_get_mainargs( &argv
);
7867 for (i
= 0; i
< ARRAY_SIZE(test_names
); ++i
)
7869 PROCESS_INFORMATION info
;
7871 memset(&startup
, 0, sizeof(startup
));
7872 startup
.cb
= sizeof(startup
);
7873 sprintf(path_name
, "%s font %s", argv
[0], test_names
[i
]);
7874 ok(CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
),
7875 "CreateProcess failed.\n");
7876 wait_child_process(info
.hProcess
);
7877 CloseHandle(info
.hProcess
);
7878 CloseHandle(info
.hThread
);