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(HDC hdc
, HFONT hfont
, LONG lfHeight
,
303 LONG lfWidth
, const char *test_str
,
304 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
305 const SIZE
*size_orig
, INT width_of_A_orig
,
306 INT scale_x
, INT scale_y
)
309 OUTLINETEXTMETRICA otm
;
312 INT width_of_A
, cx
, cy
;
318 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
320 GetObjectA(hfont
, sizeof(lf
), &lf
);
322 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
324 otm
.otmSize
= sizeof(otm
) / 2;
325 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
326 ok(ret
== sizeof(otm
)/2 /* XP */ ||
327 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
329 memset(&otm
, 0x1, sizeof(otm
));
330 otm
.otmSize
= sizeof(otm
);
331 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
332 ok(ret
== sizeof(otm
) /* XP */ ||
333 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
335 memset(&tm
, 0x2, sizeof(tm
));
336 ret
= GetTextMetricsA(hdc
, &tm
);
337 ok(ret
, "GetTextMetricsA failed\n");
338 /* the structure size is aligned */
339 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
341 ok(0, "tm != otm\n");
342 compare_tm(&tm
, &otm
.otmTextMetrics
);
345 tm
= otm
.otmTextMetrics
;
346 if (0) /* these metrics are scaled too, but with rounding errors */
348 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
349 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
351 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
352 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
353 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
354 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
355 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
356 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
360 ret
= GetTextMetricsA(hdc
, &tm
);
361 ok(ret
, "GetTextMetricsA failed\n");
364 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
365 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
366 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
367 lfHeight
, scale_x
, scale_y
, cx
, cy
);
368 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
369 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
370 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
371 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
372 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
374 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
378 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
381 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
383 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
385 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
386 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
388 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
390 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
);
393 /* Test how GDI scales bitmap font metrics */
394 static void test_bitmap_font(void)
396 static const char test_str
[11] = "Test String";
399 HFONT hfont
, old_hfont
;
402 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
404 hdc
= CreateCompatibleDC(0);
406 /* "System" has only 1 pixel size defined, otherwise the test breaks */
407 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
411 skip("no bitmap fonts were found, skipping the test\n");
415 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
417 height_orig
= bitmap_lf
.lfHeight
;
418 lfWidth
= bitmap_lf
.lfWidth
;
420 hfont
= create_font("bitmap", &bitmap_lf
);
421 old_hfont
= SelectObject(hdc
, hfont
);
422 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
423 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
424 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
425 SelectObject(hdc
, old_hfont
);
428 bitmap_lf
.lfHeight
= 0;
429 bitmap_lf
.lfWidth
= 4;
430 hfont
= create_font("bitmap", &bitmap_lf
);
431 old_hfont
= SelectObject(hdc
, hfont
);
432 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
433 SelectObject(hdc
, old_hfont
);
436 bitmap_lf
.lfHeight
= height_orig
;
437 bitmap_lf
.lfWidth
= lfWidth
;
439 /* test fractional scaling */
440 for (i
= 1; i
<= height_orig
* 6; i
++)
444 bitmap_lf
.lfHeight
= i
;
445 hfont
= create_font("fractional", &bitmap_lf
);
446 scale
= (i
+ height_orig
- 1) / height_orig
;
447 nearest_height
= scale
* height_orig
;
448 /* Only jump to the next height if the difference <= 25% original height */
449 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
450 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
451 so we'll not test this particular height. */
452 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
453 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
454 old_hfont
= SelectObject(hdc
, hfont
);
455 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
456 SelectObject(hdc
, old_hfont
);
460 /* test integer scaling 3x2 */
461 bitmap_lf
.lfHeight
= height_orig
* 2;
462 bitmap_lf
.lfWidth
*= 3;
463 hfont
= create_font("3x2", &bitmap_lf
);
464 old_hfont
= SelectObject(hdc
, hfont
);
465 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
466 SelectObject(hdc
, old_hfont
);
469 /* test integer scaling 3x3 */
470 bitmap_lf
.lfHeight
= height_orig
* 3;
471 bitmap_lf
.lfWidth
= 0;
472 hfont
= create_font("3x3", &bitmap_lf
);
473 old_hfont
= SelectObject(hdc
, hfont
);
474 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
475 SelectObject(hdc
, old_hfont
);
481 /* Test how GDI scales outline font metrics */
482 static void test_outline_font(void)
484 static const char test_str
[11] = "Test String";
487 HFONT hfont
, old_hfont
, old_hfont_2
;
488 OUTLINETEXTMETRICA otm
;
490 INT width_orig
, height_orig
, lfWidth
;
493 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
497 if (!is_truetype_font_installed("Arial"))
499 skip("Arial is not installed\n");
503 hdc
= CreateCompatibleDC(0);
505 memset(&lf
, 0, sizeof(lf
));
506 strcpy(lf
.lfFaceName
, "Arial");
508 hfont
= create_font("outline", &lf
);
509 old_hfont
= SelectObject(hdc
, hfont
);
510 otm
.otmSize
= sizeof(otm
);
511 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
512 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
513 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
515 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
516 SelectObject(hdc
, old_hfont
);
519 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
520 lf
.lfHeight
= otm
.otmEMSquare
;
521 lf
.lfHeight
= -lf
.lfHeight
;
522 hfont
= create_font("outline", &lf
);
523 old_hfont
= SelectObject(hdc
, hfont
);
524 otm
.otmSize
= sizeof(otm
);
525 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
526 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
527 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
528 SelectObject(hdc
, old_hfont
);
531 height_orig
= otm
.otmTextMetrics
.tmHeight
;
532 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
534 /* test integer scaling 3x2 */
535 lf
.lfHeight
= height_orig
* 2;
536 lf
.lfWidth
= lfWidth
* 3;
537 hfont
= create_font("3x2", &lf
);
538 old_hfont
= SelectObject(hdc
, hfont
);
539 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
540 SelectObject(hdc
, old_hfont
);
543 /* test integer scaling 3x3 */
544 lf
.lfHeight
= height_orig
* 3;
545 lf
.lfWidth
= lfWidth
* 3;
546 hfont
= create_font("3x3", &lf
);
547 old_hfont
= SelectObject(hdc
, hfont
);
548 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
549 SelectObject(hdc
, old_hfont
);
552 /* test integer scaling 1x1 */
553 lf
.lfHeight
= height_orig
* 1;
554 lf
.lfWidth
= lfWidth
* 1;
555 hfont
= create_font("1x1", &lf
);
556 old_hfont
= SelectObject(hdc
, hfont
);
557 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
558 SelectObject(hdc
, old_hfont
);
561 /* test integer scaling 1x1 */
562 lf
.lfHeight
= height_orig
;
564 hfont
= create_font("1x1", &lf
);
565 old_hfont
= SelectObject(hdc
, hfont
);
566 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
568 /* with an identity matrix */
569 memset(&gm
, 0, sizeof(gm
));
570 SetLastError(0xdeadbeef);
571 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
572 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
573 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
574 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
575 /* with a custom matrix */
576 memset(&gm
, 0, sizeof(gm
));
577 SetLastError(0xdeadbeef);
578 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
579 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
580 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
581 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
583 /* Test that changing the DC transformation affects only the font
584 * selected on this DC and doesn't affect the same font selected on
587 hdc_2
= CreateCompatibleDC(0);
588 old_hfont_2
= SelectObject(hdc_2
, hfont
);
589 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
591 SetMapMode(hdc
, MM_ANISOTROPIC
);
593 /* font metrics on another DC should be unchanged */
594 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
596 /* test restrictions of compatibility mode GM_COMPATIBLE */
597 /* part 1: rescaling only X should not change font scaling on screen.
598 So compressing the X axis by 2 is not done, and this
599 appears as X scaling of 2 that no one requested. */
600 SetWindowExtEx(hdc
, 100, 100, NULL
);
601 SetViewportExtEx(hdc
, 50, 100, NULL
);
602 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
603 /* font metrics on another DC should be unchanged */
604 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
606 /* part 2: rescaling only Y should change font scaling.
607 As also X is scaled by a factor of 2, but this is not
608 requested by the DC transformation, we get a scaling factor
609 of 2 in the X coordinate. */
610 SetViewportExtEx(hdc
, 100, 200, NULL
);
611 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
615 /* restore scaling */
616 SetMapMode(hdc
, MM_TEXT
);
618 /* font metrics on another DC should be unchanged */
619 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
621 SelectObject(hdc_2
, old_hfont_2
);
624 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
626 SelectObject(hdc
, old_hfont
);
629 skip("GM_ADVANCED is not supported on this platform\n");
640 SetLastError(0xdeadbeef);
641 ret
= SetWorldTransform(hdc
, &xform
);
642 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
644 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
646 /* with an identity matrix */
647 memset(&gm
, 0, sizeof(gm
));
648 SetLastError(0xdeadbeef);
649 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
650 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
651 pt
.x
= width_orig
; pt
.y
= 0;
653 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
654 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
655 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
656 /* with a custom matrix */
657 memset(&gm
, 0, sizeof(gm
));
658 SetLastError(0xdeadbeef);
659 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
660 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
661 pt
.x
= width_orig
; pt
.y
= 0;
663 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
664 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
665 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
667 SetLastError(0xdeadbeef);
668 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
669 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
671 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
673 /* with an identity matrix */
674 memset(&gm
, 0, sizeof(gm
));
675 SetLastError(0xdeadbeef);
676 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
677 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
678 pt
.x
= width_orig
; pt
.y
= 0;
680 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
681 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
682 /* with a custom matrix */
683 memset(&gm
, 0, sizeof(gm
));
684 SetLastError(0xdeadbeef);
685 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
686 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
687 pt
.x
= width_orig
; pt
.y
= 0;
689 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
690 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
692 SetLastError(0xdeadbeef);
693 ret
= SetMapMode(hdc
, MM_TEXT
);
694 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
696 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
698 /* with an identity matrix */
699 memset(&gm
, 0, sizeof(gm
));
700 SetLastError(0xdeadbeef);
701 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
702 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
703 pt
.x
= width_orig
; pt
.y
= 0;
705 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
706 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
707 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
708 /* with a custom matrix */
709 memset(&gm
, 0, sizeof(gm
));
710 SetLastError(0xdeadbeef);
711 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
712 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
713 pt
.x
= width_orig
; pt
.y
= 0;
715 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
716 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
717 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
719 SelectObject(hdc
, old_hfont
);
724 static INT CALLBACK
find_font_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
726 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
728 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
731 return 0; /* stop enumeration */
733 return 1; /* continue enumeration */
736 static BOOL
is_CJK(void)
738 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
741 #define FH_SCALE 0x80000000
742 static void test_bitmap_font_metrics(void)
744 static const WORD skip_rtl
[] = {LANG_ARABIC
, LANG_HEBREW
, 0};
745 static const struct font_data
747 const char face_name
[LF_FACESIZE
];
748 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
749 int ave_char_width
, max_char_width
, dpi
;
750 BYTE first_char
, last_char
, def_char
, break_char
;
752 const WORD
*skip_lang_id
;
756 { "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 },
757 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
758 { "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 },
759 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
760 { "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 },
761 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
762 { "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 },
763 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
764 { "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 },
765 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
767 { "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 },
768 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
769 { "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 },
770 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
771 { "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 },
772 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
773 { "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 },
774 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
775 { "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 },
776 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
778 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
779 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
780 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
781 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
782 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
783 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
784 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
785 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
786 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
787 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
788 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
789 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
790 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
791 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
792 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
793 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
795 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
796 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
797 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
798 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
799 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
800 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
801 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
802 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
803 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
804 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
805 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
806 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
808 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
809 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
810 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
811 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
812 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
813 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
814 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
815 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
816 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
817 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
818 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
819 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
820 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
821 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
822 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
823 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
824 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
826 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
827 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
828 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
829 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
830 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
831 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
832 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
833 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
834 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
835 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
836 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
838 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
839 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
840 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
842 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
843 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
844 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
846 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
847 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
848 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
850 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
851 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
853 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
854 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
855 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
856 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
857 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
858 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
859 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
860 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
861 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
862 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
863 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
864 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
865 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
866 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
867 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
},
868 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
869 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
870 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
871 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, skip_rtl
},
872 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
873 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
875 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
876 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
877 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
878 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
879 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
880 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
881 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
882 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
883 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
884 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
885 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
886 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
888 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
889 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
890 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
892 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
894 /* FIXME: add "Terminal" */
896 static const int font_log_pixels
[] = { 96, 120 };
899 HFONT hfont
, old_hfont
;
901 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
902 char face_name
[LF_FACESIZE
];
905 trace("system language id %04x\n", system_lang_id
);
907 expected_cs
= GetACP();
908 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
910 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
913 expected_cs
= csi
.ciCharset
;
914 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
916 hdc
= CreateCompatibleDC(0);
917 ok(hdc
!= NULL
, "failed to create hdc\n");
919 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
920 GetDeviceCaps(hdc
, LOGPIXELSY
));
922 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
925 for (i
= 0; i
< ARRAY_SIZE(font_log_pixels
); i
++)
927 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
931 font_res
= font_log_pixels
[i
];
934 trace("best font resolution is %d\n", font_res
);
936 for (i
= 0; i
< ARRAY_SIZE(fd
); i
++)
940 memset(&lf
, 0, sizeof(lf
));
942 height
= fd
[i
].height
& ~FH_SCALE
;
943 lf
.lfHeight
= height
;
944 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
946 for(bit
= 0; bit
< 32; bit
++)
954 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
955 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
957 lf
.lfCharSet
= csi
.ciCharset
;
958 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
959 if (fd
[i
].height
& FH_SCALE
)
960 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
963 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
965 todo_wine_if (ret
) /* FIXME: Remove once Wine is fixed */
966 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
969 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
972 hfont
= create_font(lf
.lfFaceName
, &lf
);
973 old_hfont
= SelectObject(hdc
, hfont
);
975 SetLastError(0xdeadbeef);
976 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
977 ok(ret
, "GetTextFace error %u\n", GetLastError());
979 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
981 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
982 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
983 SelectObject(hdc
, old_hfont
);
988 memset(&gm
, 0, sizeof(gm
));
989 SetLastError(0xdeadbeef);
990 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
992 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
993 ret
= GetLastError();
994 ok(ret
== ERROR_CAN_NOT_COMPLETE
|| ret
== 0xdeadbeef /* Win10 */, "Unexpected error %d.\n", ret
);
996 bRet
= GetTextMetricsA(hdc
, &tm
);
997 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
999 SetLastError(0xdeadbeef);
1000 ret
= GetTextCharset(hdc
);
1001 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1002 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1004 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1006 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1009 if (fd
[i
].skip_lang_id
)
1013 while(!skipme
&& fd
[i
].skip_lang_id
[si
])
1014 if (fd
[i
].skip_lang_id
[si
++] == system_lang_id
)
1019 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1020 if (fd
[i
].height
& FH_SCALE
)
1021 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
);
1023 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
);
1024 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1025 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1026 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
);
1027 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
);
1028 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
);
1029 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1030 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1031 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1032 make default char test fail */
1033 if (tm
.tmCharSet
== lf
.lfCharSet
)
1034 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1035 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1036 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
);
1038 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1039 that make the max width bigger */
1040 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1041 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
);
1044 skip("Skipping font metrics test for system langid 0x%x\n",
1047 SelectObject(hdc
, old_hfont
);
1048 DeleteObject(hfont
);
1055 static void test_GdiGetCharDimensions(void)
1061 LONG avgwidth
, height
;
1062 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1064 if (!pGdiGetCharDimensions
)
1066 win_skip("GdiGetCharDimensions not available on this platform\n");
1070 hdc
= CreateCompatibleDC(NULL
);
1072 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1073 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1075 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1076 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1077 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1079 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1080 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1082 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1083 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1086 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1087 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1088 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1093 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1094 const TEXTMETRICA
*lpntme
,
1095 DWORD FontType
, LPARAM lParam
)
1097 if (FontType
& TRUETYPE_FONTTYPE
)
1101 hfont
= CreateFontIndirectA(lpelfe
);
1104 *(HFONT
*)lParam
= hfont
;
1112 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, const ABC
*base_abci
, const ABC
*base_abcw
, const ABCFLOAT
*base_abcf
)
1118 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1119 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1120 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1121 ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1122 ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1124 ret
= GetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1125 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1126 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1127 ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1128 ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1130 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1131 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1132 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1133 ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1134 ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1137 static void test_GetCharABCWidths(void)
1162 {0xffffff, 0xffffff},
1163 {0x1000000, 0x1000000},
1164 {0xffffff, 0x1000000},
1165 {0xffffffff, 0xffffffff},
1173 BOOL r
[ARRAY_SIZE(range
)];
1176 {ANSI_CHARSET
, 0x30, 0x30,
1177 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1178 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1179 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1180 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1181 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1182 {GB2312_CHARSET
, 0x8141, 0x4e04,
1183 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1184 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1185 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1189 if (!pGetCharABCWidthsFloatW
)
1191 win_skip("GetCharABCWidthsFloatW is not available on this platform\n");
1195 memset(&lf
, 0, sizeof(lf
));
1196 strcpy(lf
.lfFaceName
, "System");
1199 hfont
= CreateFontIndirectA(&lf
);
1201 hfont
= SelectObject(hdc
, hfont
);
1203 nb
= pGetGlyphIndicesW(hdc
, L
"i", 1, glyphs
, 0);
1204 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1206 ret
= GetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1207 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1209 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1210 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1212 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1213 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1215 ret
= GetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1216 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1218 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1219 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1221 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1222 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1224 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1225 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1227 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1228 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1230 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1231 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1233 hfont
= SelectObject(hdc
, hfont
);
1234 DeleteObject(hfont
);
1236 for (i
= 0; i
< ARRAY_SIZE(c
); ++i
)
1240 UINT code
= 0x41, j
;
1242 lf
.lfFaceName
[0] = '\0';
1243 lf
.lfCharSet
= c
[i
].cs
;
1244 lf
.lfPitchAndFamily
= 0;
1245 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1247 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1251 memset(a
, 0, sizeof a
);
1252 memset(w
, 0, sizeof w
);
1253 hfont
= SelectObject(hdc
, hfont
);
1254 ok(GetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) && GetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
)
1255 && !memcmp(a
, w
, sizeof(a
)),
1256 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1258 memset(a
, 0xbb, sizeof a
);
1259 ret
= GetCharABCWidthsA(hdc
, code
, code
, a
);
1260 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1261 memset(full
, 0xcc, sizeof full
);
1262 ret
= GetCharABCWidthsA(hdc
, 0x00, code
, full
);
1263 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1264 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1265 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1267 for (j
= 0; j
< ARRAY_SIZE(range
); ++j
)
1269 memset(full
, 0xdd, sizeof full
);
1270 ret
= GetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1271 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1272 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1275 UINT last
= range
[j
].last
- range
[j
].first
;
1276 ret
= GetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1277 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1278 "GetCharABCWidthsA %x should match. codepage = %u\n",
1279 range
[j
].last
, c
[i
].cs
);
1283 hfont
= SelectObject(hdc
, hfont
);
1284 DeleteObject(hfont
);
1287 memset(&lf
, 0, sizeof(lf
));
1288 strcpy(lf
.lfFaceName
, "Tahoma");
1290 hfont
= CreateFontIndirectA(&lf
);
1292 /* test empty glyph's metrics */
1293 hfont
= SelectObject(hdc
, hfont
);
1294 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1295 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1296 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1297 ret
= GetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1298 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1299 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1301 /* 1) prepare unrotated font metrics */
1302 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1303 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1304 DeleteObject(SelectObject(hdc
, hfont
));
1306 /* 2) get rotated font metrics */
1307 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1308 hfont
= CreateFontIndirectA(&lf
);
1309 hfont
= SelectObject(hdc
, hfont
);
1310 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1311 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1313 /* 3) compare ABC results */
1314 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1315 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1316 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1317 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1318 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1319 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1321 DeleteObject(SelectObject(hdc
, hfont
));
1323 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1324 in various widths. */
1325 for (i
= 1; i
<= 2; i
++)
1330 memset(&lf
, 0, sizeof(lf
));
1334 strcpy(lf
.lfFaceName
, "Tahoma");
1339 strcpy(lf
.lfFaceName
, "Times New Roman");
1343 if (!is_truetype_font_installed(lf
.lfFaceName
))
1345 skip("%s is not installed\n", lf
.lfFaceName
);
1348 for (j
= 1; j
<= 80; j
++)
1353 hfont
= CreateFontIndirectA(&lf
);
1354 hfont
= SelectObject(hdc
, hfont
);
1356 nb
= GetGlyphOutlineA(hdc
, code
, GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1357 ok(nb
, "GetGlyphOutlineA should have succeeded at width %d\n", i
);
1359 ret
= GetCharABCWidthsA(hdc
, code
, code
, abc
);
1360 ok(ret
, "GetCharABCWidthsA should have succeeded at width %d\n", i
);
1362 ok(abc
[0].abcA
== gm
.gmptGlyphOrigin
.x
,
1363 "abcA(%d) and gmptGlyphOrigin.x(%d) values are different at width %d\n",
1364 abc
[0].abcA
, gm
.gmptGlyphOrigin
.x
, i
);
1365 ok(abc
[0].abcB
== gm
.gmBlackBoxX
,
1366 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1367 abc
[0].abcB
, gm
.gmBlackBoxX
, i
);
1368 DeleteObject(SelectObject(hdc
, hfont
));
1371 ReleaseDC(NULL
, hdc
);
1373 /* ABC sign test for a variety of transforms */
1374 memset(&lf
, 0, sizeof(lf
));
1375 strcpy(lf
.lfFaceName
, "Tahoma");
1377 hfont
= CreateFontIndirectA(&lf
);
1378 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1381 SetMapMode(hdc
, MM_ANISOTROPIC
);
1382 SelectObject(hdc
, hfont
);
1384 nb
= pGetGlyphIndicesW(hdc
, L
"i", 1, glyphs
, 0);
1385 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1387 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1388 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1389 ret
= GetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1390 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1391 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1392 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1394 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
);
1395 SetWindowExtEx(hdc
, -1, -1, NULL
);
1396 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1397 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1398 SetGraphicsMode(hdc
, GM_ADVANCED
);
1399 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1400 SetWindowExtEx(hdc
, 1, 1, NULL
);
1401 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1402 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1403 SetGraphicsMode(hdc
, GM_ADVANCED
);
1404 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1406 ReleaseDC(hwnd
, hdc
);
1407 DestroyWindow(hwnd
);
1410 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1413 SetMapMode(hdc
, MM_ANISOTROPIC
);
1414 SelectObject(hdc
, hfont
);
1416 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
);
1417 SetWindowExtEx(hdc
, -1, -1, NULL
);
1418 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1419 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1420 SetGraphicsMode(hdc
, GM_ADVANCED
);
1421 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1422 SetWindowExtEx(hdc
, 1, 1, NULL
);
1423 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1424 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1425 SetGraphicsMode(hdc
, GM_ADVANCED
);
1426 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1428 ReleaseDC(hwnd
, hdc
);
1429 DestroyWindow(hwnd
);
1430 DeleteObject(hfont
);
1433 static void test_text_extents(void)
1435 static const WCHAR wt
[] = L
"One\ntwo 3";
1437 INT i
, len
, fit1
, fit2
, extents2
[3];
1446 memset(&lf
, 0, sizeof(lf
));
1447 strcpy(lf
.lfFaceName
, "Arial");
1450 hfont
= CreateFontIndirectA(&lf
);
1452 hfont
= SelectObject(hdc
, hfont
);
1453 GetTextMetricsA(hdc
, &tm
);
1454 ret
= GetTextExtentPointA(hdc
, "o", 1, &sz
);
1455 ok(ret
, "got %d\n", ret
);
1456 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1458 memset(&sz
, 0xcc, sizeof(sz
));
1459 ret
= GetTextExtentPointA(hdc
, "o", 0, &sz
);
1460 ok(ret
, "got %d\n", ret
);
1461 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1463 memset(&sz
, 0xcc, sizeof(sz
));
1464 ret
= GetTextExtentPointA(hdc
, "", 0, &sz
);
1465 ok(ret
, "got %d\n", ret
);
1466 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1468 SetLastError(0xdeadbeef);
1469 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1470 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1472 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1473 hfont
= SelectObject(hdc
, hfont
);
1474 DeleteObject(hfont
);
1479 memset(&sz
, 0xcc, sizeof(sz
));
1480 ret
= GetTextExtentPointW(hdc
, wt
, 0, &sz
);
1481 ok(ret
, "got %d\n", ret
);
1482 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1484 memset(&sz
, 0xcc, sizeof(sz
));
1485 ret
= GetTextExtentPointW(hdc
, L
"", 0, &sz
);
1486 ok(ret
, "got %d\n", ret
);
1487 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1490 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1491 extents
[0] = 1; /* So that the increasing sequence test will fail
1492 if the extents array is untouched. */
1493 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1494 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1495 ok(sz1
.cy
== sz2
.cy
,
1496 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1497 /* Because of the '\n' in the string GetTextExtentExPoint and
1498 GetTextExtentPoint return different widths under Win2k, but
1499 under WinXP they return the same width. So we don't test that
1502 for (i
= 1; i
< len
; ++i
)
1503 ok(extents
[i
-1] <= extents
[i
],
1504 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1506 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1507 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1508 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1509 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1510 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1511 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1512 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1513 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1514 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1515 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1516 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1517 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1518 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1519 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1521 /* extents functions fail with -ve counts (the interesting case being -1) */
1522 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1523 ok(ret
== FALSE
, "got %d\n", ret
);
1524 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1525 ok(ret
== FALSE
, "got %d\n", ret
);
1526 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1527 ok(ret
== FALSE
, "got %d\n", ret
);
1529 /* max_extent = 0 succeeds and returns zero */
1531 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1533 broken(ret
== FALSE
), /* NT4, 2k */
1536 broken(fit1
== -215), /* NT4, 2k */
1537 "fit = %d\n", fit1
);
1538 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1539 ok(ret
== TRUE
, "got %d\n", ret
);
1540 ok(fit2
== 0, "fit = %d\n", fit2
);
1542 /* max_extent = -1 is interpreted as a very large width that will
1543 * definitely fit our three characters */
1545 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1546 ok(ret
== TRUE
, "got %d\n", ret
);
1547 ok(fit1
== 3, "fit = %d\n", fit1
);
1548 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1549 ok(ret
== TRUE
, "got %d\n", ret
);
1550 ok(fit2
== 3, "fit = %d\n", fit2
);
1552 /* max_extent = -2 is interpreted similarly, but the Ansi version
1553 * rejects it while the Unicode one accepts it */
1555 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1556 ok(ret
== FALSE
, "got %d\n", ret
);
1557 ok(fit1
== -215, "fit = %d\n", fit1
);
1558 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1559 ok(ret
== TRUE
, "got %d\n", ret
);
1560 ok(fit2
== 3, "fit = %d\n", fit2
);
1562 hfont
= SelectObject(hdc
, hfont
);
1563 DeleteObject(hfont
);
1565 /* non-MM_TEXT mapping mode */
1567 hfont
= CreateFontIndirectA(&lf
);
1568 hfont
= SelectObject(hdc
, hfont
);
1570 SetMapMode( hdc
, MM_HIMETRIC
);
1571 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1572 ok(ret
, "got %d\n", ret
);
1573 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1575 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1576 ok(ret
, "got %d\n", ret
);
1577 ok(fit1
== 2, "got %d\n", fit1
);
1578 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1579 for(i
= 0; i
< 2; i
++)
1580 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1582 hfont
= SelectObject(hdc
, hfont
);
1583 DeleteObject(hfont
);
1584 HeapFree(GetProcessHeap(), 0, extents
);
1585 ReleaseDC(NULL
, hdc
);
1588 static void free_font(void *font
)
1590 UnmapViewOfFile(font
);
1593 static void *load_font(const char *font_name
, DWORD
*font_size
)
1595 char file_name
[MAX_PATH
];
1596 HANDLE file
, mapping
;
1599 if (font_name
[1] == ':')
1600 strcpy(file_name
, font_name
);
1603 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
1604 strcat(file_name
, "\\fonts\\");
1605 strcat(file_name
, font_name
);
1608 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
1609 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
1611 *font_size
= GetFileSize(file
, NULL
);
1613 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
1620 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
1623 CloseHandle(mapping
);
1627 static void test_GetGlyphIndices(void)
1634 WCHAR testtext
[] = L
"Test\xffff";
1635 WORD glyphs
[(sizeof(testtext
)/2)-1];
1639 DWORD ret
, font_size
, num_fonts
;
1641 char ttf_name
[MAX_PATH
];
1643 if (!pGetGlyphIndicesW
) {
1644 win_skip("GetGlyphIndicesW not available on platform\n");
1650 memset(&lf
, 0, sizeof(lf
));
1651 strcpy(lf
.lfFaceName
, "System");
1653 lf
.lfCharSet
= ANSI_CHARSET
;
1655 hfont
= CreateFontIndirectA(&lf
);
1656 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1657 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1658 if (textm
.tmCharSet
== ANSI_CHARSET
)
1660 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1661 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1662 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1663 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1665 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1666 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1667 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1668 textm
.tmDefaultChar
, glyphs
[4]);
1671 /* FIXME: Write tests for non-ANSI charsets. */
1672 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1674 if(!is_font_installed("Tahoma"))
1676 skip("Tahoma is not installed so skipping this test\n");
1679 memset(&lf
, 0, sizeof(lf
));
1680 strcpy(lf
.lfFaceName
, "Tahoma");
1683 hfont
= CreateFontIndirectA(&lf
);
1684 hOldFont
= SelectObject(hdc
, hfont
);
1685 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1686 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1687 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1688 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1689 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1691 testtext
[0] = textm
.tmDefaultChar
;
1692 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1693 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1694 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1695 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1696 DeleteObject(SelectObject(hdc
, hOldFont
));
1698 ret
= write_ttf_file("wine_nul.ttf", ttf_name
);
1699 ok(ret
, "Failed to create test font file.\n");
1700 font
= load_font(ttf_name
, &font_size
);
1701 ok(font
!= NULL
, "Failed to map font file.\n");
1703 rsrc
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
1704 ok(ret
!= 0, "Failed to add resource, %d.\n", GetLastError());
1705 ok(num_fonts
== 1, "Unexpected number of fonts %u.\n", num_fonts
);
1707 memset(&lf
, 0, sizeof(lf
));
1708 strcpy(lf
.lfFaceName
, "wine_nul");
1711 hfont
= CreateFontIndirectA(&lf
);
1712 hOldFont
= SelectObject(hdc
, hfont
);
1713 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1715 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1716 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1717 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1718 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1719 DeleteObject(SelectObject(hdc
, hOldFont
));
1721 ret
= pRemoveFontMemResourceEx(rsrc
);
1722 ok(ret
, "RemoveFontMemResourceEx error %d\n", GetLastError());
1724 ret
= DeleteFileA(ttf_name
);
1725 ok(ret
, "Failed to delete font file, %d.\n", GetLastError());
1729 static void test_GetKerningPairs(void)
1731 static const struct kerning_data
1733 const char face_name
[LF_FACESIZE
];
1735 /* some interesting fields from OUTLINETEXTMETRIC */
1736 LONG tmHeight
, tmAscent
, tmDescent
;
1741 UINT otmsCapEmHeight
;
1746 UINT otmusMinimumPPEM
;
1747 /* small subset of kerning pairs to test */
1748 DWORD total_kern_pairs
;
1749 const KERNINGPAIR kern_pair
[26];
1752 {"Arial", 12, 12, 9, 3,
1753 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1756 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1757 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1758 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1759 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1760 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1761 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1762 {933,970,+1},{933,972,-1}
1765 {"Arial", -34, 39, 32, 7,
1766 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1769 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1770 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1771 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1772 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1773 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1774 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1775 {933,970,+2},{933,972,-3}
1778 { "Arial", 120, 120, 97, 23,
1779 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1782 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1783 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1784 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1785 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1786 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1787 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1788 {933,970,+6},{933,972,-10}
1791 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1792 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1793 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1796 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1797 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1798 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1799 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1800 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1801 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1802 {933,970,+54},{933,972,-83}
1808 HFONT hfont
, hfont_old
;
1809 KERNINGPAIR
*kern_pair
;
1811 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1815 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1816 * which may render this test unusable, so we're trying to avoid that.
1818 SetLastError(0xdeadbeef);
1819 GetKerningPairsW(hdc
, 0, NULL
);
1820 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1822 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1827 for (i
= 0; i
< ARRAY_SIZE(kd
); i
++)
1829 OUTLINETEXTMETRICW otm
;
1832 if (!is_font_installed(kd
[i
].face_name
))
1834 skip("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1838 memset(&lf
, 0, sizeof(lf
));
1839 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1840 lf
.lfHeight
= kd
[i
].height
;
1841 hfont
= CreateFontIndirectA(&lf
);
1842 ok(hfont
!= NULL
, "failed to create a font, name %s\n", kd
[i
].face_name
);
1844 hfont_old
= SelectObject(hdc
, hfont
);
1846 SetLastError(0xdeadbeef);
1847 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1848 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1849 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1851 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1852 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1853 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1854 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1855 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1856 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1858 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1859 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1860 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1861 kd
[i
].otmAscent
, otm
.otmAscent
);
1862 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1863 kd
[i
].otmDescent
, otm
.otmDescent
);
1864 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1865 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1866 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1867 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1868 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1869 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1871 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1872 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1874 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1875 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1876 ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1877 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1879 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1880 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1882 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1883 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1885 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1888 SetLastError(0xdeadbeef);
1889 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1890 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1891 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1892 ok(ret
== 0, "got %u, expected 0\n", ret
);
1894 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1895 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1897 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1898 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1900 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1901 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1905 for (n
= 0; n
< ret
; n
++)
1909 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1911 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1912 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1914 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1915 "pair %d:%d got %d, expected %d\n",
1916 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1917 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1923 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1924 matches
, kd
[i
].total_kern_pairs
);
1926 HeapFree(GetProcessHeap(), 0, kern_pair
);
1928 SelectObject(hdc
, hfont_old
);
1929 DeleteObject(hfont
);
1937 const char face_name
[LF_FACESIZE
];
1938 int requested_height
;
1939 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1943 static void test_height( HDC hdc
, const struct font_data
*fd
)
1946 HFONT hfont
, old_hfont
;
1950 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1952 if (!is_truetype_font_installed(fd
[i
].face_name
))
1954 skip("%s is not installed\n", fd
[i
].face_name
);
1958 memset(&lf
, 0, sizeof(lf
));
1959 lf
.lfHeight
= fd
[i
].requested_height
;
1960 lf
.lfWeight
= fd
[i
].weight
;
1961 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1963 hfont
= CreateFontIndirectA(&lf
);
1964 ok(hfont
!= NULL
, "failed to create a font, name %s\n", fd
[i
].face_name
);
1966 old_hfont
= SelectObject(hdc
, hfont
);
1967 ret
= GetTextMetricsA(hdc
, &tm
);
1968 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1969 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1971 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
);
1972 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
);
1973 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
);
1974 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
);
1975 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
);
1976 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
);
1979 SelectObject(hdc
, old_hfont
);
1980 /* force GDI to use new font, otherwise Windows leaks the font reference */
1981 GetTextMetricsA(hdc
, &tm
);
1982 DeleteObject(hfont
);
1986 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1988 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1989 DWORD
*table
= (DWORD
*)ttf
+ 3;
1991 for (i
= 0; i
< num_tables
; i
++)
1993 if (table
[0] == tag
)
1994 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
2000 static void test_height_selection_vdmx( HDC hdc
)
2002 static const struct font_data charset_0
[] = /* doesn't use VDMX */
2004 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2005 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2006 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2007 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2008 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2009 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
2010 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2011 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
2012 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
2013 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
2014 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
2015 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
2016 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
2017 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
2018 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2019 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
2020 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
2021 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
2022 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2023 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2024 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2025 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2026 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
2027 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2028 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
2029 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2030 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2031 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2032 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2033 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2034 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
2035 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
2036 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
2037 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
2038 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
2039 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
2040 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2041 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
2042 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
2043 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2044 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2045 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2046 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2047 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
2048 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
2049 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
2050 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
2051 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
2052 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
2053 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2054 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
2055 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2056 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2059 static const struct font_data charset_1
[] = /* Uses VDMX */
2061 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2062 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2063 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2064 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2065 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2066 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2067 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2068 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2069 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2070 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2071 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2072 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2073 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2074 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2075 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2076 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2077 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2078 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2079 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2080 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2081 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2082 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2083 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2084 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
2085 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
2086 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
2087 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2088 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2089 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2090 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2091 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2092 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2093 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2094 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2095 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2096 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2097 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2098 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2099 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2100 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2101 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2102 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
2103 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
2104 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
2105 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
2106 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
2107 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
2108 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
2109 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
2110 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
2111 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
2112 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
2113 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2116 static const struct vdmx_data
2120 const struct font_data
*fd
;
2123 { 0, 0, charset_0
},
2124 { 0, 1, charset_1
},
2125 { 1, 0, charset_0
},
2132 char ttf_name
[MAX_PATH
];
2136 if (!pAddFontResourceExA
)
2138 win_skip("AddFontResourceExA unavailable\n");
2142 for (i
= 0; i
< ARRAY_SIZE(data
); i
++)
2144 res
= get_res_data( "wine_vdmx.ttf", &size
);
2146 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2147 memcpy( copy
, res
, size
);
2148 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2149 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2150 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2151 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2152 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2153 ratio_rec
[0] = data
[i
].bCharSet
;
2155 write_tmp_file( copy
, &size
, ttf_name
);
2156 HeapFree( GetProcessHeap(), 0, copy
);
2158 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2159 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2160 if (!num
) win_skip("Unable to add ttf font resource\n");
2163 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2164 test_height( hdc
, data
[i
].fd
);
2165 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2167 ret
= DeleteFileA( ttf_name
);
2168 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
),
2169 "DeleteFile error %d\n", GetLastError());
2173 static void test_height_selection(void)
2175 static const struct font_data tahoma
[] =
2177 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2178 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2179 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2180 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2181 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2182 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2183 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2184 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2185 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2186 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2187 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2189 HDC hdc
= CreateCompatibleDC(0);
2190 ok(hdc
!= NULL
, "failed to create hdc\n");
2192 test_height( hdc
, tahoma
);
2193 test_height_selection_vdmx( hdc
);
2198 static UINT
get_font_fsselection(LOGFONTA
*lf
)
2200 OUTLINETEXTMETRICA
*otm
;
2201 HFONT hfont
, hfont_old
;
2202 DWORD ret
, otm_size
;
2207 hfont
= CreateFontIndirectA(lf
);
2208 ok(hfont
!= NULL
, "failed to create a font\n");
2210 hfont_old
= SelectObject(hdc
, hfont
);
2212 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2213 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2214 otm
->otmSize
= sizeof(*otm
);
2215 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2216 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2217 fsSelection
= otm
->otmfsSelection
;
2218 HeapFree(GetProcessHeap(), 0, otm
);
2219 SelectObject(hdc
, hfont_old
);
2220 DeleteObject(hfont
);
2226 static void test_GetOutlineTextMetrics(void)
2228 OUTLINETEXTMETRICA
*otm
;
2230 HFONT hfont
, hfont_old
;
2232 DWORD ret
, otm_size
;
2236 /* check fsSelection field with bold simulation */
2237 memset(&lf
, 0, sizeof(lf
));
2238 strcpy(lf
.lfFaceName
, "Wingdings");
2239 lf
.lfCharSet
= SYMBOL_CHARSET
;
2242 fsSelection
= get_font_fsselection(&lf
);
2243 ok((fsSelection
& (1 << 5)) == 0, "got 0x%x\n", fsSelection
);
2245 /* face with bold simulation */
2246 lf
.lfWeight
= FW_BOLD
;
2247 fsSelection
= get_font_fsselection(&lf
);
2248 ok((fsSelection
& (1 << 5)) != 0, "got 0x%x\n", fsSelection
);
2250 /* check fsSelection field with oblique simulation */
2251 memset(&lf
, 0, sizeof(lf
));
2252 strcpy(lf
.lfFaceName
, "Tahoma");
2254 lf
.lfWeight
= FW_NORMAL
;
2255 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2256 lf
.lfQuality
= PROOF_QUALITY
;
2259 fsSelection
= get_font_fsselection(&lf
);
2260 ok((fsSelection
& 1) == 0, "got 0x%x\n", fsSelection
);
2263 /* face with oblique simulation */
2264 fsSelection
= get_font_fsselection(&lf
);
2265 ok((fsSelection
& 1) == 1, "got 0x%x\n", fsSelection
);
2267 if (!is_font_installed("Arial"))
2269 skip("Arial is not installed\n");
2275 memset(&lf
, 0, sizeof(lf
));
2276 strcpy(lf
.lfFaceName
, "Arial");
2278 lf
.lfWeight
= FW_NORMAL
;
2279 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2280 lf
.lfQuality
= PROOF_QUALITY
;
2281 hfont
= CreateFontIndirectA(&lf
);
2282 ok(hfont
!= NULL
, "failed to create a font\n");
2284 hfont_old
= SelectObject(hdc
, hfont
);
2285 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2287 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2289 memset(otm
, 0xAA, otm_size
);
2290 SetLastError(0xdeadbeef);
2291 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2292 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2293 ok(ret
== 1 /* Win9x */ ||
2294 ret
== otm
->otmSize
/* XP*/,
2295 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2296 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2298 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2299 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2300 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2301 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2304 memset(otm
, 0xAA, otm_size
);
2305 SetLastError(0xdeadbeef);
2306 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2307 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2308 ok(ret
== 1 /* Win9x */ ||
2309 ret
== otm
->otmSize
/* XP*/,
2310 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2311 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2313 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2314 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2315 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2316 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2319 /* ask about truncated data */
2320 memset(otm
, 0xAA, otm_size
);
2321 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2322 SetLastError(0xdeadbeef);
2323 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2324 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2325 ok(ret
== 1 /* Win9x */ ||
2326 ret
== otm
->otmSize
/* XP*/,
2327 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2328 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2330 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2331 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2332 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2334 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2336 /* check handling of NULL pointer */
2337 SetLastError(0xdeadbeef);
2338 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, NULL
);
2339 ok(ret
== otm_size
, "expected %u, got %u, error %d\n", otm_size
, ret
, GetLastError());
2341 HeapFree(GetProcessHeap(), 0, otm
);
2343 SelectObject(hdc
, hfont_old
);
2344 DeleteObject(hfont
);
2349 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2353 areaWidth
= clientArea
->right
- clientArea
->left
,
2355 const char *pFirstChar
, *pLastChar
;
2362 int GetTextExtentExPointWWidth
;
2365 GetTextMetricsA(hdc
, &tm
);
2366 y
= clientArea
->top
;
2369 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2375 /* if not at the end of the string, ... */
2376 if (*str
== '\0') break;
2377 /* ... add the next word to the current extent */
2378 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2380 SetTextJustification(hdc
, 0, 0);
2381 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2382 } while ((int) size
.cx
< areaWidth
);
2384 /* ignore trailing break chars */
2386 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2392 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2394 SetTextJustification(hdc
, 0, 0);
2395 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2397 /* do not justify the last extent */
2398 if (*str
!= '\0' && breakCount
> 0)
2400 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2401 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2402 if (size
.cx
!= areaWidth
&& nErrors
< ARRAY_SIZE(error
) - 1)
2404 error
[nErrors
].start
= pFirstChar
;
2405 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2406 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2413 } while (*str
&& y
< clientArea
->bottom
);
2415 for (e
= 0; e
< nErrors
; e
++)
2417 /* The width returned by GetTextExtentPoint32() is exactly the same
2418 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2419 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2420 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2421 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2425 static void test_SetTextJustification(void)
2435 static const char testText
[] =
2436 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2437 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2438 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2439 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2440 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2441 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2442 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2444 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2445 GetClientRect( hwnd
, &clientArea
);
2446 hdc
= GetDC( hwnd
);
2448 if (!is_font_installed("Times New Roman"))
2450 skip("Times New Roman is not installed\n");
2454 memset(&lf
, 0, sizeof lf
);
2455 lf
.lfCharSet
= ANSI_CHARSET
;
2456 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2457 lf
.lfWeight
= FW_DONTCARE
;
2459 lf
.lfQuality
= DEFAULT_QUALITY
;
2460 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2461 hfont
= create_font("Times New Roman", &lf
);
2462 SelectObject(hdc
, hfont
);
2464 testJustification(hdc
, testText
, &clientArea
);
2466 if (!pGetTextExtentExPointI
) goto done
;
2467 GetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2469 SetTextJustification(hdc
, 0, 0);
2470 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2471 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2472 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2473 SetTextJustification(hdc
, 4, 1);
2474 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2475 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2476 SetTextJustification(hdc
, 9, 2);
2477 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2478 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2479 SetTextJustification(hdc
, 7, 3);
2480 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2481 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2482 SetTextJustification(hdc
, 7, 3);
2483 SetTextCharacterExtra(hdc
, 2 );
2484 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2485 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2486 SetTextJustification(hdc
, 0, 0);
2487 SetTextCharacterExtra(hdc
, 0);
2488 size
.cx
= size
.cy
= 1234;
2489 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2490 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
2491 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2492 SetTextJustification(hdc
, 5, 1);
2493 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2494 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2495 SetTextJustification(hdc
, 0, 0);
2497 SetMapMode( hdc
, MM_ANISOTROPIC
);
2498 SetWindowExtEx( hdc
, 2, 2, NULL
);
2499 GetClientRect( hwnd
, &clientArea
);
2500 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2501 testJustification(hdc
, testText
, &clientArea
);
2503 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2504 for (i
= 0; i
< 10; i
++)
2506 SetTextCharacterExtra(hdc
, i
);
2507 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2508 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2510 SetTextCharacterExtra(hdc
, 0);
2511 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2512 for (i
= 0; i
< 10; i
++)
2514 SetTextCharacterExtra(hdc
, i
);
2515 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2516 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2518 SetTextCharacterExtra(hdc
, 0);
2520 SetViewportExtEx( hdc
, 3, 3, NULL
);
2521 GetClientRect( hwnd
, &clientArea
);
2522 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2523 testJustification(hdc
, testText
, &clientArea
);
2525 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2526 for (i
= 0; i
< 10; i
++)
2528 SetTextCharacterExtra(hdc
, i
);
2529 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2530 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2534 DeleteObject(hfont
);
2535 ReleaseDC(hwnd
, hdc
);
2536 DestroyWindow(hwnd
);
2539 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2543 HFONT hfont
, hfont_old
;
2550 assert(count
<= 128);
2552 memset(&lf
, 0, sizeof(lf
));
2554 lf
.lfCharSet
= charset
;
2556 lstrcpyA(lf
.lfFaceName
, "Arial");
2557 SetLastError(0xdeadbeef);
2558 hfont
= CreateFontIndirectA(&lf
);
2559 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2562 hfont_old
= SelectObject(hdc
, hfont
);
2564 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2565 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2567 SetLastError(0xdeadbeef);
2568 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2569 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
2571 if (charset
== SYMBOL_CHARSET
)
2573 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2574 ok(fs
.fsCsb
[0] & (1u << 31), "symbol encoding should be available\n");
2578 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2579 ok(!(fs
.fsCsb
[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2582 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2584 trace("Can't find codepage for charset %d\n", cs
);
2588 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2590 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2592 skip("Font code page %d, looking for code page %d\n",
2593 pGdiGetCodePage(hdc
), code_page
);
2601 WCHAR unicode_buf
[128];
2603 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2605 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2607 SetLastError(0xdeadbeef);
2608 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2609 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2610 count
, ret
, GetLastError());
2616 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2618 SetLastError(0xdeadbeef);
2619 ret
= GetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2620 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2621 count
, ret
, GetLastError());
2624 SelectObject(hdc
, hfont_old
);
2625 DeleteObject(hfont
);
2632 static void test_font_charset(void)
2634 static struct charset_data
2638 WORD font_idxA
[128], font_idxW
[128];
2641 { ANSI_CHARSET
, 1252 },
2642 { RUSSIAN_CHARSET
, 1251 },
2643 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2647 if (!pGetGlyphIndicesW
)
2649 win_skip("Skipping the font charset test on a Win9x platform\n");
2653 if (!is_font_installed("Arial"))
2655 skip("Arial is not installed\n");
2659 for (i
= 0; i
< ARRAY_SIZE(cd
); i
++)
2661 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2663 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2665 skip("Symbol or Wingdings is not installed\n");
2669 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2670 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2671 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2674 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2677 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2678 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2681 skip("Symbol or Wingdings is not installed\n");
2684 static void test_GdiGetCodePage(void)
2686 static const struct _matching_data
2688 UINT current_codepage
;
2691 UINT expected_codepage
;
2692 } matching_data
[] = {
2693 {1251, "Arial", ANSI_CHARSET
, 1252},
2694 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2696 {1252, "Arial", ANSI_CHARSET
, 1252},
2697 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2699 {1253, "Arial", ANSI_CHARSET
, 1252},
2700 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2702 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2703 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2704 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2706 { 936, "Arial", ANSI_CHARSET
, 936},
2707 { 936, "Tahoma", ANSI_CHARSET
, 936},
2708 { 936, "Simsun", ANSI_CHARSET
, 936},
2710 { 949, "Arial", ANSI_CHARSET
, 949},
2711 { 949, "Tahoma", ANSI_CHARSET
, 949},
2712 { 949, "Gulim", ANSI_CHARSET
, 949},
2714 { 950, "Arial", ANSI_CHARSET
, 950},
2715 { 950, "Tahoma", ANSI_CHARSET
, 950},
2716 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2725 if (!pGdiGetCodePage
)
2727 skip("GdiGetCodePage not available on this platform\n");
2733 for (i
= 0; i
< ARRAY_SIZE(matching_data
); i
++)
2735 /* only test data matched current locale codepage */
2736 if (matching_data
[i
].current_codepage
!= acp
)
2739 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2741 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2747 memset(&lf
, 0, sizeof(lf
));
2749 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2750 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2751 hfont
= CreateFontIndirectA(&lf
);
2752 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2754 hfont
= SelectObject(hdc
, hfont
);
2755 codepage
= pGdiGetCodePage(hdc
);
2756 ok(codepage
== matching_data
[i
].expected_codepage
,
2757 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2759 hfont
= SelectObject(hdc
, hfont
);
2760 DeleteObject(hfont
);
2762 /* CLIP_DFA_DISABLE turns off the font association */
2763 lf
.lfClipPrecision
= CLIP_DFA_DISABLE
;
2764 hfont
= CreateFontIndirectA(&lf
);
2765 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2767 hfont
= SelectObject(hdc
, hfont
);
2768 codepage
= pGdiGetCodePage(hdc
);
2769 ok(codepage
== 1252, "GdiGetCodePage returned %d\n", codepage
);
2771 hfont
= SelectObject(hdc
, hfont
);
2772 DeleteObject(hfont
);
2774 ReleaseDC(NULL
, hdc
);
2778 static void test_GetFontUnicodeRanges(void)
2782 HFONT hfont
, hfont_old
;
2786 if (!pGetFontUnicodeRanges
)
2788 win_skip("GetFontUnicodeRanges not available before W2K\n");
2792 memset(&lf
, 0, sizeof(lf
));
2793 lstrcpyA(lf
.lfFaceName
, "Arial");
2794 hfont
= create_font("Arial", &lf
);
2797 hfont_old
= SelectObject(hdc
, hfont
);
2799 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2800 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2802 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2803 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2805 gs
= heap_alloc_zero(size
);
2807 size
= pGetFontUnicodeRanges(hdc
, gs
);
2808 ok(size
, "GetFontUnicodeRanges failed\n");
2809 ok(gs
->cRanges
, "Unexpected ranges count.\n");
2813 SelectObject(hdc
, hfont_old
);
2814 DeleteObject(hfont
);
2815 ReleaseDC(NULL
, hdc
);
2818 struct enum_font_data
2824 struct enum_fullname_data
2830 struct enum_fullname_data_w
2836 struct enum_font_dataW
2842 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2844 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2845 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2847 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2848 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2850 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2852 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2854 if (efd
->total
>= efd
->size
)
2856 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2857 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2858 if (!efd
->lf
) return 0;
2860 efd
->lf
[efd
->total
++] = *lf
;
2865 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2867 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2868 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2870 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2871 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2873 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2875 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2877 if (efd
->total
>= efd
->size
)
2879 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2880 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2881 if (!efd
->lf
) return 0;
2883 efd
->lf
[efd
->total
++] = *lf
;
2888 static void get_charset_stats(struct enum_font_data
*efd
,
2889 int *ansi_charset
, int *symbol_charset
,
2890 int *russian_charset
)
2895 *symbol_charset
= 0;
2896 *russian_charset
= 0;
2898 for (i
= 0; i
< efd
->total
; i
++)
2900 switch (efd
->lf
[i
].lfCharSet
)
2905 case SYMBOL_CHARSET
:
2906 (*symbol_charset
)++;
2908 case RUSSIAN_CHARSET
:
2909 (*russian_charset
)++;
2915 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2916 int *ansi_charset
, int *symbol_charset
,
2917 int *russian_charset
)
2922 *symbol_charset
= 0;
2923 *russian_charset
= 0;
2925 for (i
= 0; i
< efd
->total
; i
++)
2927 switch (efd
->lf
[i
].lfCharSet
)
2932 case SYMBOL_CHARSET
:
2933 (*symbol_charset
)++;
2935 case RUSSIAN_CHARSET
:
2936 (*russian_charset
)++;
2942 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2944 struct enum_font_data efd
;
2945 struct enum_font_dataW efdw
;
2948 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2950 if (*font_name
&& !is_truetype_font_installed(font_name
))
2952 skip("%s is not installed\n", font_name
);
2955 memset( &efd
, 0, sizeof(efd
) );
2956 memset( &efdw
, 0, sizeof(efdw
) );
2960 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2961 * while EnumFontFamiliesEx doesn't.
2963 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2966 * Use EnumFontFamiliesW since win98 crashes when the
2967 * second parameter is NULL using EnumFontFamilies
2970 SetLastError(0xdeadbeef);
2971 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2972 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2975 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2976 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2977 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2978 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2979 ok(russian_charset
> 0 ||
2980 broken(russian_charset
== 0), /* NT4 */
2981 "NULL family should enumerate RUSSIAN_CHARSET\n");
2985 SetLastError(0xdeadbeef);
2986 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2987 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2990 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2991 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2992 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2993 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2994 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2999 SetLastError(0xdeadbeef);
3000 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
3001 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
3002 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3004 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3006 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
3007 for (i
= 0; i
< efd
.total
; i
++)
3009 /* FIXME: remove completely once Wine is fixed */
3010 todo_wine_if(efd
.lf
[i
].lfCharSet
!= font_charset
)
3011 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3012 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3013 font_name
, efd
.lf
[i
].lfFaceName
);
3016 memset(&lf
, 0, sizeof(lf
));
3017 lf
.lfCharSet
= ANSI_CHARSET
;
3018 strcpy(lf
.lfFaceName
, font_name
);
3020 SetLastError(0xdeadbeef);
3021 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3022 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3023 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3024 if (font_charset
== SYMBOL_CHARSET
)
3027 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
3029 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3033 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
3034 for (i
= 0; i
< efd
.total
; i
++)
3036 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3038 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3039 font_name
, efd
.lf
[i
].lfFaceName
);
3043 /* DEFAULT_CHARSET should enumerate all available charsets */
3044 memset(&lf
, 0, sizeof(lf
));
3045 lf
.lfCharSet
= DEFAULT_CHARSET
;
3046 strcpy(lf
.lfFaceName
, font_name
);
3048 SetLastError(0xdeadbeef);
3049 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3050 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3051 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3052 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
3053 for (i
= 0; i
< efd
.total
; i
++)
3056 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3057 font_name
, efd
.lf
[i
].lfFaceName
);
3061 switch (font_charset
)
3064 ok(ansi_charset
> 0,
3065 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3067 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
3068 ok(russian_charset
> 0,
3069 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3071 case SYMBOL_CHARSET
:
3073 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
3075 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3076 ok(!russian_charset
,
3077 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3079 case DEFAULT_CHARSET
:
3080 ok(ansi_charset
> 0,
3081 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3082 ok(symbol_charset
> 0,
3083 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3084 ok(russian_charset
> 0,
3085 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3091 ok(ansi_charset
> 0,
3092 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3093 ok(symbol_charset
> 0,
3094 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3095 ok(russian_charset
> 0,
3096 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3099 memset(&lf
, 0, sizeof(lf
));
3100 lf
.lfCharSet
= SYMBOL_CHARSET
;
3101 strcpy(lf
.lfFaceName
, font_name
);
3103 SetLastError(0xdeadbeef);
3104 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3105 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3106 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3107 if (*font_name
&& font_charset
== ANSI_CHARSET
)
3108 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
3111 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
3112 for (i
= 0; i
< efd
.total
; i
++)
3114 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3116 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3117 font_name
, efd
.lf
[i
].lfFaceName
);
3121 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3122 ok(symbol_charset
> 0,
3123 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3124 ok(!russian_charset
,
3125 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3130 heap_free( efd
.lf
);
3131 heap_free( efdw
.lf
);
3134 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
3136 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
3137 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
3138 const DWORD valid_bits
= 0x003f01ff;
3142 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
3144 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
3145 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
3146 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
3155 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3157 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
3159 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3161 if (efd
->total
>= efd
->size
)
3163 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
3164 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
3165 if (!efd
->lf
) return 0;
3167 efd
->lf
[efd
->total
++] = *lf
;
3172 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3174 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
3176 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3178 if (efnd
->total
>= efnd
->size
)
3180 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3181 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3182 if (!efnd
->elf
) return 0;
3184 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
3189 static INT CALLBACK
enum_fullname_data_proc_w( const LOGFONTW
*lf
, const TEXTMETRICW
*ntm
, DWORD type
, LPARAM lParam
)
3191 struct enum_fullname_data_w
*efnd
= (struct enum_fullname_data_w
*)lParam
;
3193 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3195 if (efnd
->total
>= efnd
->size
)
3197 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3198 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3199 if (!efnd
->elf
) return 0;
3201 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTW
*)lf
;
3206 static void test_EnumFontFamiliesEx_default_charset(void)
3208 struct enum_font_data efd
;
3209 LOGFONTA target
, enum_font
;
3215 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3216 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3221 memset(&enum_font
, 0, sizeof(enum_font
));
3222 enum_font
.lfCharSet
= csi
.ciCharset
;
3223 target
.lfFaceName
[0] = '\0';
3224 target
.lfCharSet
= csi
.ciCharset
;
3225 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3226 if (target
.lfFaceName
[0] == '\0') {
3227 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3230 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3231 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3232 target
.lfCharSet
= ANSI_CHARSET
;
3235 memset(&efd
, 0, sizeof(efd
));
3236 memset(&enum_font
, 0, sizeof(enum_font
));
3237 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3238 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3239 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3243 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3245 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3246 "(%s) got charset %d expected %d\n",
3247 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3253 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3255 HFONT hfont
, hfont_prev
;
3257 GLYPHMETRICS gm1
, gm2
;
3261 /* negative widths are handled just as positive ones */
3262 lf2
.lfWidth
= -lf
->lfWidth
;
3264 SetLastError(0xdeadbeef);
3265 hfont
= CreateFontIndirectA(lf
);
3266 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3267 check_font("original", lf
, hfont
);
3269 hfont_prev
= SelectObject(hdc
, hfont
);
3271 ret
= GetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3272 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3274 SelectObject(hdc
, hfont_prev
);
3275 DeleteObject(hfont
);
3276 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3280 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3281 memset(&gm1
, 0xab, sizeof(gm1
));
3282 SetLastError(0xdeadbeef);
3283 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3284 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3286 SelectObject(hdc
, hfont_prev
);
3287 DeleteObject(hfont
);
3289 SetLastError(0xdeadbeef);
3290 hfont
= CreateFontIndirectA(&lf2
);
3291 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3292 check_font("negative width", &lf2
, hfont
);
3294 hfont_prev
= SelectObject(hdc
, hfont
);
3296 memset(&gm2
, 0xbb, sizeof(gm2
));
3297 SetLastError(0xdeadbeef);
3298 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3299 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3301 SelectObject(hdc
, hfont_prev
);
3302 DeleteObject(hfont
);
3304 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3305 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3306 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3307 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3308 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3309 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3310 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3311 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3312 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3313 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3314 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3317 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3318 #include "pshpack2.h"
3322 SHORT xAvgCharWidth
;
3323 USHORT usWeightClass
;
3324 USHORT usWidthClass
;
3326 SHORT ySubscriptXSize
;
3327 SHORT ySubscriptYSize
;
3328 SHORT ySubscriptXOffset
;
3329 SHORT ySubscriptYOffset
;
3330 SHORT ySuperscriptXSize
;
3331 SHORT ySuperscriptYSize
;
3332 SHORT ySuperscriptXOffset
;
3333 SHORT ySuperscriptYOffset
;
3334 SHORT yStrikeoutSize
;
3335 SHORT yStrikeoutPosition
;
3338 ULONG ulUnicodeRange1
;
3339 ULONG ulUnicodeRange2
;
3340 ULONG ulUnicodeRange3
;
3341 ULONG ulUnicodeRange4
;
3344 USHORT usFirstCharIndex
;
3345 USHORT usLastCharIndex
;
3346 /* According to the Apple spec, original version didn't have the below fields,
3347 * version numbers were taken from the OpenType spec.
3349 /* version 0 (TrueType 1.5) */
3350 USHORT sTypoAscender
;
3351 USHORT sTypoDescender
;
3352 USHORT sTypoLineGap
;
3354 USHORT usWinDescent
;
3355 /* version 1 (TrueType 1.66) */
3356 ULONG ulCodePageRange1
;
3357 ULONG ulCodePageRange2
;
3358 /* version 2 (OpenType 1.2) */
3361 USHORT usDefaultChar
;
3363 USHORT usMaxContext
;
3364 /* version 4 (OpenType 1.6) */
3365 USHORT usLowerOpticalPointSize
;
3366 USHORT usUpperOpticalPointSize
;
3368 #include "poppack.h"
3370 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3383 } cmap_encoding_record
;
3391 BYTE glyph_ids
[256];
3401 USHORT search_range
;
3402 USHORT entry_selector
;
3405 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3408 USHORT start_count[seg_countx2 / 2];
3409 USHORT id_delta[seg_countx2 / 2];
3410 USHORT id_range_offset[seg_countx2 / 2];
3420 USHORT id_range_offset
;
3421 } cmap_format_4_seg
;
3423 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V4
*os2
, WORD family
, const char *name
)
3425 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3426 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3427 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3428 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3429 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3432 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3435 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3439 for(i
= 0; i
< 256; i
++)
3441 if(cmap
->glyph_ids
[i
] == 0) continue;
3443 if(*first
== 256) *first
= i
;
3445 if(*first
== 256) return FALSE
;
3449 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3451 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3452 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3453 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3454 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3455 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3458 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3461 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3462 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3466 for(i
= 0; i
< seg_count
; i
++)
3468 cmap_format_4_seg seg
;
3470 get_seg4(cmap
, i
, &seg
);
3472 if(seg
.start_count
> 0xfffe) break;
3474 if(*first
== 0x10000) *first
= seg
.start_count
;
3476 *last
= min(seg
.end_count
, 0xfffe);
3479 if(*first
== 0x10000) return FALSE
;
3483 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3486 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3488 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3490 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3491 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3504 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3507 cmap_header
*header
;
3512 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3513 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3514 if(size
== GDI_ERROR
) return FALSE
;
3516 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3517 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3518 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3519 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3521 cmap
= get_cmap(header
, 3, 1);
3523 *cmap_type
= cmap_ms_unicode
;
3526 cmap
= get_cmap(header
, 3, 0);
3527 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3531 *cmap_type
= cmap_none
;
3535 format
= GET_BE_WORD(*(WORD
*)cmap
);
3539 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3542 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3545 skip("unhandled cmap format %d\n", format
);
3550 HeapFree(GetProcessHeap(), 0, header
);
3554 #define TT_PLATFORM_APPLE_UNICODE 0
3555 #define TT_PLATFORM_MACINTOSH 1
3556 #define TT_PLATFORM_MICROSOFT 3
3557 #define TT_APPLE_ID_DEFAULT 0
3558 #define TT_APPLE_ID_ISO_10646 2
3559 #define TT_APPLE_ID_UNICODE_2_0 3
3560 #define TT_MS_ID_SYMBOL_CS 0
3561 #define TT_MS_ID_UNICODE_CS 1
3562 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3563 #define TT_NAME_ID_FONT_FAMILY 1
3564 #define TT_NAME_ID_FONT_SUBFAMILY 2
3565 #define TT_NAME_ID_UNIQUE_ID 3
3566 #define TT_NAME_ID_FULL_NAME 4
3567 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3569 typedef struct sfnt_name
3579 static const LANGID mac_langid_table
[] =
3581 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
3582 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
3583 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
3584 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
3585 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
3586 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
3587 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
3588 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
3589 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
3590 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
3591 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
3592 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
3593 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
3594 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
3595 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
3596 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
3597 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
3598 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
3599 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
3600 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3601 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
3602 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
3603 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
3604 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
3605 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
3606 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
3607 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
3608 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
3609 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
3610 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
3611 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
3612 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
3613 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
3614 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3615 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
3616 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
3617 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
3618 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
3619 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
3620 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
3621 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
3622 0, /* TT_MAC_LANGID_YIDDISH */
3623 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
3624 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
3625 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
3626 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
3627 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
3628 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
3629 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
3630 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
3631 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3632 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
3633 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
3634 0, /* TT_MAC_LANGID_MOLDAVIAN */
3635 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
3636 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
3637 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
3638 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
3639 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3640 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
3641 0, /* TT_MAC_LANGID_KURDISH */
3642 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
3643 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
3644 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
3645 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
3646 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
3647 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
3648 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
3649 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
3650 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
3651 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
3652 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
3653 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
3654 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
3655 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
3656 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
3657 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
3658 0, /* TT_MAC_LANGID_BURMESE */
3659 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
3660 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
3661 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
3662 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
3663 0, /* TT_MAC_LANGID_TAGALOG */
3664 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3665 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3666 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
3667 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
3668 0, /* TT_MAC_LANGID_GALLA */
3669 0, /* TT_MAC_LANGID_SOMALI */
3670 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
3671 0, /* TT_MAC_LANGID_RUANDA */
3672 0, /* TT_MAC_LANGID_RUNDI */
3673 0, /* TT_MAC_LANGID_CHEWA */
3674 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
3675 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
3676 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3677 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3678 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
3679 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
3680 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
3681 0, /* TT_MAC_LANGID_LATIN */
3682 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
3683 0, /* TT_MAC_LANGID_GUARANI */
3684 0, /* TT_MAC_LANGID_AYMARA */
3685 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
3686 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
3687 0, /* TT_MAC_LANGID_DZONGKHA */
3688 0, /* TT_MAC_LANGID_JAVANESE */
3689 0, /* TT_MAC_LANGID_SUNDANESE */
3690 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
3691 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
3692 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
3693 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
3694 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3695 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
3696 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
3697 0, /* TT_MAC_LANGID_TONGAN */
3698 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3699 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
3700 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3703 static inline WORD
get_mac_code_page( const sfnt_name
*name
)
3705 if (GET_BE_WORD(name
->encoding_id
) == TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
3706 return 10000 + GET_BE_WORD(name
->encoding_id
);
3709 static int match_name_table_language( const sfnt_name
*name
, LANGID lang
)
3714 switch (GET_BE_WORD(name
->platform_id
))
3716 case TT_PLATFORM_MICROSOFT
:
3717 res
+= 5; /* prefer the Microsoft name */
3718 switch (GET_BE_WORD(name
->encoding_id
))
3720 case TT_MS_ID_UNICODE_CS
:
3721 case TT_MS_ID_SYMBOL_CS
:
3722 name_lang
= GET_BE_WORD(name
->language_id
);
3728 case TT_PLATFORM_MACINTOSH
:
3729 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
3730 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3731 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3733 case TT_PLATFORM_APPLE_UNICODE
:
3734 res
+= 2; /* prefer Unicode encodings */
3735 switch (GET_BE_WORD(name
->encoding_id
))
3737 case TT_APPLE_ID_DEFAULT
:
3738 case TT_APPLE_ID_ISO_10646
:
3739 case TT_APPLE_ID_UNICODE_2_0
:
3740 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3741 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3750 if (name_lang
== lang
) res
+= 30;
3751 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
3752 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
3756 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3758 struct sfnt_name_header
3761 USHORT number_of_record
;
3762 USHORT storage_offset
;
3766 LONG size
, offset
, length
;
3771 int res
, best_lang
= 0, best_index
= -1;
3773 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3774 ok(size
!= GDI_ERROR
, "no name table found\n");
3775 if(size
== GDI_ERROR
) return FALSE
;
3777 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3778 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3779 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3781 header
= (void *)data
;
3782 header
->format
= GET_BE_WORD(header
->format
);
3783 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3784 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3785 if (header
->format
!= 0)
3787 skip("got format %u\n", header
->format
);
3790 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3792 skip("number records out of range: %d\n", header
->number_of_record
);
3795 if (header
->storage_offset
>= size
)
3797 skip("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3801 entry
= (void *)&header
[1];
3802 for (i
= 0; i
< header
->number_of_record
; i
++)
3804 if (GET_BE_WORD(entry
[i
].name_id
) != name_id
) continue;
3805 res
= match_name_table_language( &entry
[i
], language_id
);
3806 if (res
> best_lang
)
3813 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[best_index
].offset
);
3814 length
= GET_BE_WORD(entry
[best_index
].length
);
3815 if (offset
+ length
> size
)
3817 skip("entry %d is out of range\n", best_index
);
3820 if (length
>= out_size
)
3822 skip("buffer too small for entry %d\n", best_index
);
3826 name
= (WCHAR
*)(data
+ offset
);
3827 for (c
= 0; c
< length
/ 2; c
++)
3828 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3834 HeapFree(GetProcessHeap(), 0, data
);
3838 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3841 HFONT hfont
, hfont_old
;
3845 const char *font_name
= lf
->lfFaceName
;
3846 DWORD cmap_first
= 0, cmap_last
= 0;
3847 UINT ascent
, descent
, cell_height
;
3848 cmap_type cmap_type
;
3849 BOOL sys_lang_non_english
;
3851 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3854 SetLastError(0xdeadbeef);
3855 hfont
= CreateFontIndirectA(lf
);
3856 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3858 hfont_old
= SelectObject(hdc
, hfont
);
3860 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3861 if (size
== GDI_ERROR
)
3863 trace("OS/2 chunk was not found\n");
3866 if (size
> sizeof(tt_os2
))
3868 trace("got too large OS/2 chunk of size %u\n", size
);
3869 size
= sizeof(tt_os2
);
3872 memset(&tt_os2
, 0, sizeof(tt_os2
));
3873 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3874 ok(ret
>= TT_OS2_V0_SIZE
&& ret
<= size
, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE
,
3877 SetLastError(0xdeadbeef);
3878 ret
= GetTextMetricsA(hdc
, &tmA
);
3879 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3881 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3883 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3887 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3888 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3889 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3893 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3894 descent
= abs((SHORT
)GET_BE_WORD(tt_os2
.usWinDescent
));
3895 cell_height
= ascent
+ descent
;
3896 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3897 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3899 version
= GET_BE_WORD(tt_os2
.version
);
3901 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3902 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3903 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3904 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3906 if (winetest_debug
> 1)
3907 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3908 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3909 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3911 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3916 case 1255: /* Hebrew */
3917 expect_last_W
= 0xf896;
3919 case 1257: /* Baltic */
3920 expect_last_W
= 0xf8fd;
3923 expect_last_W
= 0xf0ff;
3925 expect_break_W
= 0x20;
3926 expect_default_W
= expect_break_W
- 1;
3927 expect_first_A
= 0x1e;
3928 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3932 expect_first_W
= cmap_first
;
3933 expect_last_W
= cmap_last
;
3934 if(os2_first_char
<= 1)
3935 expect_break_W
= os2_first_char
+ 2;
3936 else if(os2_first_char
> 0xff)
3937 expect_break_W
= 0x20;
3939 expect_break_W
= os2_first_char
;
3940 expect_default_W
= expect_break_W
- 1;
3941 expect_first_A
= expect_default_W
- 1;
3942 expect_last_A
= min(expect_last_W
, 0xff);
3944 expect_break_A
= expect_break_W
;
3945 expect_default_A
= expect_default_W
;
3947 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3948 todo_wine_if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3949 ok(tmA
.tmFirstChar
== expect_first_A
||
3950 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3951 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3952 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3953 ok(tmA
.tmLastChar
== expect_last_A
||
3954 tmA
.tmLastChar
== 0xff /* win9x */,
3955 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3957 skip("tmLastChar is DBCS lead byte\n");
3958 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3959 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3960 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3961 "A: tmDefaultChar for %s got %02x expected %02x\n",
3962 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3965 SetLastError(0xdeadbeef);
3966 ret
= GetTextMetricsW(hdc
, &tmW
);
3967 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3968 "GetTextMetricsW error %u\n", GetLastError());
3971 /* Wine uses the os2 first char */
3972 todo_wine_if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3973 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3974 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3976 /* Wine uses the os2 last char */
3977 todo_wine_if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3978 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3979 font_name
, tmW
.tmLastChar
, expect_last_W
);
3980 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3981 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3982 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3983 "W: tmDefaultChar for %s got %02x expected %02x\n",
3984 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3986 /* Test the aspect ratio while we have tmW */
3987 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3988 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3989 tmW
.tmDigitizedAspectX
, ret
);
3990 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3991 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3992 tmW
.tmDigitizedAspectX
, ret
);
3996 /* test FF_ values */
3997 switch(tt_os2
.panose
.bFamilyType
)
4001 case PAN_FAMILY_TEXT_DISPLAY
:
4002 case PAN_FAMILY_PICTORIAL
:
4004 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
4005 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
4007 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
4010 switch(tt_os2
.panose
.bSerifStyle
)
4015 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
4018 case PAN_SERIF_COVE
:
4019 case PAN_SERIF_OBTUSE_COVE
:
4020 case PAN_SERIF_SQUARE_COVE
:
4021 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
4022 case PAN_SERIF_SQUARE
:
4023 case PAN_SERIF_THIN
:
4024 case PAN_SERIF_BONE
:
4025 case PAN_SERIF_EXAGGERATED
:
4026 case PAN_SERIF_TRIANGLE
:
4027 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
4030 case PAN_SERIF_NORMAL_SANS
:
4031 case PAN_SERIF_OBTUSE_SANS
:
4032 case PAN_SERIF_PERP_SANS
:
4033 case PAN_SERIF_FLARED
:
4034 case PAN_SERIF_ROUNDED
:
4035 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
4040 case PAN_FAMILY_SCRIPT
:
4041 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
4044 case PAN_FAMILY_DECORATIVE
:
4045 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
4049 test_negative_width(hdc
, lf
);
4052 SelectObject(hdc
, hfont_old
);
4053 DeleteObject(hfont
);
4058 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4060 INT
*enumed
= (INT
*)lParam
;
4062 if (type
== TRUETYPE_FONTTYPE
)
4065 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
4070 static void test_GetTextMetrics(void)
4078 memset(&lf
, 0, sizeof(lf
));
4079 lf
.lfCharSet
= DEFAULT_CHARSET
;
4081 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
4086 static void test_nonexistent_font(void)
4094 { "Times New Roman Baltic", 186 },
4095 { "Times New Roman CE", 238 },
4096 { "Times New Roman CYR", 204 },
4097 { "Times New Roman Greek", 161 },
4098 { "Times New Roman TUR", 162 }
4106 { "MS Shell Dlg", 186 },
4107 { "MS Shell Dlg", 238 },
4108 { "MS Shell Dlg", 204 },
4109 { "MS Shell Dlg", 161 },
4110 { "MS Shell Dlg", 162 }
4116 INT cs
, expected_cs
, i
, ret
;
4117 char buf
[LF_FACESIZE
];
4119 expected_cs
= GetACP();
4120 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
4122 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
4125 expected_cs
= csi
.ciCharset
;
4126 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
4128 hdc
= CreateCompatibleDC(0);
4130 for (i
= 0; i
< ARRAY_SIZE(shell_subst
); i
++)
4132 ret
= is_font_installed(shell_subst
[i
].name
);
4133 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4134 ret
= is_truetype_font_installed(shell_subst
[i
].name
);
4135 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4137 memset(&lf
, 0, sizeof(lf
));
4139 lf
.lfWeight
= FW_REGULAR
;
4140 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4141 hfont
= CreateFontIndirectA(&lf
);
4142 hfont
= SelectObject(hdc
, hfont
);
4143 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4144 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4145 cs
= GetTextCharset(hdc
);
4146 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, shell_subst
[i
].name
);
4148 DeleteObject(SelectObject(hdc
, hfont
));
4150 memset(&lf
, 0, sizeof(lf
));
4152 lf
.lfWeight
= FW_DONTCARE
;
4153 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4154 hfont
= CreateFontIndirectA(&lf
);
4155 hfont
= SelectObject(hdc
, hfont
);
4156 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4157 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4158 cs
= GetTextCharset(hdc
);
4159 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, shell_subst
[i
].name
);
4160 DeleteObject(SelectObject(hdc
, hfont
));
4163 if (!is_truetype_font_installed("Arial") ||
4164 !is_truetype_font_installed("Times New Roman"))
4167 skip("Arial or Times New Roman not installed\n");
4171 memset(&lf
, 0, sizeof(lf
));
4173 lf
.lfWeight
= FW_REGULAR
;
4174 lf
.lfCharSet
= ANSI_CHARSET
;
4175 lf
.lfPitchAndFamily
= FF_SWISS
;
4176 strcpy(lf
.lfFaceName
, "Nonexistent font");
4177 hfont
= CreateFontIndirectA(&lf
);
4178 hfont
= SelectObject(hdc
, hfont
);
4179 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4180 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
4181 cs
= GetTextCharset(hdc
);
4182 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4183 DeleteObject(SelectObject(hdc
, hfont
));
4185 memset(&lf
, 0, sizeof(lf
));
4187 lf
.lfWeight
= FW_DONTCARE
;
4188 strcpy(lf
.lfFaceName
, "Nonexistent font");
4189 hfont
= CreateFontIndirectA(&lf
);
4190 hfont
= SelectObject(hdc
, hfont
);
4191 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4192 todo_wine
/* Wine uses Arial for all substitutions */
4193 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
4194 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
4195 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4197 cs
= GetTextCharset(hdc
);
4198 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
4199 DeleteObject(SelectObject(hdc
, hfont
));
4201 memset(&lf
, 0, sizeof(lf
));
4203 lf
.lfWeight
= FW_REGULAR
;
4204 strcpy(lf
.lfFaceName
, "Nonexistent font");
4205 hfont
= CreateFontIndirectA(&lf
);
4206 hfont
= SelectObject(hdc
, hfont
);
4207 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4208 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4209 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
4210 cs
= GetTextCharset(hdc
);
4211 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4212 DeleteObject(SelectObject(hdc
, hfont
));
4214 memset(&lf
, 0, sizeof(lf
));
4216 lf
.lfWeight
= FW_DONTCARE
;
4217 strcpy(lf
.lfFaceName
, "Times New Roman");
4218 hfont
= CreateFontIndirectA(&lf
);
4219 hfont
= SelectObject(hdc
, hfont
);
4220 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4221 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
4222 cs
= GetTextCharset(hdc
);
4223 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4224 DeleteObject(SelectObject(hdc
, hfont
));
4226 for (i
= 0; i
< ARRAY_SIZE(font_subst
); i
++)
4228 ret
= is_font_installed(font_subst
[i
].name
);
4230 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4231 "%s should be enumerated\n", font_subst
[i
].name
);
4232 ret
= is_truetype_font_installed(font_subst
[i
].name
);
4234 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4235 "%s should be enumerated\n", font_subst
[i
].name
);
4237 memset(&lf
, 0, sizeof(lf
));
4239 lf
.lfWeight
= FW_REGULAR
;
4240 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4241 hfont
= CreateFontIndirectA(&lf
);
4242 hfont
= SelectObject(hdc
, hfont
);
4243 cs
= GetTextCharset(hdc
);
4244 if (font_subst
[i
].charset
== expected_cs
)
4246 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4247 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4248 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
4252 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
4253 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4254 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4255 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
4257 DeleteObject(SelectObject(hdc
, hfont
));
4259 memset(&lf
, 0, sizeof(lf
));
4261 lf
.lfWeight
= FW_DONTCARE
;
4262 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4263 hfont
= CreateFontIndirectA(&lf
);
4264 hfont
= SelectObject(hdc
, hfont
);
4265 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4266 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
4267 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
4268 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
4269 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4270 "got %s for font %s\n", buf
, font_subst
[i
].name
);
4271 cs
= GetTextCharset(hdc
);
4272 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4273 DeleteObject(SelectObject(hdc
, hfont
));
4279 struct font_realization_info
4294 WCHAR path
[MAX_PATH
];
4297 static void test_RealizationInfo(void)
4299 struct realization_info_t
4306 struct file_info file_info
;
4308 DWORD info
[4], info2
[32], read
;
4309 HFONT hfont
, hfont_old
;
4313 BYTE file
[16], data
[14];
4318 if(!pGdiRealizationInfo
)
4320 win_skip("GdiRealizationInfo not available\n");
4326 memset(info
, 0xcc, sizeof(info
));
4327 r
= pGdiRealizationInfo(hdc
, info
);
4328 ok(r
!= 0, "ret 0\n");
4329 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
4330 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4332 if (!is_truetype_font_installed("Tahoma"))
4334 skip("skipping GdiRealizationInfo with truetype font\n");
4338 memset(&lf
, 0, sizeof(lf
));
4339 strcpy(lf
.lfFaceName
, "Tahoma");
4341 lf
.lfWeight
= FW_BOLD
;
4343 hfont
= CreateFontIndirectA(&lf
);
4344 hfont_old
= SelectObject(hdc
, hfont
);
4346 memset(info
, 0xcc, sizeof(info
));
4347 r
= pGdiRealizationInfo(hdc
, info
);
4348 ok(r
!= 0, "ret 0\n");
4349 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
4350 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4352 if (pGetFontRealizationInfo
)
4354 struct font_realization_info
*fri
= (struct font_realization_info
*)info2
;
4355 struct realization_info_t
*ri
= (struct realization_info_t
*)info
;
4357 /* The first DWORD represents a struct size. On a
4358 newly rebooted system setting this to < 16 results
4359 in GetFontRealizationInfo failing. However there
4360 appears to be some caching going on which results
4361 in calls after a successful call also succeeding even
4362 if the size < 16. This means we can't reliably test
4365 memset(info2
, 0xcc, sizeof(info2
));
4367 r
= pGetFontRealizationInfo(hdc
, info2
);
4368 ok(r
!= 0, "ret 0\n");
4369 /* We may get the '24' version here if that has been previously
4371 ok(fri
->size
== 16 || fri
->size
== 24, "got %d\n", info2
[0]);
4372 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4373 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4374 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4375 ok(info2
[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2
[6]);
4377 memset(info2
, 0xcc, sizeof(info2
));
4379 r
= pGetFontRealizationInfo(hdc
, info2
);
4380 ok(r
== FALSE
, "got %d\n", r
);
4382 memset(info2
, 0xcc, sizeof(info2
));
4384 r
= pGetFontRealizationInfo(hdc
, info2
);
4385 ok(r
!= 0, "ret 0\n");
4386 ok(fri
->size
== 24, "got %d\n", fri
->size
);
4387 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4388 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4389 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4390 ok(fri
->simulations
== 0x2, "got simulations flags 0x%04x\n", fri
->simulations
);
4391 ok(fri
->face_index
== 0, "got wrong face index %u\n", fri
->face_index
);
4392 ok(info2
[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4394 /* Test GetFontFileInfo() */
4395 /* invalid font id */
4396 SetLastError(0xdeadbeef);
4397 r
= pGetFontFileInfo(0xabababab, 0, &file_info
, sizeof(file_info
), &needed
);
4398 ok(r
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "ret %d gle %d\n", r
, GetLastError());
4401 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, sizeof(file_info
), &needed
);
4402 ok(r
!= 0, "Failed to get font file info, error %d.\n", GetLastError());
4406 ok(needed
> 0 && needed
< sizeof(file_info
), "Unexpected required size.\n");
4408 h
= CreateFileW(file_info
.path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
4409 ok(h
!= INVALID_HANDLE_VALUE
, "Unable to open file %d\n", GetLastError());
4411 GetFileTime(h
, NULL
, NULL
, &time
);
4412 ok(!CompareFileTime(&file_info
.time
, &time
), "time mismatch\n");
4413 GetFileSizeEx(h
, &size
);
4414 ok(file_info
.size
.QuadPart
== size
.QuadPart
, "size mismatch\n");
4416 /* Read first 16 bytes from the file */
4417 ReadFile(h
, file
, sizeof(file
), &read
, NULL
);
4420 /* shorter buffer */
4421 SetLastError(0xdeadbeef);
4422 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, needed
- 1, &needed
);
4423 ok(r
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "ret %d gle %d\n", r
, GetLastError());
4426 /* Get bytes 2 - 16 using GetFontFileData */
4427 r
= pGetFontFileData(fri
->instance_id
, 0, 2, data
, sizeof(data
));
4428 ok(r
!= 0, "ret 0 gle %d\n", GetLastError());
4430 ok(!memcmp(data
, file
+ 2, sizeof(data
)), "mismatch\n");
4433 DeleteObject(SelectObject(hdc
, hfont_old
));
4439 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4440 the nul in the count of characters copied when the face name buffer is not
4441 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4442 always includes it. */
4443 static void test_GetTextFace(void)
4445 static const char faceA
[] = "Tahoma";
4446 static const WCHAR faceW
[] = L
"Tahoma";
4449 char bufA
[LF_FACESIZE
];
4450 WCHAR bufW
[LF_FACESIZE
];
4455 if(!is_font_installed("Tahoma"))
4457 skip("Tahoma is not installed so skipping this test\n");
4462 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
4463 f
= CreateFontIndirectA(&fA
);
4464 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
4467 g
= SelectObject(dc
, f
);
4468 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
4469 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
4470 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
4472 /* Play with the count arg. */
4474 n
= GetTextFaceA(dc
, 0, bufA
);
4475 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4476 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4479 n
= GetTextFaceA(dc
, 1, bufA
);
4480 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4481 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4483 bufA
[0] = 'x'; bufA
[1] = 'y';
4484 n
= GetTextFaceA(dc
, 2, bufA
);
4485 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
4486 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
4488 n
= GetTextFaceA(dc
, 0, NULL
);
4489 ok(n
== sizeof faceA
||
4490 broken(n
== 0), /* win98, winMe */
4491 "GetTextFaceA returned %d\n", n
);
4493 DeleteObject(SelectObject(dc
, g
));
4494 ReleaseDC(NULL
, dc
);
4497 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
4498 SetLastError(0xdeadbeef);
4499 f
= CreateFontIndirectW(&fW
);
4500 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4502 win_skip("CreateFontIndirectW is not implemented\n");
4505 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
4508 g
= SelectObject(dc
, f
);
4509 n
= GetTextFaceW(dc
, ARRAY_SIZE(bufW
), bufW
);
4510 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4511 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
4513 /* Play with the count arg. */
4515 n
= GetTextFaceW(dc
, 0, bufW
);
4516 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
4517 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4520 n
= GetTextFaceW(dc
, 1, bufW
);
4521 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
4522 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4524 bufW
[0] = 'x'; bufW
[1] = 'y';
4525 n
= GetTextFaceW(dc
, 2, bufW
);
4526 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4527 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4529 n
= GetTextFaceW(dc
, 0, NULL
);
4530 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4532 DeleteObject(SelectObject(dc
, g
));
4533 ReleaseDC(NULL
, dc
);
4536 static void test_orientation(void)
4538 static const char test_str
[11] = "Test String";
4541 HFONT hfont
, old_hfont
;
4544 if (!is_truetype_font_installed("Arial"))
4546 skip("Arial is not installed\n");
4550 hdc
= CreateCompatibleDC(0);
4551 memset(&lf
, 0, sizeof(lf
));
4552 lstrcpyA(lf
.lfFaceName
, "Arial");
4554 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4555 hfont
= create_font("orientation", &lf
);
4556 old_hfont
= SelectObject(hdc
, hfont
);
4557 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4558 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4559 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4560 SelectObject(hdc
, old_hfont
);
4561 DeleteObject(hfont
);
4565 static void test_oemcharset(void)
4569 HFONT hfont
, old_hfont
;
4572 hdc
= CreateCompatibleDC(0);
4573 ZeroMemory(&lf
, sizeof(lf
));
4575 lf
.lfCharSet
= OEM_CHARSET
;
4576 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4577 lstrcpyA(lf
.lfFaceName
, "Terminal");
4578 hfont
= CreateFontIndirectA(&lf
);
4579 old_hfont
= SelectObject(hdc
, hfont
);
4580 charset
= GetTextCharset(hdc
);
4582 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4583 hfont
= SelectObject(hdc
, old_hfont
);
4584 GetObjectA(hfont
, sizeof(clf
), &clf
);
4585 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4586 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4587 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4588 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4589 DeleteObject(hfont
);
4593 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4594 const TEXTMETRICA
*lpntme
,
4595 DWORD FontType
, LPARAM lParam
)
4597 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4599 LOGFONTA lf
= *lpelfe
;
4603 /* skip bitmap, proportional or vertical font */
4604 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4605 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4606 lf
.lfFaceName
[0] == '@')
4609 /* skip linked font */
4610 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4611 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4614 /* skip linked font, like SimSun-ExtB */
4615 switch (lpelfe
->lfCharSet
) {
4616 case SHIFTJIS_CHARSET
:
4617 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4619 case GB2312_CHARSET
:
4620 case CHINESEBIG5_CHARSET
:
4621 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4623 case HANGEUL_CHARSET
:
4624 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4627 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4633 /* test with an odd height */
4636 hfont
= CreateFontIndirectA(&lf
);
4639 *(HFONT
*)lParam
= hfont
;
4645 static void test_GetGlyphOutline(void)
4648 GLYPHMETRICS gm
, gm2
;
4650 HFONT hfont
, old_hfont
;
4652 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4653 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4661 {ANSI_CHARSET
, 0x30, 0x30},
4662 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4663 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4664 {GB2312_CHARSET
, 0x8141, 0x4e04},
4665 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4669 if (!is_truetype_font_installed("Tahoma"))
4671 skip("Tahoma is not installed\n");
4675 hdc
= CreateCompatibleDC(0);
4676 memset(&lf
, 0, sizeof(lf
));
4678 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4679 SetLastError(0xdeadbeef);
4680 hfont
= CreateFontIndirectA(&lf
);
4681 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4682 old_hfont
= SelectObject(hdc
, hfont
);
4684 memset(&gm
, 0, sizeof(gm
));
4685 SetLastError(0xdeadbeef);
4686 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4687 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4689 memset(&gm
, 0, sizeof(gm
));
4690 SetLastError(0xdeadbeef);
4691 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4692 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4693 ok(GetLastError() == 0xdeadbeef ||
4694 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4695 "expected 0xdeadbeef, got %u\n", GetLastError());
4697 memset(&gm
, 0, sizeof(gm
));
4698 SetLastError(0xdeadbeef);
4699 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4700 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4701 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4703 memset(&gm
, 0, sizeof(gm
));
4704 SetLastError(0xdeadbeef);
4705 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4706 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4708 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4709 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4712 /* test for needed buffer size request on space char */
4713 memset(&gm
, 0, sizeof(gm
));
4714 SetLastError(0xdeadbeef);
4715 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4716 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4718 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4719 ok(gm
.gmBlackBoxX
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxX
);
4720 ok(gm
.gmBlackBoxY
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxY
);
4723 /* requesting buffer size for space char + error */
4724 memset(&gm
, 0, sizeof(gm
));
4725 SetLastError(0xdeadbeef);
4726 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4727 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4729 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4730 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4731 ok(gm
.gmBlackBoxX
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxX
);
4732 ok(gm
.gmBlackBoxY
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxY
);
4735 /* test GetGlyphOutline with a buffer too small */
4736 SetLastError(0xdeadbeef);
4737 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_NATIVE
, &gm
, sizeof(i
), &i
, &mat
);
4738 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4739 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4741 for (i
= 0; i
< ARRAY_SIZE(fmt
); ++i
)
4745 memset(&gm
, 0xab, sizeof(gm
));
4746 SetLastError(0xdeadbeef);
4747 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4748 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4750 if (fmt
[i
] == GGO_METRICS
)
4751 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4753 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4754 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4755 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4758 memset(&gm
, 0xab, sizeof(gm
));
4759 SetLastError(0xdeadbeef);
4760 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4761 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4763 if (fmt
[i
] == GGO_METRICS
)
4764 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4766 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4767 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4768 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4771 memset(&gm
, 0xab, sizeof(gm
));
4772 SetLastError(0xdeadbeef);
4773 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4774 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4776 if (fmt
[i
] == GGO_METRICS
)
4777 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4779 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4780 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4781 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4784 memset(&gm
, 0xab, sizeof(gm
));
4785 SetLastError(0xdeadbeef);
4786 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4787 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4789 if (fmt
[i
] == GGO_METRICS
) {
4790 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4791 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4792 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4796 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4797 memset(&gm2
, 0xab, sizeof(gm2
));
4798 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4799 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4804 SelectObject(hdc
, old_hfont
);
4805 DeleteObject(hfont
);
4807 for (i
= 0; i
< ARRAY_SIZE(c
); ++i
)
4809 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4812 lf
.lfFaceName
[0] = '\0';
4813 lf
.lfCharSet
= c
[i
].cs
;
4814 lf
.lfPitchAndFamily
= 0;
4815 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4817 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4821 old_hfont
= SelectObject(hdc
, hfont
);
4823 /* expected to ignore superfluous bytes (single-byte character) */
4824 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4825 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4826 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4828 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4829 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4830 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4832 /* expected to ignore superfluous bytes (double-byte character) */
4833 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4834 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4835 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4836 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4838 /* expected to match wide-char version results */
4839 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4840 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4842 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4844 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4847 DeleteObject(SelectObject(hdc
, hfont
));
4850 DeleteObject(SelectObject(hdc
, old_hfont
));
4854 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4855 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4857 ret
= GetTextMetricsA(hdc
, &tm
);
4858 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4859 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4860 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4861 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4862 "expected %d, got %d (%s:%d)\n",
4863 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4865 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4866 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4867 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4868 "expected %d, got %d (%s:%d)\n",
4869 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4872 hfont
= CreateFontIndirectA(&lf
);
4873 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4874 DeleteObject(SelectObject(hdc
, hfont
));
4875 ret
= GetTextMetricsA(hdc
, &tm
);
4876 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4877 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4878 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4879 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4880 "expected %d, got %d (%s:%d)\n",
4881 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4883 lf
.lfItalic
= FALSE
;
4884 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4885 hfont
= CreateFontIndirectA(&lf
);
4886 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4887 DeleteObject(SelectObject(hdc
, hfont
));
4888 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4889 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4890 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4891 "expected %d, got %d (%s:%d)\n",
4892 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4894 hfont
= SelectObject(hdc
, old_hfont
);
4895 DeleteObject(hfont
);
4901 /* bug #9995: there is a limit to the character width that can be specified */
4902 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4908 int ave_width
, height
, width
, ratio
;
4910 if (!is_truetype_font_installed( fontname
)) {
4911 skip("%s is not installed\n", fontname
);
4914 hdc
= CreateCompatibleDC(0);
4915 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4916 /* select width = 0 */
4917 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4918 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4919 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4921 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4922 of
= SelectObject( hdc
, hf
);
4923 ret
= GetTextMetricsA( hdc
, &tm
);
4924 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4925 height
= tm
.tmHeight
;
4926 ave_width
= tm
.tmAveCharWidth
;
4927 SelectObject( hdc
, of
);
4930 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4932 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4933 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4934 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4935 ok(hf
!= 0, "CreateFont failed\n");
4936 of
= SelectObject(hdc
, hf
);
4937 ret
= GetTextMetricsA(hdc
, &tm
);
4938 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4939 SelectObject(hdc
, of
);
4942 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4948 ratio
= width
/ height
;
4950 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4953 static void test_GetCharacterPlacement(void)
4955 GCP_RESULTSA result
;
4961 hdc
= CreateCompatibleDC(0);
4962 ok(!!hdc
, "CreateCompatibleDC failed\n");
4964 memset(&result
, 0, sizeof(result
));
4965 result
.lStructSize
= sizeof(result
);
4966 result
.lpCaretPos
= pos
;
4967 result
.lpGlyphs
= glyphs
;
4968 result
.nGlyphs
= 20;
4972 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, &result
, 0);
4973 ok(size
, "GetCharacterPlacementA failed!\n");
4974 ok(result
.nGlyphs
== 9, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
4975 ok(glyphs
[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
4976 ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
4980 result
.nGlyphs
= 20;
4981 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 0, 0, &result
, 0);
4982 ok(!size2
, "Expected GetCharacterPlacementA to fail\n");
4983 ok(result
.nGlyphs
== 20, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
4984 ok(glyphs
[0] == '!', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
4985 ok(pos
[0] == -1, "Unexpected caret position %d\n", pos
[0]);
4987 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, NULL
, 0);
4988 ok(size2
, "GetCharacterPlacementA failed!\n");
4989 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
4991 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, NULL
, GCP_REORDER
);
4992 ok(size2
, "GetCharacterPlacementA failed!\n");
4993 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
4997 result
.nGlyphs
= 20;
4998 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, &result
, GCP_REORDER
);
4999 ok(size
, "GetCharacterPlacementA failed!\n");
5000 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
5001 ok(result
.nGlyphs
== 9, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5002 ok(glyphs
[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5003 todo_wine
ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
5008 static void test_CreateFontIndirect(void)
5010 LOGFONTA lf
, getobj_lf
;
5013 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
5015 memset(&lf
, 0, sizeof(lf
));
5016 lf
.lfCharSet
= ANSI_CHARSET
;
5017 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5020 lf
.lfQuality
= DEFAULT_QUALITY
;
5021 lf
.lfItalic
= FALSE
;
5022 lf
.lfWeight
= FW_DONTCARE
;
5024 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5026 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5027 hfont
= CreateFontIndirectA(&lf
);
5028 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5029 SetLastError(0xdeadbeef);
5030 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
5031 ok(ret
, "GetObject failed: %d\n", GetLastError());
5032 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
5033 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
5034 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
5035 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
5036 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
5037 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
5038 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
5039 DeleteObject(hfont
);
5043 static void test_CreateFontIndirectEx(void)
5045 ENUMLOGFONTEXDVA lfex
;
5048 if (!pCreateFontIndirectExA
)
5050 win_skip("CreateFontIndirectExA is not available\n");
5054 if (!is_truetype_font_installed("Arial"))
5056 skip("Arial is not installed\n");
5060 SetLastError(0xdeadbeef);
5061 hfont
= pCreateFontIndirectExA(NULL
);
5062 ok(hfont
== NULL
, "got %p\n", hfont
);
5063 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
5065 memset(&lfex
, 0, sizeof(lfex
));
5066 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
5067 hfont
= pCreateFontIndirectExA(&lfex
);
5068 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
5070 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
5071 DeleteObject(hfont
);
5074 static void test_realization_info(const char *name
, DWORD size
, BOOL is_memory_resource
)
5076 struct font_realization_info info
;
5077 struct file_info file_info
;
5078 HFONT hfont
, hfont_prev
;
5085 if (!pGetFontRealizationInfo
)
5088 memset(&lf
, 0, sizeof(lf
));
5090 strcpy(lf
.lfFaceName
, name
);
5092 hfont
= CreateFontIndirectA(&lf
);
5093 ok(hfont
!= 0, "Failed to create a font, %u.\n", GetLastError());
5097 hfont_prev
= SelectObject(hdc
, hfont
);
5098 ok(hfont_prev
!= NULL
, "Failed to select font.\n");
5100 memset(&info
, 0xcc, sizeof(info
));
5101 info
.size
= sizeof(info
);
5102 ret
= pGetFontRealizationInfo(hdc
, (DWORD
*)&info
);
5103 ok(ret
!= 0, "Unexpected return value %d.\n", ret
);
5105 ok((info
.flags
& 0xf) == 0x3, "Unexpected flags %#x.\n", info
.flags
);
5106 ok(info
.cache_num
!= 0, "Unexpected cache num %u.\n", info
.cache_num
);
5107 ok(info
.instance_id
!= 0, "Unexpected instance id %u.\n", info
.instance_id
);
5108 ok(info
.simulations
== 0, "Unexpected simulations %#x.\n", info
.simulations
);
5109 ok(info
.face_index
== 0, "Unexpected face index %u.\n", info
.face_index
);
5111 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, NULL
);
5112 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5113 ret
, GetLastError());
5116 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, &needed
);
5117 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5118 ret
, GetLastError());
5120 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, 0, NULL
);
5121 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5122 ret
, GetLastError());
5124 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
- 1, NULL
);
5125 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5126 ret
, GetLastError());
5128 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
, NULL
);
5129 ok(ret
!= 0, "Failed to get font file info, ret %d gle %d.\n", ret
, GetLastError());
5131 memset(&file_info
, 0xcc, sizeof(file_info
));
5132 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, sizeof(file_info
), NULL
);
5133 ok(ret
!= 0, "Failed to get font file info, ret %d gle %d.\n", ret
, GetLastError());
5136 ok(is_memory_resource
? file_info
.size
.QuadPart
== size
: file_info
.size
.QuadPart
> 0, "Unexpected file size.\n");
5137 ok(is_memory_resource
? !file_info
.path
[0] : file_info
.path
[0], "Unexpected file path %s.\n",
5138 wine_dbgstr_w(file_info
.path
));
5141 size
= file_info
.size
.LowPart
;
5142 data
= HeapAlloc(GetProcessHeap(), 0, size
+ 16);
5144 memset(data
, 0xcc, size
);
5145 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
);
5146 ok(ret
!= 0, "Failed to get font file data, %d\n", GetLastError());
5147 ok(*(DWORD
*)data
== 0x00000100, "Unexpected sfnt header version %#x.\n", *(DWORD
*)data
);
5148 ok(*(WORD
*)(data
+ 4) == 0x0e00, "Unexpected table count %#x.\n", *(WORD
*)(data
+ 4));
5150 /* Larger than font data size. */
5151 memset(data
, 0xcc, size
);
5152 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
+ 16);
5153 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %d\n",
5154 ret
, GetLastError());
5155 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5158 memset(data
, 0xcc, size
);
5159 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
- 16);
5160 ok(ret
!= 0, "Failed to get font file data, %d\n", GetLastError());
5161 ok(*(DWORD
*)data
== 0x1000000, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5163 memset(data
, 0xcc, size
);
5164 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
);
5165 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %d\n",
5166 ret
, GetLastError());
5167 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5169 /* Zero buffer size. */
5170 memset(data
, 0xcc, size
);
5171 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, 0);
5173 ok(ret
== 0 && GetLastError() == ERROR_NOACCESS
, "Unexpected return value %d, error %d\n", ret
, GetLastError());
5174 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5176 HeapFree(GetProcessHeap(), 0, data
);
5178 SelectObject(hdc
, hfont_prev
);
5179 DeleteObject(hfont
);
5180 ReleaseDC(NULL
, hdc
);
5183 static void test_AddFontMemResource(void)
5185 char ttf_name
[MAX_PATH
];
5187 DWORD font_size
, num_fonts
;
5191 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
5193 win_skip("AddFontMemResourceEx is not available on this platform\n");
5197 SetLastError(0xdeadbeef);
5198 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
5199 ok(!ret
, "AddFontMemResourceEx should fail\n");
5200 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5201 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5204 SetLastError(0xdeadbeef);
5205 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
5206 ok(!ret
, "AddFontMemResourceEx should fail\n");
5207 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5208 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5211 SetLastError(0xdeadbeef);
5212 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
5213 ok(!ret
, "AddFontMemResourceEx should fail\n");
5214 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5215 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5218 SetLastError(0xdeadbeef);
5219 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
5220 ok(!ret
, "AddFontMemResourceEx should fail\n");
5221 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5222 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5225 /* Now with scalable font */
5226 bRet
= write_ttf_file("wine_test.ttf", ttf_name
);
5227 ok(bRet
, "Failed to create test font file.\n");
5229 font
= load_font(ttf_name
, &font_size
);
5230 ok(font
!= NULL
, "Failed to map font file.\n");
5232 bRet
= is_truetype_font_installed("wine_test");
5233 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5236 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5237 ok(ret
!= 0, "Failed to add resource, %d.\n", GetLastError());
5238 ok(num_fonts
== 1, "Unexpected number of fonts %u.\n", num_fonts
);
5240 bRet
= is_truetype_font_installed("wine_test");
5242 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5244 test_realization_info("wine_test", font_size
, TRUE
);
5246 bRet
= pRemoveFontMemResourceEx(ret
);
5247 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
5251 bRet
= DeleteFileA(ttf_name
);
5252 ok(bRet
, "Failed to delete font file, %d.\n", GetLastError());
5254 font
= load_font("sserife.fon", &font_size
);
5257 skip("Unable to locate and load font sserife.fon\n");
5261 SetLastError(0xdeadbeef);
5262 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
5263 ok(!ret
, "AddFontMemResourceEx should fail\n");
5264 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5265 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5268 SetLastError(0xdeadbeef);
5269 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
5270 ok(!ret
, "AddFontMemResourceEx should fail\n");
5271 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5272 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5275 num_fonts
= 0xdeadbeef;
5276 SetLastError(0xdeadbeef);
5277 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
5278 ok(!ret
, "AddFontMemResourceEx should fail\n");
5279 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5280 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5282 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5284 if (0) /* hangs under windows 2000 */
5286 num_fonts
= 0xdeadbeef;
5287 SetLastError(0xdeadbeef);
5288 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
5289 ok(!ret
, "AddFontMemResourceEx should fail\n");
5290 ok(GetLastError() == 0xdeadbeef,
5291 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5293 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5296 num_fonts
= 0xdeadbeef;
5297 SetLastError(0xdeadbeef);
5298 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5299 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
5300 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5301 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
5305 SetLastError(0xdeadbeef);
5306 bRet
= pRemoveFontMemResourceEx(ret
);
5307 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
5309 /* test invalid pointer to number of loaded fonts */
5310 font
= load_font("sserife.fon", &font_size
);
5311 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
5313 SetLastError(0xdeadbeef);
5314 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
5315 ok(!ret
, "AddFontMemResourceEx should fail\n");
5316 ok(GetLastError() == 0xdeadbeef,
5317 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5320 SetLastError(0xdeadbeef);
5321 ret
= pAddFontMemResourceEx(font
, font_size
, 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",
5330 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5334 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5336 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5338 lf
= (LOGFONTA
*)lparam
;
5343 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5348 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5350 lf
= (LOGFONTA
*)lparam
;
5351 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
5354 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5361 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5366 static void test_EnumFonts(void)
5372 if (!is_truetype_font_installed("Arial"))
5374 skip("Arial is not installed\n");
5378 /* Windows uses localized font face names, so Arial Bold won't be found */
5379 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
5381 skip("User locale is not English, skipping the test\n");
5385 hdc
= CreateCompatibleDC(0);
5387 /* check that the enumproc's retval is returned */
5388 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
5389 ok(ret
== 0xcafe, "got %08x\n", ret
);
5391 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
5392 ok(!ret
, "font Arial is not enumerated\n");
5393 ret
= strcmp(lf
.lfFaceName
, "Arial");
5394 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5395 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5397 strcpy(lf
.lfFaceName
, "Arial");
5398 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5399 ok(!ret
, "font Arial is not enumerated\n");
5400 ret
= strcmp(lf
.lfFaceName
, "Arial");
5401 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5402 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5404 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5405 ok(!ret
, "font Arial Bold is not enumerated\n");
5406 ret
= strcmp(lf
.lfFaceName
, "Arial");
5407 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5408 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5410 strcpy(lf
.lfFaceName
, "Arial Bold");
5411 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5412 ok(ret
, "font Arial Bold should not be enumerated\n");
5414 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
5415 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
5416 ret
= strcmp(lf
.lfFaceName
, "Arial");
5417 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5418 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5420 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
5421 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5422 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
5424 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5425 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5427 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
5428 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5429 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5434 static INT CALLBACK
enum_ms_shell_dlg_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5436 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5438 if (0) /* Disabled to limit console spam */
5439 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5440 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5442 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5443 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg") != 0) return 1;
5445 if (efnd
->total
>= efnd
->size
)
5447 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5448 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5449 if (!efnd
->elf
) return 0;
5451 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5455 static INT CALLBACK
enum_ms_shell_dlg2_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5457 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5459 if (0) /* Disabled to limit console spam */
5460 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5461 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5463 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5464 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg 2") != 0) return 1;
5466 if (efnd
->total
>= efnd
->size
)
5468 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5469 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5470 if (!efnd
->elf
) return 0;
5472 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5476 static void test_EnumFonts_subst(void)
5481 struct enum_fullname_data efnd
;
5483 ret
= is_font_installed("MS Shell Dlg");
5484 ok(ret
, "MS Shell Dlg should be enumerated\n");
5485 ret
= is_truetype_font_installed("MS Shell Dlg");
5486 ok(ret
, "MS Shell Dlg should be enumerated as a TrueType font\n");
5488 ret
= is_font_installed("MS Shell Dlg 2");
5489 ok(ret
, "MS Shell Dlg 2 should be enumerated\n");
5490 ret
= is_truetype_font_installed("MS Shell Dlg 2");
5491 ok(ret
, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5493 hdc
= CreateCompatibleDC(0);
5495 memset(&efnd
, 0, sizeof(efnd
));
5496 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5497 ok(ret
, "MS Shell Dlg should not be enumerated\n");
5498 ok(!efnd
.total
, "MS Shell Dlg should not be enumerated\n");
5500 memset(&lf
, 0, sizeof(lf
));
5501 lf
.lfCharSet
= DEFAULT_CHARSET
;
5504 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
5505 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5506 ok(!ret
, "MS Shell Dlg should be enumerated\n");
5507 ok(efnd
.total
> 0, "MS Shell Dlg should be enumerated\n");
5510 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
5511 ok(!ret
, "expected MS Shell Dlg, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5512 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
5513 ok(ret
, "did not expect MS Shell Dlg\n");
5517 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5518 ok(ret
, "MS Shell Dlg 2 should not be enumerated\n");
5519 ok(!efnd
.total
, "MS Shell Dlg 2 should not be enumerated\n");
5522 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
5523 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5524 ok(!ret
, "MS Shell Dlg 2 should be enumerated\n");
5525 ok(efnd
.total
> 0, "MS Shell Dlg 2 should be enumerated\n");
5528 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
5529 ok(!ret
, "expected MS Shell Dlg 2, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5530 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
5531 ok(ret
, "did not expect MS Shell Dlg 2\n");
5534 heap_free(efnd
.elf
);
5538 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5540 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
5541 const char *fullname
= (const char *)lParam
;
5543 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
5548 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
5553 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
5560 static void test_fullname(void)
5562 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5563 WCHAR bufW
[LF_FULLFACESIZE
];
5564 char bufA
[LF_FULLFACESIZE
];
5571 hdc
= CreateCompatibleDC(0);
5572 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5574 memset(&lf
, 0, sizeof(lf
));
5575 lf
.lfCharSet
= ANSI_CHARSET
;
5576 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5579 lf
.lfQuality
= DEFAULT_QUALITY
;
5580 lf
.lfItalic
= FALSE
;
5581 lf
.lfWeight
= FW_DONTCARE
;
5583 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5585 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
5587 skip("%s is not installed\n", TestName
[i
]);
5591 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5592 hfont
= CreateFontIndirectA(&lf
);
5593 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5595 of
= SelectObject(hdc
, hfont
);
5598 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5599 ok(ret
, "face full name could not be read\n");
5600 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
5601 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
5602 SelectObject(hdc
, of
);
5603 DeleteObject(hfont
);
5608 static WCHAR
*prepend_at(WCHAR
*family
)
5613 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
5618 static void test_fullname2_helper(const char *Family
)
5620 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
5621 struct enum_fullname_data efnd
;
5628 DWORD otm_size
, ret
, buf_size
;
5629 OUTLINETEXTMETRICA
*otm
;
5630 BOOL want_vertical
, get_vertical
;
5631 want_vertical
= ( Family
[0] == '@' );
5633 hdc
= CreateCompatibleDC(0);
5634 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5636 memset(&lf
, 0, sizeof(lf
));
5637 lf
.lfCharSet
= DEFAULT_CHARSET
;
5638 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5641 lf
.lfQuality
= DEFAULT_QUALITY
;
5642 lf
.lfItalic
= FALSE
;
5643 lf
.lfWeight
= FW_DONTCARE
;
5644 strcpy(lf
.lfFaceName
, Family
);
5645 memset(&efnd
, 0, sizeof(efnd
));
5646 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
5647 if (efnd
.total
== 0)
5648 skip("%s is not installed\n", lf
.lfFaceName
);
5650 for (i
= 0; i
< efnd
.total
; i
++)
5652 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
5653 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
5654 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
5656 get_vertical
= ( FamilyName
[0] == '@' );
5657 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
5659 lstrcpyA(lf
.lfFaceName
, FaceName
);
5660 hfont
= CreateFontIndirectA(&lf
);
5661 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5663 of
= SelectObject(hdc
, hfont
);
5664 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
5665 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
5666 if (buf_size
== GDI_ERROR
) continue;
5668 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5669 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5671 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5672 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5673 memset(otm
, 0, otm_size
);
5674 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
5675 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
5676 if (ret
== 0) continue;
5680 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5681 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5682 ok(ret
, "%s: FAMILY (family name) could not be read\n", FamilyName
);
5683 if (want_vertical
) bufW
= prepend_at(bufW
);
5684 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5685 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
5686 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
5687 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
5691 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
5692 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5693 ok(ret
, "FULL_NAME (face name) could not be read\n");
5694 if (want_vertical
) bufW
= prepend_at(bufW
);
5695 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5696 ok(!lstrcmpA(FaceName
, bufA
), "%s: font face names don't match: returned %s, expect %s\n", FamilyName
, FaceName
, bufA
);
5697 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
5698 ok(!lstrcmpA(FaceName
, otmStr
), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName
, FaceName
, otmStr
);
5702 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5703 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5704 ok(ret
, "%s: SUBFAMILY (style name) could not be read\n", FamilyName
);
5705 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5706 ok(!lstrcmpA(StyleName
, bufA
), "%s: style names don't match: returned %s, expect %s\n", FamilyName
, StyleName
, bufA
);
5707 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
5708 ok(!lstrcmpA(StyleName
, otmStr
), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName
, StyleName
, otmStr
);
5712 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
5713 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5714 ok(ret
, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName
);
5715 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5716 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
5717 ok(!lstrcmpA(otmStr
, bufA
), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName
, otmStr
, bufA
);
5719 SelectObject(hdc
, of
);
5720 DeleteObject(hfont
);
5722 HeapFree(GetProcessHeap(), 0, otm
);
5723 HeapFree(GetProcessHeap(), 0, bufW
);
5724 HeapFree(GetProcessHeap(), 0, bufA
);
5726 heap_free(efnd
.elf
);
5730 static void test_fullname2(void)
5732 test_fullname2_helper("Arial");
5733 test_fullname2_helper("DejaVu Sans");
5734 test_fullname2_helper("Lucida Sans");
5735 test_fullname2_helper("Tahoma");
5736 test_fullname2_helper("Webdings");
5737 test_fullname2_helper("Wingdings");
5738 test_fullname2_helper("SimSun");
5739 test_fullname2_helper("NSimSun");
5740 test_fullname2_helper("MingLiu");
5741 test_fullname2_helper("PMingLiu");
5742 test_fullname2_helper("WenQuanYi Micro Hei");
5743 test_fullname2_helper("MS UI Gothic");
5744 test_fullname2_helper("Ume UI Gothic");
5745 test_fullname2_helper("MS Gothic");
5746 test_fullname2_helper("Ume Gothic");
5747 test_fullname2_helper("MS PGothic");
5748 test_fullname2_helper("Ume P Gothic");
5749 test_fullname2_helper("Gulim");
5750 test_fullname2_helper("Batang");
5751 test_fullname2_helper("UnBatang");
5752 test_fullname2_helper("UnDotum");
5753 test_fullname2_helper("@SimSun");
5754 test_fullname2_helper("@NSimSun");
5755 test_fullname2_helper("@MingLiu");
5756 test_fullname2_helper("@PMingLiu");
5757 test_fullname2_helper("@WenQuanYi Micro Hei");
5758 test_fullname2_helper("@MS UI Gothic");
5759 test_fullname2_helper("@Ume UI Gothic");
5760 test_fullname2_helper("@MS Gothic");
5761 test_fullname2_helper("@Ume Gothic");
5762 test_fullname2_helper("@MS PGothic");
5763 test_fullname2_helper("@Ume P Gothic");
5764 test_fullname2_helper("@Gulim");
5765 test_fullname2_helper("@Batang");
5766 test_fullname2_helper("@UnBatang");
5767 test_fullname2_helper("@UnDotum");
5771 static void test_GetGlyphOutline_empty_contour(void)
5775 HFONT hfont
, hfont_prev
;
5776 TTPOLYGONHEADER
*header
;
5781 memset(&lf
, 0, sizeof(lf
));
5783 lstrcpyA(lf
.lfFaceName
, "wine_test");
5785 hfont
= CreateFontIndirectA(&lf
);
5786 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5790 hfont_prev
= SelectObject(hdc
, hfont
);
5791 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5793 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5794 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5796 header
= (TTPOLYGONHEADER
*)buf
;
5797 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5798 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5799 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5800 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5801 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5802 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5803 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5804 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5806 SelectObject(hdc
, hfont_prev
);
5807 DeleteObject(hfont
);
5808 ReleaseDC(NULL
, hdc
);
5811 static void test_GetGlyphOutline_metric_clipping(void)
5815 HFONT hfont
, hfont_prev
;
5821 memset(&lf
, 0, sizeof(lf
));
5823 lstrcpyA(lf
.lfFaceName
, "wine_test");
5825 SetLastError(0xdeadbeef);
5826 hfont
= CreateFontIndirectA(&lf
);
5827 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5831 hfont_prev
= SelectObject(hdc
, hfont
);
5832 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5834 SetLastError(0xdeadbeef);
5835 ret
= GetTextMetricsA(hdc
, &tm
);
5836 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5838 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5839 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5840 "Glyph top(%d) exceeds ascent(%d)\n",
5841 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5842 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5843 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5844 "Glyph bottom(%d) exceeds descent(%d)\n",
5845 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5847 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5848 GetTextMetricsW(hdc
, &tmW
);
5850 ok( tmW
.tmLastChar
== 0xfffe, "got %04x\n", tmW
.tmLastChar
);
5852 SelectObject(hdc
, hfont_prev
);
5853 DeleteObject(hfont
);
5854 ReleaseDC(NULL
, hdc
);
5857 static void test_GetGlyphOutline_character(void)
5859 HFONT hfont
, hfont_old
;
5863 GLYPHMETRICS gm1
, gm2
, gmn
;
5864 char test_chars
[] = { 'A', 'D', '!', '\0' };
5867 memset(&lf
, 0, sizeof(lf
));
5869 lstrcpyA(lf
.lfFaceName
, "wine_test");
5871 hfont
= CreateFontIndirectA(&lf
);
5872 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5876 hfont_old
= SelectObject(hdc
, hfont
);
5877 ok(hfont_old
!= NULL
, "SelectObject failed\n");
5879 ret
= GetGlyphOutlineW(hdc
, 'Z', GGO_METRICS
, &gmn
, 0, NULL
, &mat
);
5880 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed to default to .notdef for character 'Z'\n");
5882 for (current_char
= test_chars
; *current_char
!= '\0'; current_char
++)
5884 ret
= GetGlyphOutlineW(hdc
, *current_char
, GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
5885 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for '%c'\n", *current_char
);
5886 ok(memcmp(&gm1
, &gmn
, sizeof(gmn
)) != 0, "the test character '%c' matches .notdef\n", *current_char
);
5888 ret
= GetGlyphOutlineW(hdc
, 0x10000 + *current_char
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
5889 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for 0x10000 + '%c'\n", *current_char
);
5890 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for character 0x10000 + '%c'\n", *current_char
);
5893 ret
= GetGlyphOutlineW(hdc
, 0x3, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm1
, 0, NULL
, &mat
);
5894 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for glyph index 0x3\n");
5896 ret
= GetGlyphOutlineW(hdc
, 0xFFFF, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5897 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW for nonexistent glyph index 0xFFFF has succeeded\n");
5899 ret
= GetGlyphOutlineW(hdc
, 0x10003, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5900 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW for index 0x10003 has failed\n");
5901 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for glyph 0x10003\n");
5903 SelectObject(hdc
, hfont_old
);
5904 DeleteObject(hfont
);
5905 ReleaseDC(NULL
, hdc
);
5908 static void test_fstype_fixup(void)
5912 HFONT hfont
, hfont_prev
;
5914 OUTLINETEXTMETRICA
*otm
;
5917 memset(&lf
, 0, sizeof(lf
));
5919 lstrcpyA(lf
.lfFaceName
, "wine_test");
5921 SetLastError(0xdeadbeef);
5922 hfont
= CreateFontIndirectA(&lf
);
5923 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5927 hfont_prev
= SelectObject(hdc
, hfont
);
5928 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5930 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5931 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5932 otm
->otmSize
= sizeof(*otm
);
5933 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
5934 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
5936 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5937 valid bits are 1, 2, 3, 8, 9. */
5938 ok((otm
->otmfsType
& ~0x30e) == 0, "fsType %#x\n", otm
->otmfsType
);
5940 HeapFree(GetProcessHeap(), 0, otm
);
5942 SelectObject(hdc
, hfont_prev
);
5943 DeleteObject(hfont
);
5944 ReleaseDC(NULL
, hdc
);
5947 static void test_CreateScalableFontResource(void)
5949 char ttf_name
[MAX_PATH
];
5950 char tmp_path
[MAX_PATH
];
5951 char fot_name
[MAX_PATH
];
5956 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
5958 win_skip("AddFontResourceExA is not available on this platform\n");
5962 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5964 skip("Failed to create ttf file for testing\n");
5968 trace("created %s\n", ttf_name
);
5970 ret
= is_truetype_font_installed("wine_test");
5971 ok(!ret
, "font wine_test should not be enumerated\n");
5973 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
5974 ok(ret
, "GetTempPath() error %d\n", GetLastError());
5975 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
5976 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
5978 ret
= GetFileAttributesA(fot_name
);
5979 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
5981 SetLastError(0xdeadbeef);
5982 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5983 ok(!ret
, "CreateScalableFontResource() should fail\n");
5984 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5986 SetLastError(0xdeadbeef);
5987 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
5988 ok(!ret
, "CreateScalableFontResource() should fail\n");
5989 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5991 file_part
= strrchr(ttf_name
, '\\');
5992 SetLastError(0xdeadbeef);
5993 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
5994 ok(!ret
, "CreateScalableFontResource() should fail\n");
5995 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
5997 SetLastError(0xdeadbeef);
5998 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
5999 ok(!ret
, "CreateScalableFontResource() should fail\n");
6000 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
6002 SetLastError(0xdeadbeef);
6003 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
6004 ok(!ret
, "CreateScalableFontResource() should fail\n");
6005 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
6007 ret
= DeleteFileA(fot_name
);
6008 ok(ret
, "DeleteFile() error %d\n", GetLastError());
6010 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6011 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6013 /* test public font resource */
6014 SetLastError(0xdeadbeef);
6015 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
6016 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
6018 ret
= is_truetype_font_installed("wine_test");
6019 ok(!ret
, "font wine_test should not be enumerated\n");
6021 SetLastError(0xdeadbeef);
6022 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6023 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6025 ret
= is_truetype_font_installed("wine_test");
6026 ok(ret
, "font wine_test should be enumerated\n");
6028 test_GetGlyphOutline_empty_contour();
6029 test_GetGlyphOutline_metric_clipping();
6030 test_GetGlyphOutline_character();
6031 test_fstype_fixup();
6033 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6034 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
6036 SetLastError(0xdeadbeef);
6037 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6038 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6040 ret
= is_truetype_font_installed("wine_test");
6041 ok(!ret
, "font wine_test should not be enumerated\n");
6043 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6044 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6046 /* test refcounting */
6047 for (i
= 0; i
< 5; i
++)
6049 SetLastError(0xdeadbeef);
6050 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6051 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6053 for (i
= 0; i
< 5; i
++)
6055 SetLastError(0xdeadbeef);
6056 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6057 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6059 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6060 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6062 DeleteFileA(fot_name
);
6064 /* test hidden font resource */
6065 SetLastError(0xdeadbeef);
6066 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
6067 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
6069 ret
= is_truetype_font_installed("wine_test");
6070 ok(!ret
, "font wine_test should not be enumerated\n");
6072 SetLastError(0xdeadbeef);
6073 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6074 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6076 ret
= is_truetype_font_installed("wine_test");
6078 ok(!ret
, "font wine_test should not be enumerated\n");
6080 /* XP allows removing a private font added with 0 flags */
6081 SetLastError(0xdeadbeef);
6082 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6083 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6085 ret
= is_truetype_font_installed("wine_test");
6086 ok(!ret
, "font wine_test should not be enumerated\n");
6088 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6089 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6091 DeleteFileA(fot_name
);
6092 DeleteFileA(ttf_name
);
6095 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
6098 HFONT hfont
, hfont_prev
;
6102 static const WCHAR str
[] = { 0x2025 };
6104 *installed
= is_truetype_font_installed(name
);
6108 lf
.lfEscapement
= 0;
6109 lf
.lfOrientation
= 0;
6110 lf
.lfWeight
= FW_DONTCARE
;
6114 lf
.lfCharSet
= DEFAULT_CHARSET
;
6115 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
6116 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6117 lf
.lfQuality
= DEFAULT_QUALITY
;
6118 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
6119 strcpy(lf
.lfFaceName
, name
);
6121 hfont
= CreateFontIndirectA(&lf
);
6122 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
6126 hfont_prev
= SelectObject(hdc
, hfont
);
6127 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
6129 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
6130 ok(ret
, "GetTextFaceA failed\n");
6131 *selected
= !strcmp(facename
, name
);
6133 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
6134 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6136 memset(gm
, 0, sizeof *gm
);
6138 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
6139 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
6141 SelectObject(hdc
, hfont_prev
);
6142 DeleteObject(hfont
);
6143 ReleaseDC(NULL
, hdc
);
6146 static void check_vertical_metrics(const char *face
)
6149 HFONT hfont
, hfont_prev
;
6152 GLYPHMETRICS rgm
, vgm
;
6153 const UINT code
= 0x5EAD, height
= 1000;
6156 OUTLINETEXTMETRICA otm
;
6157 USHORT numOfLongVerMetrics
;
6161 memset(&lf
, 0, sizeof(lf
));
6162 strcpy(lf
.lfFaceName
, face
);
6163 lf
.lfHeight
= -height
;
6164 lf
.lfCharSet
= DEFAULT_CHARSET
;
6165 lf
.lfEscapement
= lf
.lfOrientation
= 900;
6166 hfont
= CreateFontIndirectA(&lf
);
6167 hfont_prev
= SelectObject(hdc
, hfont
);
6168 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
6169 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6170 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
6171 ok(ret
, "GetCharABCWidthsW failed\n");
6172 DeleteObject(SelectObject(hdc
, hfont_prev
));
6174 memset(&lf
, 0, sizeof(lf
));
6175 strcpy(lf
.lfFaceName
, "@");
6176 strcat(lf
.lfFaceName
, face
);
6177 lf
.lfHeight
= -height
;
6178 lf
.lfCharSet
= DEFAULT_CHARSET
;
6179 hfont
= CreateFontIndirectA(&lf
);
6180 hfont_prev
= SelectObject(hdc
, hfont
);
6181 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
6182 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6183 ret
= GetCharABCWidthsW(hdc
, code
, code
, &vabc
);
6184 ok(ret
, "GetCharABCWidthsW failed\n");
6185 ok(vabc
.abcA
== vgm
.gmptGlyphOrigin
.x
, "expected %d, got %d\n",
6186 vabc
.abcA
, vgm
.gmptGlyphOrigin
.x
);
6187 ok(vabc
.abcB
== vgm
.gmBlackBoxX
, "expected %d, got %d\n",
6188 vabc
.abcB
, vgm
.gmBlackBoxX
);
6189 ok(vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
== vgm
.gmCellIncX
,
6190 "expected %d, got %d\n",
6191 vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
, vgm
.gmCellIncX
);
6193 memset(&otm
, 0, sizeof(otm
));
6194 otm
.otmSize
= sizeof(otm
);
6195 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
6196 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
6198 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
6199 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
6201 SHORT topSideBearing
;
6203 if (!pGetGlyphIndicesW
) {
6204 win_skip("GetGlyphIndices is not available on this platform\n");
6207 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
6208 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
6209 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
6210 if (numOfLongVerMetrics
> idx
)
6211 offset
= idx
* 2 + 1;
6213 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
6214 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
6215 &topSideBearing
, sizeof(SHORT
));
6216 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
6217 topSideBearing
= GET_BE_WORD(topSideBearing
);
6218 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
6219 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
6220 "expected %d, got %d\n",
6221 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
6226 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
6227 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
6228 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
6231 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
6232 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
6233 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6234 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
6236 DeleteObject(SelectObject(hdc
, hfont_prev
));
6237 ReleaseDC(NULL
, hdc
);
6240 static void test_vertical_font(void)
6242 char ttf_name
[MAX_PATH
];
6244 BOOL ret
, installed
, selected
;
6247 const char* face_list
[] = {
6248 "@WineTestVertical", /* has vmtx table */
6249 "@Ume Gothic", /* doesn't have vmtx table */
6250 "@MS UI Gothic", /* has vmtx table, available on native */
6253 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
6255 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
6259 if (!write_ttf_file("vertical.ttf", ttf_name
))
6261 skip("Failed to create ttf file for testing\n");
6265 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6266 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6268 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
6269 ok(installed
, "WineTestVertical is not installed\n");
6270 ok(selected
, "WineTestVertical is not selected\n");
6271 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6272 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6273 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6275 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
6276 ok(installed
, "@WineTestVertical is not installed\n");
6277 ok(selected
, "@WineTestVertical is not selected\n");
6278 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6279 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6280 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6282 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
6284 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++) {
6285 const char* face
= face_list
[i
];
6286 if (!is_truetype_font_installed(face
)) {
6287 skip("%s is not installed\n", face
);
6290 check_vertical_metrics(&face
[1]);
6293 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6294 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6296 DeleteFileA(ttf_name
);
6299 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
6300 DWORD type
, LPARAM lParam
)
6302 if (lf
->lfFaceName
[0] == '@') {
6308 static void test_east_asian_font_selection(void)
6311 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
6312 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
6317 for (i
= 0; i
< ARRAY_SIZE(charset
); i
++)
6321 char face_name
[LF_FACESIZE
];
6324 memset(&lf
, 0, sizeof lf
);
6325 lf
.lfFaceName
[0] = '\0';
6326 lf
.lfCharSet
= charset
[i
];
6328 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
6330 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
6334 hfont
= CreateFontIndirectA(&lf
);
6335 hfont
= SelectObject(hdc
, hfont
);
6336 memset(face_name
, 0, sizeof face_name
);
6337 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6338 ok(ret
&& face_name
[0] != '@',
6339 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6340 DeleteObject(SelectObject(hdc
, hfont
));
6342 memset(&lf
, 0, sizeof lf
);
6343 strcpy(lf
.lfFaceName
, "@");
6344 lf
.lfCharSet
= charset
[i
];
6345 hfont
= CreateFontIndirectA(&lf
);
6346 hfont
= SelectObject(hdc
, hfont
);
6347 memset(face_name
, 0, sizeof face_name
);
6348 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6349 ok(ret
&& face_name
[0] == '@',
6350 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6351 DeleteObject(SelectObject(hdc
, hfont
));
6353 ReleaseDC(NULL
, hdc
);
6356 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
6358 HDC hdc
= CreateCompatibleDC(0);
6363 hfont
= CreateFontIndirectA(lf
);
6364 ok(hfont
!= 0, "CreateFontIndirect failed\n");
6366 SelectObject(hdc
, hfont
);
6367 ret
= GetTextMetricsA(hdc
, &tm
);
6368 ok(ret
, "GetTextMetrics failed\n");
6369 ret
= tm
.tmDigitizedAspectX
;
6370 if (height
) *height
= tm
.tmHeight
;
6373 DeleteObject(hfont
);
6378 static void test_stock_fonts(void)
6380 static const int font
[] =
6382 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
6383 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6385 static const struct test_data
6387 int charset
, weight
, height
, height_pixels
, dpi
;
6388 const char face_name
[LF_FACESIZE
];
6392 { /* ANSI_FIXED_FONT */
6393 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_ARABIC
},
6394 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_HEBREW
},
6395 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
6396 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
6399 { /* ANSI_VAR_FONT */
6400 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
6401 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
6405 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6406 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6407 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6408 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6409 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6410 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6413 { /* DEVICE_DEFAULT_FONT */
6414 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6415 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6416 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6417 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6418 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6419 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6422 { /* DEFAULT_GUI_FONT */
6423 { SHIFTJIS_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6424 { SHIFTJIS_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6425 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
6426 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
6427 { HANGEUL_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6428 { HANGEUL_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6429 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
6430 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
6431 { GB2312_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6432 { GB2312_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6433 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
6434 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
6435 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
6436 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
6437 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6438 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6444 for (i
= 0; i
< ARRAY_SIZE(font
); i
++)
6450 hfont
= GetStockObject(font
[i
]);
6451 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
6453 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
6454 if (ret
!= sizeof(lf
))
6457 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
6461 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
6463 if ((lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
) ||
6464 (system_lang_id
!= td
[i
][j
].lang_id
&& td
[i
][j
].lang_id
!= LANG_NEUTRAL
) ||
6465 (td
[i
][j
].face_name
[0] != '?' && strcmp(lf
.lfFaceName
, td
[i
][j
].face_name
)))
6470 ret
= get_font_dpi(&lf
, &height
);
6471 if (ret
!= td
[i
][j
].dpi
)
6473 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6474 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
6478 /* FIXME: Remove once Wine is fixed */
6479 todo_wine_if (td
[i
][j
].dpi
!= 96 &&
6480 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6481 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
6482 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6483 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
6484 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
6486 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
6487 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
6488 if (td
[i
][j
].face_name
[0] == '?')
6490 /* Wine doesn't have this font, skip this case for now.
6491 Actually, the face name is localized on Windows and varies
6492 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6493 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
6497 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
);
6504 static void test_max_height(void)
6508 HFONT hfont
, hfont_old
;
6509 TEXTMETRICA tm1
, tm
;
6511 LONG invalid_height
[] = { -65536, -123456, 123456 };
6514 memset(&tm1
, 0, sizeof(tm1
));
6515 memset(&lf
, 0, sizeof(lf
));
6516 strcpy(lf
.lfFaceName
, "Tahoma");
6521 /* get 1 ppem value */
6522 hfont
= CreateFontIndirectA(&lf
);
6523 hfont_old
= SelectObject(hdc
, hfont
);
6524 r
= GetTextMetricsA(hdc
, &tm1
);
6525 ok(r
, "GetTextMetrics failed\n");
6526 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6527 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6528 DeleteObject(SelectObject(hdc
, hfont_old
));
6530 /* test the largest value */
6531 lf
.lfHeight
= -((1 << 16) - 1);
6532 hfont
= CreateFontIndirectA(&lf
);
6533 hfont_old
= SelectObject(hdc
, hfont
);
6534 memset(&tm
, 0, sizeof(tm
));
6535 r
= GetTextMetricsA(hdc
, &tm
);
6536 ok(r
, "GetTextMetrics failed\n");
6537 ok(tm
.tmHeight
> tm1
.tmHeight
,
6538 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6539 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
6540 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6541 DeleteObject(SelectObject(hdc
, hfont_old
));
6543 /* test an invalid value */
6544 for (i
= 0; i
< ARRAY_SIZE(invalid_height
); i
++) {
6545 lf
.lfHeight
= invalid_height
[i
];
6546 hfont
= CreateFontIndirectA(&lf
);
6547 hfont_old
= SelectObject(hdc
, hfont
);
6548 memset(&tm
, 0, sizeof(tm
));
6549 r
= GetTextMetricsA(hdc
, &tm
);
6550 ok(r
, "GetTextMetrics failed\n");
6551 ok(tm
.tmHeight
== tm1
.tmHeight
,
6552 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6553 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
6554 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6555 DeleteObject(SelectObject(hdc
, hfont_old
));
6558 ReleaseDC(NULL
, hdc
);
6562 static void test_vertical_order(void)
6564 struct enum_font_data efd
;
6569 hdc
= CreateCompatibleDC(0);
6570 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6572 memset(&lf
, 0, sizeof(lf
));
6573 lf
.lfCharSet
= DEFAULT_CHARSET
;
6574 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6577 lf
.lfQuality
= DEFAULT_QUALITY
;
6578 lf
.lfItalic
= FALSE
;
6579 lf
.lfWeight
= FW_DONTCARE
;
6580 memset( &efd
, 0, sizeof(efd
) );
6581 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
6582 for (i
= 0; i
< efd
.total
; i
++)
6584 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
6585 for (j
= 0; j
< efd
.total
; j
++)
6587 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
6589 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
6594 heap_free( efd
.lf
);
6598 static void test_GetCharWidth32(void)
6608 if (!pGetCharWidth32W
)
6610 win_skip("GetCharWidth32W not available on this platform\n");
6614 memset(&lf
, 0, sizeof(lf
));
6615 strcpy(lf
.lfFaceName
, "System");
6618 hfont
= CreateFontIndirectA(&lf
);
6620 hfont
= SelectObject(hdc
, hfont
);
6622 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6623 ok(ret
, "GetCharWidth32W should have succeeded\n");
6624 ret
= GetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
6625 ok(ret
, "GetCharWidth32A should have succeeded\n");
6626 ok (bufferA
== bufferW
, "Widths should be the same\n");
6627 ok (bufferA
> 0," Width should be greater than zero\n");
6629 hfont
= SelectObject(hdc
, hfont
);
6630 DeleteObject(hfont
);
6631 ReleaseDC(NULL
, hdc
);
6633 memset(&lf
, 0, sizeof(lf
));
6634 strcpy(lf
.lfFaceName
, "Tahoma");
6637 hfont
= CreateFontIndirectA(&lf
);
6638 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
6641 SetMapMode( hdc
, MM_ANISOTROPIC
);
6642 SelectObject(hdc
, hfont
);
6644 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6645 ok(ret
, "GetCharWidth32W should have succeeded\n");
6646 ok (bufferW
> 0," Width should be greater than zero\n");
6647 SetWindowExtEx(hdc
, -1,-1,NULL
);
6648 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6649 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6650 ok(ret
, "GetCharWidth32W should have succeeded\n");
6651 ok (bufferW
> 0," Width should be greater than zero\n");
6652 SetGraphicsMode(hdc
, GM_ADVANCED
);
6653 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6654 ok(ret
, "GetCharWidth32W should have succeeded\n");
6655 ok (bufferW
> 0," Width should be greater than zero\n");
6656 SetWindowExtEx(hdc
, 1,1,NULL
);
6657 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6658 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6659 ok(ret
, "GetCharWidth32W should have succeeded\n");
6660 ok (bufferW
> 0," Width should be greater than zero\n");
6661 SetGraphicsMode(hdc
, GM_ADVANCED
);
6662 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6663 ok(ret
, "GetCharWidth32W should have succeeded\n");
6664 ok (bufferW
> 0," Width should be greater than zero\n");
6666 ReleaseDC(hwnd
, hdc
);
6667 DestroyWindow(hwnd
);
6669 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
6672 SetMapMode( hdc
, MM_ANISOTROPIC
);
6673 SelectObject(hdc
, hfont
);
6675 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6676 ok(ret
, "GetCharWidth32W should have succeeded\n");
6677 ok (bufferW
> 0," Width should be greater than zero\n");
6678 SetWindowExtEx(hdc
, -1,-1,NULL
);
6679 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6680 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6681 ok(ret
, "GetCharWidth32W should have succeeded\n");
6682 ok (bufferW
> 0," Width should be greater than zero\n");
6683 SetGraphicsMode(hdc
, GM_ADVANCED
);
6684 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6685 ok(ret
, "GetCharWidth32W should have succeeded\n");
6686 ok (bufferW
> 0," Width should be greater than zero\n");
6687 SetWindowExtEx(hdc
, 1,1,NULL
);
6688 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6689 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6690 ok(ret
, "GetCharWidth32W should have succeeded\n");
6691 ok (bufferW
> 0," Width should be greater than zero\n");
6692 SetGraphicsMode(hdc
, GM_ADVANCED
);
6693 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6694 ok(ret
, "GetCharWidth32W should have succeeded\n");
6695 ok (bufferW
> 0," Width should be greater than zero\n");
6697 ReleaseDC(hwnd
, hdc
);
6698 DestroyWindow(hwnd
);
6699 DeleteObject(hfont
);
6702 static void test_fake_bold_font(void)
6704 static const MAT2 x2_mat
= { {0,2}, {0,0}, {0,0}, {0,2} };
6717 /* Test outline font */
6718 memset(&lf
, 0, sizeof(lf
));
6719 strcpy(lf
.lfFaceName
, "Wingdings");
6720 lf
.lfCharSet
= SYMBOL_CHARSET
;
6724 for (i
= 0; i
<= 1; i
++)
6726 HFONT hfont
, hfont_old
;
6728 lf
.lfWeight
= i
? FW_BOLD
: FW_NORMAL
;
6729 hfont
= CreateFontIndirectA(&lf
);
6730 hfont_old
= SelectObject(hdc
, hfont
);
6732 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6733 ok(ret
, "got %d\n", ret
);
6734 ret
= GetCharABCWidthsA(hdc
, 0x76, 0x76, &data
[i
].abc
);
6735 ok(ret
, "got %d\n", ret
);
6736 data
[i
].w
= data
[i
].abc
.abcA
+ data
[i
].abc
.abcB
+ data
[i
].abc
.abcC
;
6737 r
= GetGlyphOutlineA(hdc
, 0x76, GGO_METRICS
, &data
[i
].gm
, 0, NULL
, &x2_mat
);
6738 ok(r
!= GDI_ERROR
, "got %d\n", ret
);
6740 SelectObject(hdc
, hfont_old
);
6741 DeleteObject(hfont
);
6743 ReleaseDC(NULL
, hdc
);
6745 /* compare results (outline) */
6746 ok(data
[0].tm
.tmHeight
== data
[1].tm
.tmHeight
,
6747 "expected %d, got %d\n", data
[0].tm
.tmHeight
, data
[1].tm
.tmHeight
);
6748 ok(data
[0].tm
.tmAscent
== data
[1].tm
.tmAscent
,
6749 "expected %d, got %d\n", data
[0].tm
.tmAscent
, data
[1].tm
.tmAscent
);
6750 ok(data
[0].tm
.tmDescent
== data
[1].tm
.tmDescent
,
6751 "expected %d, got %d\n", data
[0].tm
.tmDescent
, data
[1].tm
.tmDescent
);
6752 ok(data
[0].tm
.tmAveCharWidth
+ 1 == data
[1].tm
.tmAveCharWidth
,
6753 "expected %d, got %d\n", data
[0].tm
.tmAveCharWidth
+ 1, data
[1].tm
.tmAveCharWidth
);
6754 ok(data
[0].tm
.tmMaxCharWidth
+ 1 == data
[1].tm
.tmMaxCharWidth
,
6755 "expected %d, got %d\n", data
[0].tm
.tmMaxCharWidth
+ 1, data
[1].tm
.tmMaxCharWidth
);
6756 ok(data
[0].tm
.tmOverhang
== data
[1].tm
.tmOverhang
,
6757 "expected %d, got %d\n", data
[0].tm
.tmOverhang
, data
[1].tm
.tmOverhang
);
6758 ok(data
[0].w
+ 1 == data
[1].w
,
6759 "expected %d, got %d\n", data
[0].w
+ 1, data
[1].w
);
6761 ok(data
[0].gm
.gmCellIncX
+ 1 == data
[1].gm
.gmCellIncX
,
6762 "expected %d, got %d\n", data
[0].gm
.gmCellIncX
+ 1, data
[1].gm
.gmCellIncX
);
6763 ok(data
[0].gm
.gmCellIncY
== data
[1].gm
.gmCellIncY
,
6764 "expected %d, got %d\n", data
[0].gm
.gmCellIncY
, data
[1].gm
.gmCellIncY
);
6766 /* Test bitmap font */
6767 memset(&data
, 0xaa, sizeof(data
));
6768 memset(&lf
, 0, sizeof(lf
));
6769 strcpy(lf
.lfFaceName
, "Courier");
6770 lf
.lfCharSet
= ANSI_CHARSET
;
6774 for (i
= 0; i
< 4; i
++)
6776 HFONT hfont
, hfont_old
;
6778 lf
.lfWeight
= (i
% 2) ? FW_BOLD
: FW_NORMAL
;
6779 lf
.lfHeight
= (i
> 1) ? data
[0].tm
.tmHeight
* x2_mat
.eM11
.value
: 0;
6780 hfont
= CreateFontIndirectA(&lf
);
6781 hfont_old
= SelectObject(hdc
, hfont
);
6783 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6784 ok(ret
, "got %d\n", ret
);
6785 ret
= GetCharWidth32A(hdc
, 0x76, 0x76, &data
[i
].w
);
6786 ok(ret
, "got %d\n", ret
);
6788 SelectObject(hdc
, hfont_old
);
6789 DeleteObject(hfont
);
6791 ReleaseDC(NULL
, hdc
);
6793 /* compare results (bitmap) */
6794 for (i
= 0; i
< 4; i
+=2)
6796 int diff
= (i
> 1) ? x2_mat
.eM11
.value
: 1;
6797 if (data
[i
].tm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
6799 skip("TrueType font is selected (expected a bitmap one)\n");
6802 ok(data
[i
].tm
.tmHeight
== data
[i
+1].tm
.tmHeight
,
6803 "expected %d, got %d\n", data
[i
].tm
.tmHeight
, data
[i
+1].tm
.tmHeight
);
6804 ok(data
[i
].tm
.tmAscent
== data
[i
+1].tm
.tmAscent
,
6805 "expected %d, got %d\n", data
[i
].tm
.tmAscent
, data
[i
+1].tm
.tmAscent
);
6806 ok(data
[i
].tm
.tmDescent
== data
[i
+1].tm
.tmDescent
,
6807 "expected %d, got %d\n", data
[i
].tm
.tmDescent
, data
[i
+1].tm
.tmDescent
);
6808 ok(data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
== diff
,
6809 "expected %d, got %d\n", diff
, data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
);
6810 ok(data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
== diff
,
6811 "expected %d, got %d\n", diff
, data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
);
6812 ok(data
[i
].tm
.tmOverhang
== 0,
6813 "expected 0, got %d\n", data
[i
].tm
.tmOverhang
);
6814 ok(data
[i
+1].tm
.tmOverhang
== 1,
6815 "expected 1, got %d\n", data
[i
+1].tm
.tmOverhang
);
6816 ok(data
[i
].w
+ 1 == data
[i
+1].w
,
6817 "expected %d, got %d\n", data
[i
].w
+ 1, data
[i
+1].w
);
6821 static void test_bitmap_font_glyph_index(void)
6823 const WCHAR text
[] = L
"#!/bin/sh";
6827 } bitmap_font_list
[] = {
6828 { "Courier", ANSI_CHARSET
},
6829 { "Small Fonts", ANSI_CHARSET
},
6830 { "Fixedsys", DEFAULT_CHARSET
},
6831 { "System", DEFAULT_CHARSET
}
6836 CHAR facename
[LF_FACESIZE
];
6847 if (!pGetGlyphIndicesW
) {
6848 win_skip("GetGlyphIndices is unavailable\n");
6852 hdc
= CreateCompatibleDC(0);
6853 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6855 memset(&bmi
, 0, sizeof(bmi
));
6856 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
6857 bmi
.bmiHeader
.biBitCount
= 32;
6858 bmi
.bmiHeader
.biPlanes
= 1;
6859 bmi
.bmiHeader
.biWidth
= 128;
6860 bmi
.bmiHeader
.biHeight
= 32;
6861 bmi
.bmiHeader
.biCompression
= BI_RGB
;
6863 for (i
= 0; i
< ARRAY_SIZE(bitmap_font_list
); i
++) {
6864 memset(&lf
, 0, sizeof(lf
));
6865 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
6866 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
6867 hFont
= CreateFontIndirectA(&lf
);
6868 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
6869 hFont
= SelectObject(hdc
, hFont
);
6870 ret
= GetTextMetricsA(hdc
, &tm
);
6871 ok(ret
, "GetTextMetric failed\n");
6872 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
6873 ok(ret
, "GetTextFace failed\n");
6874 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
6875 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
6878 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
6879 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
6883 for (j
= 0; j
< 2; j
++) {
6885 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
6886 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
6887 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6890 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
6894 int len
= lstrlenW(text
);
6895 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
6896 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
6897 ok(ret
, "GetGlyphIndices failed\n");
6898 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
6899 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
6900 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
6901 HeapFree(GetProcessHeap(), 0, indices
);
6905 ok(ret
, "ExtTextOutW failed\n");
6906 SelectObject(hdc
, hBmpPrev
);
6909 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
6910 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6911 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6913 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
6915 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6918 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
6919 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
6923 for (j
= 0; j
< 2; j
++) {
6926 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6929 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6932 ret
= GetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6933 ok(ret
, "GetGlyphIndices failed\n");
6934 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6935 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6938 ok(ret
, "ExtTextOutA failed\n");
6939 SelectObject(hdc
, hBmpPrev
);
6942 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6943 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6945 for (j
= 0; j
< 2; j
++)
6946 DeleteObject(hBmp
[j
]);
6947 hFont
= SelectObject(hdc
, hFont
);
6948 DeleteObject(hFont
);
6954 static void test_GetCharWidthI(void)
6956 static const char *teststr
= "wine ";
6957 HFONT hfont
, prev_hfont
;
6967 memset(&lf
, 0, sizeof(lf
));
6968 strcpy(lf
.lfFaceName
, "Tahoma");
6973 hfont
= CreateFontIndirectA(&lf
);
6974 prev_hfont
= SelectObject(hdc
, hfont
);
6976 len
= strlen(teststr
);
6977 nb
= GetGlyphIndicesA(hdc
, teststr
, len
, glyphs
, 0);
6978 ok(nb
== len
, "\n");
6980 memset(abc
, 0xcc, sizeof(abc
));
6981 ret
= GetCharABCWidthsI(hdc
, 0, len
, glyphs
, abc
);
6982 ok(ret
, "GetCharABCWidthsI failed\n");
6984 memset(widths
, 0xcc, sizeof(widths
));
6985 ret
= GetCharWidthI(hdc
, 0, len
, glyphs
, widths
);
6986 ok(ret
, "GetCharWidthI failed\n");
6988 for (i
= 0; i
< len
; i
++)
6989 ok(widths
[i
] == abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
, "%u, glyph %u, got width %d\n",
6990 i
, glyphs
[i
], widths
[i
]);
6992 DeleteObject(SelectObject(hdc
, prev_hfont
));
6996 static INT CALLBACK
long_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lparam
)
6998 BOOL
*found_font
= (BOOL
*)lparam
;
7003 static void test_long_names(void)
7005 char ttf_name
[MAX_PATH
];
7006 LOGFONTA font
= {0};
7012 if (!write_ttf_file("wine_longname.ttf", ttf_name
))
7014 skip("Failed to create ttf file for testing\n");
7020 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7021 ok(ret
, "AddFontResourceEx() failed\n");
7023 strcpy(font
.lfFaceName
, "wine_3_this_is_a_very_long_name");
7025 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7026 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7028 strcpy(font
.lfFaceName
, "wine_2_this_is_a_very_long_name");
7030 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7031 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7033 strcpy(font
.lfFaceName
, "wine_1_this_is_a_very_long_name");
7035 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7036 ok(found_font
== FALSE
, "EnumFontFamiliesExA must not find font.\n");
7038 handle_font
= CreateFontIndirectA(&font
);
7039 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7040 DeleteObject(handle_font
);
7042 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7043 ok(ret
, "RemoveFontResourceEx() failed\n");
7045 DeleteFileA(ttf_name
);
7046 ReleaseDC(NULL
, dc
);
7049 static void test_ttf_names(void)
7051 struct enum_fullname_data efnd
;
7052 char ttf_name
[MAX_PATH
], ttf_name_bold
[MAX_PATH
];
7053 LOGFONTA font
= {0};
7058 if (!write_ttf_file("wine_ttfnames.ttf", ttf_name
))
7060 skip("Failed to create ttf file for testing\n");
7064 if (!write_ttf_file("wine_ttfnames_bold.ttf", ttf_name_bold
))
7066 skip("Failed to create ttf file for testing\n");
7067 DeleteFileA(ttf_name
);
7071 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7072 ok(ret
, "AddFontResourceEx() failed\n");
7074 ret
= AddFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7075 ok(ret
, "AddFontResourceEx() failed\n");
7079 strcpy(font
.lfFaceName
, "Wine_TTF_Names_Long_Family1_Con");
7080 memset(&efnd
, 0, sizeof(efnd
));
7081 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7082 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7084 /* Windows doesn't match with Typographic/Preferred Family tags */
7085 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1");
7086 memset(&efnd
, 0, sizeof(efnd
));
7087 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7088 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7090 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Ext");
7091 memset(&efnd
, 0, sizeof(efnd
));
7092 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7093 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7095 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Con");
7096 memset(&efnd
, 0, sizeof(efnd
));
7097 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7098 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7100 handle_font
= CreateFontIndirectA(&font
);
7101 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7102 DeleteObject(handle_font
);
7104 ret
= RemoveFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7105 ok(ret
, "RemoveFontResourceEx() failed\n");
7107 DeleteFileA(ttf_name_bold
);
7109 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7110 ok(ret
, "RemoveFontResourceEx() failed\n");
7112 DeleteFileA(ttf_name
);
7113 ReleaseDC(NULL
, dc
);
7116 static void test_lang_names(void)
7118 static const WCHAR name_cond_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja)";
7119 static const WCHAR name_cond_ja_reg_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg";
7120 static const WCHAR name_cond_ja_reg_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg (ja)";
7121 static const WCHAR name_wws_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d WWS (ja)";
7123 struct enum_fullname_data efnd
;
7124 struct enum_fullname_data_w efnd_w
;
7125 char ttf_name
[MAX_PATH
], ttf_name2
[MAX_PATH
], ttf_name3
[MAX_PATH
];
7126 LOGFONTA font
= {0};
7127 LOGFONTW font_w
= {0};
7130 const WCHAR
*primary_family
, *primary_fullname
;
7132 if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
&& PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE
)
7134 skip( "Primary language is neither English nor Japanese, skipping test\n" );
7138 if (!write_ttf_file( "wine_langnames.ttf", ttf_name
))
7140 skip( "Failed to create ttf file for testing\n" );
7144 if (!write_ttf_file( "wine_langnames2.ttf", ttf_name2
))
7146 skip( "Failed to create ttf file for testing\n" );
7147 DeleteFileA( ttf_name
);
7151 if (!write_ttf_file( "wine_langnames3.ttf", ttf_name3
))
7153 skip( "Failed to create ttf file for testing\n" );
7154 DeleteFileA( ttf_name2
);
7155 DeleteFileA( ttf_name
);
7159 ret
= AddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7160 ok( ret
, "AddFontResourceEx() failed\n" );
7164 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7166 primary_family
= L
"Wine Lang Cond (en)";
7167 primary_fullname
= L
"Wine Lang Cond Reg (en)";
7171 primary_family
= name_cond_ja_w
;
7172 primary_fullname
= name_cond_ja_reg_w
;
7175 for (i
= 0; i
< 3; ++i
)
7177 /* check that lookup by preferred or WWS family / full names or postscript FontName doesn't work */
7179 strcpy( font
.lfFaceName
, "Wine Lang (en)" );
7180 memset( &efnd
, 0, sizeof(efnd
) );
7181 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7182 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7184 strcpy( font
.lfFaceName
, "Wine Lang Condensed Bold (ko)" );
7185 memset( &efnd
, 0, sizeof(efnd
) );
7186 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7187 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7189 wcscpy( font_w
.lfFaceName
, name_wws_ja_w
);
7190 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7191 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7192 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7194 strcpy( font
.lfFaceName
, "Reg WWS (zh-tw)" );
7195 memset( &efnd
, 0, sizeof(efnd
) );
7196 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7197 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7199 strcpy( font
.lfFaceName
, "Wine Lang (en) Reg WWS (en)" );
7200 memset( &efnd
, 0, sizeof(efnd
) );
7201 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7202 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7204 strcpy( font
.lfFaceName
, "WineLangNamesRegular" );
7205 memset( &efnd
, 0, sizeof(efnd
) );
7206 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7207 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7209 /* then, the primary ttf family name always works */
7211 wcscpy( font_w
.lfFaceName
, primary_family
);
7212 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7213 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7214 ok( efnd_w
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7216 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7218 wcscpy( font_w
.lfFaceName
, name_cond_ja_w
);
7219 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7220 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7221 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7224 /* if there is no primary ttf family name, the english ttf name, or postscript FamilyName are used instead */
7226 strcpy( font
.lfFaceName
, "Wine_Lang_Names" );
7227 memset( &efnd
, 0, sizeof(efnd
) );
7228 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7230 ok( efnd
.total
== 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7232 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7234 /* same goes for ttf full names */
7236 wcscpy( font_w
.lfFaceName
, primary_fullname
);
7237 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7238 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7239 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7241 if (efnd_w
.total
>= 1)
7243 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
, primary_family
),
7244 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
) );
7245 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfFullName
, primary_fullname
),
7246 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfFullName
) );
7247 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
? L
"Reg (en)" : L
"Reg (ja)" ),
7248 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfStyle
) );
7251 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7253 wcscpy( font_w
.lfFaceName
, name_cond_ja_reg_w
);
7254 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7255 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7256 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7259 wcscpy( font_w
.lfFaceName
, L
"Wine_Lang_Names_Regular" );
7260 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7261 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7262 ok( efnd_w
.total
== i
, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7264 while (efnd_w
.total
--)
7266 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
, efnd_w
.total
== 1 ? L
"Wine_Lang_Names" : primary_family
),
7267 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
) );
7268 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
, L
"Wine_Lang_Names_Regular" ),
7269 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
) );
7270 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7271 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
, efnd_w
.total
== 1 ? L
"Regular" : L
"Reg (en)" ),
7272 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
) );
7274 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, L
"Reg (ja)" ),
7275 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfStyle
) );
7278 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7280 wcscpy( font_w
.lfFaceName
, name_cond_ja_reg_ja_w
);
7281 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7282 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7283 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7286 /* another language can also be used for lookup, if the primary langid isn't english, then
7287 english seems to have priority, otherwise or if english is already the primary langid,
7288 the family name with the smallest langid is used as secondary lookup language. */
7290 strcpy( font
.lfFaceName
, "Wine Lang Cond (zh-tw)" );
7291 memset( &efnd
, 0, sizeof(efnd
) );
7292 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7293 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7294 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7295 else /* (zh-tw) doesn't match here probably because there's an (en) name too */
7296 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7298 strcpy( font
.lfFaceName
, "Wine Lang Cond (en)" );
7299 memset( &efnd
, 0, sizeof(efnd
) );
7300 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7301 /* either because it's the primary language, or because it's a secondary */
7302 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7304 wcscpy( font_w
.lfFaceName
, L
"Wine Police d'\xe9" "criture (fr)" );
7305 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7306 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7307 /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */
7308 if (i
== 2) ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7309 else ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7311 /* case matching should not depend on the current locale */
7314 wcscpy( font_w
.lfFaceName
, L
"Wine POLICE D'\xc9" "CRITURE (fr)" );
7315 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7316 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7317 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7320 strcpy( font
.lfFaceName
, "Wine Lang Cond (ko)" );
7321 memset( &efnd
, 0, sizeof(efnd
) );
7322 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7323 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7325 /* that doesn't apply to full names */
7327 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (zh-tw)" );
7328 memset( &efnd
, 0, sizeof(efnd
) );
7329 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7330 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7332 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (fr)" );
7333 memset( &efnd
, 0, sizeof(efnd
) );
7334 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7335 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7339 ret
= AddFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7340 ok( ret
, "AddFontResourceEx() failed\n" );
7344 ret
= AddFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7345 ok( ret
, "AddFontResourceEx() failed\n" );
7349 ret
= RemoveFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7350 ok( ret
, "RemoveFontResourceEx() failed\n" );
7352 DeleteFileA( ttf_name3
);
7354 ret
= RemoveFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7355 ok( ret
, "RemoveFontResourceEx() failed\n" );
7357 DeleteFileA( ttf_name2
);
7359 ret
= RemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7360 ok( ret
, "RemoveFontResourceEx() failed\n" );
7362 DeleteFileA( ttf_name
);
7363 ReleaseDC( NULL
, dc
);
7368 USHORT majorVersion
;
7369 USHORT minorVersion
;
7373 USHORT advanceWidthMax
;
7374 SHORT minLeftSideBearing
;
7375 SHORT minRightSideBearing
;
7377 SHORT caretSlopeRise
;
7378 SHORT caretSlopeRun
;
7381 SHORT metricDataFormat
;
7382 SHORT numberOfHMetrics
;
7385 static void test_GetCharWidthInfo(void)
7388 HFONT hfont
, hfont_prev
;
7392 OUTLINETEXTMETRICA otm
;
7393 TT_Hori_Header hhea
;
7394 struct char_width_info
7398 SHORT minLeftSideBearing
, minRightSideBearing
;
7400 const char* face_list
[] = { "Symbol", "Ume Gothic", "MS Gothic" };
7402 if (!pGetCharWidthInfo
)
7404 win_skip("GetCharWidthInfo is unavailable\n");
7410 /* test default (System) font */
7411 memset(&info
, 0xaa, sizeof(info
));
7412 r
= pGetCharWidthInfo(hdc
, &info
);
7413 if (r
) /* win10 1803 succeeds */
7415 ok(info
.lsb
== 0, "expected 0, got %d\n", info
.lsb
);
7416 ok(info
.rsb
== 0, "expected 0, got %d\n", info
.rsb
);
7417 ok(info
.unk
== 0, "expected 0, got %d\n", info
.unk
);
7420 memset(&lf
, 0, sizeof(lf
));
7421 lf
.lfWeight
= FW_NORMAL
;
7422 lf
.lfCharSet
= ANSI_CHARSET
;
7423 strcpy(lf
.lfFaceName
, "Tahoma");
7424 hfont
= CreateFontIndirectA(&lf
);
7425 hfont_prev
= SelectObject(hdc
, hfont
);
7426 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7428 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
7429 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
7430 DeleteObject(SelectObject(hdc
, hfont_prev
));
7432 /* test Tahoma at the em square size */
7433 lf
.lfHeight
= -(int)otm
.otmEMSquare
;
7434 hfont
= CreateFontIndirectA(&lf
);
7435 hfont_prev
= SelectObject(hdc
, hfont
);
7436 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7438 ret
= GetFontData(hdc
, MS_MAKE_TAG('h','h','e','a'), 0, &hhea
, sizeof(hhea
));
7439 ok(ret
== sizeof(hhea
), "got %u\n", ret
);
7440 minLeftSideBearing
= GET_BE_WORD(hhea
.minLeftSideBearing
);
7441 minRightSideBearing
= GET_BE_WORD(hhea
.minRightSideBearing
);
7443 memset(&info
, 0xaa, sizeof(info
));
7444 r
= pGetCharWidthInfo(hdc
, &info
);
7445 ok(r
, "GetCharWidthInfo failed\n");
7446 ok(info
.lsb
== minLeftSideBearing
, "expected %d, got %d\n", minLeftSideBearing
, info
.lsb
);
7447 ok(info
.rsb
== minRightSideBearing
, "expected %d, got %d\n", minRightSideBearing
, info
.rsb
);
7449 DeleteObject(SelectObject(hdc
, hfont_prev
));
7451 /* these values are scaled, try with smaller size */
7453 hfont
= CreateFontIndirectA(&lf
);
7454 hfont_prev
= SelectObject(hdc
, hfont
);
7455 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7457 memset(&info2
, 0xaa, sizeof(info2
));
7458 r
= pGetCharWidthInfo(hdc
, &info2
);
7459 ok(r
, "pGetCharWidthInfo failed\n");
7460 ok(info2
.lsb
== info
.lsb
/3, "expected %d, got %d\n", info
.lsb
/3, info2
.lsb
);
7461 ok(info2
.rsb
== info
.rsb
/3, "expected %d, got %d\n", info
.rsb
/3, info2
.rsb
);
7463 DeleteObject(SelectObject(hdc
, hfont_prev
));
7464 ReleaseDC(NULL
, hdc
);
7466 /* test with another mapping mode */
7468 SetMapMode(hdc
, MM_ISOTROPIC
);
7469 SetWindowExtEx(hdc
, 2, 2, NULL
);
7470 SetViewportExtEx(hdc
, 1, 1, NULL
);
7472 memset(pt
, 0, sizeof(pt
));
7473 pt
[0].y
= otm
.otmEMSquare
;
7476 memset(&lf
, 0, sizeof(lf
));
7477 lf
.lfWeight
= FW_NORMAL
;
7478 lf
.lfCharSet
= ANSI_CHARSET
;
7479 lf
.lfHeight
= -abs(pt
[0].y
);
7480 strcpy(lf
.lfFaceName
, "Tahoma");
7481 hfont
= CreateFontIndirectA(&lf
);
7482 hfont_prev
= SelectObject(hdc
, hfont
);
7483 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7485 memset(&info2
, 0xaa, sizeof(info2
));
7486 r
= pGetCharWidthInfo(hdc
, &info2
);
7487 ok(r
, "GetCharWidthInfo failed\n");
7488 pt
[0].x
= info
.lsb
; pt
[0].y
= 0;
7489 pt
[1].x
= info
.rsb
; pt
[1].y
= 0;
7491 ok(pt
[0].x
== info2
.lsb
, "expected %d, got %d\n", pt
[0].x
, info2
.lsb
);
7492 ok(pt
[1].x
== info2
.rsb
, "expected %d, got %d\n", pt
[1].x
, info2
.rsb
);
7494 DeleteObject(SelectObject(hdc
, hfont_prev
));
7495 ReleaseDC(NULL
, hdc
);
7497 /* test with synthetic fonts */
7499 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++)
7501 const char* face
= face_list
[i
];
7502 if (!is_truetype_font_installed(face
))
7504 skip("%s is not installed\n", face
);
7507 memset(&lf
, 0, sizeof(lf
));
7508 lf
.lfWeight
= FW_NORMAL
;
7509 lf
.lfItalic
= FALSE
;
7510 lf
.lfCharSet
= DEFAULT_CHARSET
;
7512 strcpy(lf
.lfFaceName
, face
);
7513 hfont
= CreateFontIndirectA(&lf
);
7514 hfont_prev
= SelectObject(hdc
, hfont
);
7516 memset(&info
, 0xaa, sizeof(info
));
7517 r
= pGetCharWidthInfo(hdc
, &info
);
7518 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7520 /* test with synthetic bold */
7521 lf
.lfWeight
= FW_BOLD
;
7522 lf
.lfItalic
= FALSE
;
7523 hfont
= CreateFontIndirectA(&lf
);
7524 DeleteObject(SelectObject(hdc
, hfont
));
7526 memset(&info2
, 0xaa, sizeof(info2
));
7527 r
= pGetCharWidthInfo(hdc
, &info2
);
7528 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7529 ok(info
.lsb
== info2
.lsb
, "%s: expected %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7530 ok(info
.rsb
== info2
.rsb
, "%s: expected %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7532 /* test with synthetic italic */
7533 lf
.lfWeight
= FW_NORMAL
;
7535 hfont
= CreateFontIndirectA(&lf
);
7536 DeleteObject(SelectObject(hdc
, hfont
));
7538 memset(&info2
, 0xaa, sizeof(info2
));
7539 r
= pGetCharWidthInfo(hdc
, &info2
);
7540 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7541 todo_wine
ok(info
.lsb
> info2
.lsb
, "%s: expected less than %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7542 todo_wine
ok(info
.rsb
> info2
.rsb
, "%s: expected less than %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7543 DeleteObject(SelectObject(hdc
, hfont_prev
));
7546 ReleaseDC(NULL
, hdc
);
7549 static int CALLBACK
get_char_width_proc(const LOGFONTA
*lf
,
7550 const TEXTMETRICA
*tm
, DWORD type
, LPARAM ctx
)
7552 HFONT font
= CreateFontIndirectA(lf
);
7553 HDC dc
= GetDC(NULL
);
7561 SelectObject(dc
, font
);
7563 ret
= GetCharWidthFloatA(dc
, c
, c
, &f
);
7564 ok(ret
, "%s: GetCharWidthFloat() failed\n", lf
->lfFaceName
);
7565 ret
= GetCharWidth32A(dc
, c
, c
, &i32
);
7566 ok(ret
, "%s: GetCharWidth32A() failed\n", lf
->lfFaceName
);
7567 ret
= GetCharWidthA(dc
, c
, c
, &i
);
7568 ok(ret
, "%s: GetCharWidthA() failed\n", lf
->lfFaceName
);
7569 ok(i
== i32
, "%s: mismatched widths %d/%d\n", lf
->lfFaceName
, i
, i32
);
7570 ok((float)i
/ 16.0f
== f
, "%s: mismatched widths %d/%.8e\n", lf
->lfFaceName
, i
, f
);
7572 ret
= GetCharABCWidthsFloatA(dc
, c
, c
, &abcf
);
7573 ok(ret
, "%s: GetCharABCWidths() failed\n", lf
->lfFaceName
);
7574 if (GetCharABCWidthsA(dc
, c
, c
, &abc
))
7575 ok((float)abc
.abcB
== abcf
.abcfB
, "%s: mismatched widths %d/%.8e\n",
7576 lf
->lfFaceName
, abc
.abcB
, abcf
.abcfB
);
7578 ReleaseDC(NULL
, dc
);
7583 static void test_char_width(void)
7585 HDC dc
= GetDC(NULL
);
7588 lf
.lfCharSet
= DEFAULT_CHARSET
;
7589 EnumFontFamiliesExA(dc
, &lf
, get_char_width_proc
, 0, 0);
7591 ReleaseDC(NULL
, dc
);
7594 static void test_GetCharacterPlacement_kerning(void)
7597 HFONT hfont
, hfont_old
;
7600 DWORD count
, ret
, i
, size
, width
, width_kern
, idx
;
7602 GCP_RESULTSW result
;
7603 int kern
[30], pos
[30], pos_kern
[30], dx
[30], dx_kern
[30], kern_amount
;
7605 if (!is_font_installed("Arial"))
7607 skip("Arial is not installed, skipping the test\n");
7613 memset(&lf
, 0, sizeof(lf
));
7614 strcpy(lf
.lfFaceName
, "Arial");
7616 hfont
= CreateFontIndirectA(&lf
);
7617 ok(hfont
!= NULL
, "CreateFontIndirect failed\n");
7619 hfont_old
= SelectObject(hdc
, hfont
);
7621 count
= GetKerningPairsW(hdc
, 0, NULL
);
7622 kp
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*kp
));
7624 ret
= GetKerningPairsW(hdc
, count
, kp
);
7625 ok(ret
== count
, "got %u, expected %u\n", ret
, count
);
7627 size
= kern_amount
= idx
= 0;
7628 for (i
= 0; i
< count
; i
++)
7630 if (kp
[i
].wFirst
>= 'A' && kp
[i
].wFirst
<= 'z' &&
7631 kp
[i
].wSecond
>= 'A' && kp
[i
].wSecond
<= 'z')
7633 str
[size
++] = kp
[i
].wFirst
;
7634 str
[size
++] = kp
[i
].wSecond
;
7636 kern
[idx
] = kp
[i
].iKernAmount
;
7638 kern_amount
+= kp
[i
].iKernAmount
;
7639 if (size
>= ARRAY_SIZE(str
)) break;
7643 HeapFree(GetProcessHeap(), 0, kp
);
7647 memset(&result
, 0, sizeof(result
));
7648 result
.lStructSize
= sizeof(result
);
7649 result
.lpCaretPos
= pos
;
7651 result
.nGlyphs
= count
;
7652 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, 0);
7653 ok(ret
, "GetCharacterPlacement failed\n");
7654 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7655 width
= LOWORD(ret
);
7657 memset(&result
, 0, sizeof(result
));
7658 result
.lStructSize
= sizeof(result
);
7659 result
.lpCaretPos
= pos_kern
;
7660 result
.lpDx
= dx_kern
;
7661 result
.nGlyphs
= count
;
7662 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, GCP_USEKERNING
);
7663 ok(ret
, "GetCharacterPlacement failed\n");
7664 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7665 width_kern
= LOWORD(ret
);
7667 if (width
== width_kern
)
7669 win_skip("GCP_USEKERNING is broken on this platform\n");
7673 ok(width
+ kern_amount
== width_kern
, "%d + %d != %d\n", width
, kern_amount
, width_kern
);
7675 kern_amount
= idx
= 0;
7676 for (i
= 0; i
< count
; i
+= 3, idx
++)
7678 ok(pos
[i
] + kern_amount
== pos_kern
[i
], "%d: %d + %d != %d\n", i
, pos
[i
], kern_amount
, pos_kern
[i
]);
7679 kern_amount
+= kern
[idx
];
7680 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]);
7681 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]);
7683 ok(dx
[i
] + kern
[idx
] == dx_kern
[i
], "%d: %d + %d != %d\n", i
, dx
[i
], kern
[idx
], dx_kern
[i
]);
7684 ok(dx
[i
+1] == dx_kern
[i
+1], "%d: %d != %d\n", i
, dx
[i
+1], dx_kern
[i
+1]);
7685 ok(dx
[i
+2] == dx_kern
[i
+2], "%d: %d != %d\n", i
, dx
[i
+2], dx_kern
[i
+2]);
7689 SelectObject(hdc
, hfont_old
);
7690 DeleteObject(hfont
);
7696 static const char *test_names
[] =
7698 "AddFontMemResource",
7700 char path_name
[MAX_PATH
];
7701 STARTUPINFOA startup
;
7707 argc
= winetest_get_mainargs(&argv
);
7710 if (!strcmp(argv
[2], "AddFontMemResource"))
7711 test_AddFontMemResource();
7718 test_outline_font();
7719 test_bitmap_font_metrics();
7720 test_GdiGetCharDimensions();
7721 test_GetCharABCWidths();
7722 test_text_extents();
7723 test_GetGlyphIndices();
7724 test_GetKerningPairs();
7725 test_GetOutlineTextMetrics();
7726 test_SetTextJustification();
7727 test_font_charset();
7728 test_GdiGetCodePage();
7729 test_GetFontUnicodeRanges();
7730 test_nonexistent_font();
7732 test_height_selection();
7734 test_EnumFonts_subst();
7736 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
7737 * I'd like to avoid them in this test.
7739 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
7740 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
7741 if (is_truetype_font_installed("Arial Black") &&
7742 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
7744 test_EnumFontFamilies("", ANSI_CHARSET
);
7745 test_EnumFontFamilies("", SYMBOL_CHARSET
);
7746 test_EnumFontFamilies("", DEFAULT_CHARSET
);
7749 skip("Arial Black or Symbol/Wingdings is not installed\n");
7750 test_EnumFontFamiliesEx_default_charset();
7751 test_GetTextMetrics();
7752 test_RealizationInfo();
7754 test_GetGlyphOutline();
7755 test_GetTextMetrics2("Tahoma", -11);
7756 test_GetTextMetrics2("Tahoma", -55);
7757 test_GetTextMetrics2("Tahoma", -110);
7758 test_GetTextMetrics2("Arial", -11);
7759 test_GetTextMetrics2("Arial", -55);
7760 test_GetTextMetrics2("Arial", -110);
7761 test_GetCharacterPlacement();
7762 test_GetCharacterPlacement_kerning();
7763 test_GetCharWidthInfo();
7764 test_CreateFontIndirect();
7765 test_CreateFontIndirectEx();
7769 test_east_asian_font_selection();
7771 test_vertical_order();
7772 test_GetCharWidth32();
7773 test_fake_bold_font();
7774 test_bitmap_font_glyph_index();
7775 test_GetCharWidthI();
7781 /* These tests should be last test until RemoveFontResource
7782 * is properly implemented.
7784 test_vertical_font();
7785 test_CreateScalableFontResource();
7787 winetest_get_mainargs( &argv
);
7788 for (i
= 0; i
< ARRAY_SIZE(test_names
); ++i
)
7790 PROCESS_INFORMATION info
;
7792 memset(&startup
, 0, sizeof(startup
));
7793 startup
.cb
= sizeof(startup
);
7794 sprintf(path_name
, "%s font %s", argv
[0], test_names
[i
]);
7795 ok(CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
),
7796 "CreateProcess failed.\n");
7797 wait_child_process(info
.hProcess
);
7798 CloseHandle(info
.hProcess
);
7799 CloseHandle(info
.hThread
);