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 WCHAR c
[] = { 0x25bc /* Black Down-Pointing Triangle */, 0x212a /* Kelvin Sign */ };
1636 WORD glyphs
[(sizeof(testtext
)/2)-1];
1640 DWORD ret
, font_size
, num_fonts
;
1642 char ttf_name
[MAX_PATH
];
1644 if (!pGetGlyphIndicesW
) {
1645 win_skip("GetGlyphIndicesW not available on platform\n");
1651 memset(&lf
, 0, sizeof(lf
));
1652 strcpy(lf
.lfFaceName
, "System");
1654 lf
.lfCharSet
= ANSI_CHARSET
;
1656 hfont
= CreateFontIndirectA(&lf
);
1657 ok(hfont
!= 0, "CreateFontIndirect failed\n");
1658 hOldFont
= SelectObject(hdc
, hfont
);
1659 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetrics failed\n");
1660 if (textm
.tmCharSet
== ANSI_CHARSET
)
1662 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1663 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1664 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1665 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1667 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1668 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1669 ok(glyphs
[4] == textm
.tmDefaultChar
|| glyphs
[4] == 0x20 /* CJK Windows */,
1670 "GetGlyphIndicesW should have returned a %04x not %04x\n", textm
.tmDefaultChar
, glyphs
[4]);
1673 /* FIXME: Write tests for non-ANSI charsets. */
1674 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1676 DeleteObject(SelectObject(hdc
, hOldFont
));
1678 memset(&lf
, 0, sizeof(lf
));
1679 strcpy(lf
.lfFaceName
, "MS Sans Serif");
1681 lf
.lfCharSet
= DEFAULT_CHARSET
;
1682 hfont
= CreateFontIndirectA(&lf
);
1683 ok(hfont
!= 0, "CreateFontIndirect failed\n");
1684 hOldFont
= SelectObject(hdc
, hfont
);
1685 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetrics failed\n");
1687 glyphs
[0] = glyphs
[1] = 0;
1688 charcount
= GetGlyphIndicesW(hdc
, c
, ARRAY_SIZE(c
), glyphs
, GGI_MARK_NONEXISTING_GLYPHS
);
1689 ok(charcount
== ARRAY_SIZE(c
), "got %u\n", charcount
);
1690 ok(glyphs
[0] == 0x001f || glyphs
[0] == 0xffff /* Vista */, "got %#x\n", glyphs
[0]);
1691 ok(glyphs
[1] == 0x001f || glyphs
[1] == 0xffff /* Vista */, "got %#x\n", glyphs
[1]);
1693 glyphs
[0] = glyphs
[1] = 0;
1694 charcount
= GetGlyphIndicesW(hdc
, c
, ARRAY_SIZE(c
), glyphs
, 0);
1695 ok(charcount
== ARRAY_SIZE(c
), "got %u\n", charcount
);
1696 ok(glyphs
[0] == textm
.tmDefaultChar
|| glyphs
[0] == 0x20 /* CJK Windows */, "got %#x\n", glyphs
[0]);
1697 ok(glyphs
[1] == textm
.tmDefaultChar
|| glyphs
[1] == 0x20 /* CJK Windows */, "got %#x\n", glyphs
[1]);
1699 DeleteObject(SelectObject(hdc
, hOldFont
));
1701 if(!is_font_installed("Tahoma"))
1703 skip("Tahoma is not installed so skipping this test\n");
1707 memset(&lf
, 0, sizeof(lf
));
1708 strcpy(lf
.lfFaceName
, "Tahoma");
1711 hfont
= CreateFontIndirectA(&lf
);
1712 hOldFont
= SelectObject(hdc
, hfont
);
1713 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1714 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
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
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1719 testtext
[0] = textm
.tmDefaultChar
;
1720 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1721 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1722 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1723 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1724 DeleteObject(SelectObject(hdc
, hOldFont
));
1726 ret
= write_ttf_file("wine_nul.ttf", ttf_name
);
1727 ok(ret
, "Failed to create test font file.\n");
1728 font
= load_font(ttf_name
, &font_size
);
1729 ok(font
!= NULL
, "Failed to map font file.\n");
1731 rsrc
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
1732 ok(ret
!= 0, "Failed to add resource, %d.\n", GetLastError());
1733 ok(num_fonts
== 1, "Unexpected number of fonts %u.\n", num_fonts
);
1735 memset(&lf
, 0, sizeof(lf
));
1736 strcpy(lf
.lfFaceName
, "wine_nul");
1739 hfont
= CreateFontIndirectA(&lf
);
1740 hOldFont
= SelectObject(hdc
, hfont
);
1741 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1743 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1744 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1745 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1746 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1747 DeleteObject(SelectObject(hdc
, hOldFont
));
1751 ret
= pRemoveFontMemResourceEx(rsrc
);
1752 ok(ret
, "RemoveFontMemResourceEx error %d\n", GetLastError());
1754 ret
= DeleteFileA(ttf_name
);
1755 ok(ret
, "Failed to delete font file, %d.\n", GetLastError());
1758 static void test_GetKerningPairs(void)
1760 static const struct kerning_data
1762 const char face_name
[LF_FACESIZE
];
1764 /* some interesting fields from OUTLINETEXTMETRIC */
1765 LONG tmHeight
, tmAscent
, tmDescent
;
1770 UINT otmsCapEmHeight
;
1775 UINT otmusMinimumPPEM
;
1776 /* small subset of kerning pairs to test */
1777 DWORD total_kern_pairs
;
1778 const KERNINGPAIR kern_pair
[26];
1781 {"Arial", 12, 12, 9, 3,
1782 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1785 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1786 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1787 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1788 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1789 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1790 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1791 {933,970,+1},{933,972,-1}
1794 {"Arial", -34, 39, 32, 7,
1795 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1798 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1799 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1800 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1801 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1802 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1803 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1804 {933,970,+2},{933,972,-3}
1807 { "Arial", 120, 120, 97, 23,
1808 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1811 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1812 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1813 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1814 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1815 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1816 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1817 {933,970,+6},{933,972,-10}
1820 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1821 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1822 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1825 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1826 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1827 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1828 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1829 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1830 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1831 {933,970,+54},{933,972,-83}
1837 HFONT hfont
, hfont_old
;
1838 KERNINGPAIR
*kern_pair
;
1840 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1844 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1845 * which may render this test unusable, so we're trying to avoid that.
1847 SetLastError(0xdeadbeef);
1848 GetKerningPairsW(hdc
, 0, NULL
);
1849 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1851 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1856 for (i
= 0; i
< ARRAY_SIZE(kd
); i
++)
1858 OUTLINETEXTMETRICW otm
;
1861 if (!is_font_installed(kd
[i
].face_name
))
1863 skip("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1867 memset(&lf
, 0, sizeof(lf
));
1868 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1869 lf
.lfHeight
= kd
[i
].height
;
1870 hfont
= CreateFontIndirectA(&lf
);
1871 ok(hfont
!= NULL
, "failed to create a font, name %s\n", kd
[i
].face_name
);
1873 hfont_old
= SelectObject(hdc
, hfont
);
1875 SetLastError(0xdeadbeef);
1876 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1877 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1878 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1880 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1881 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1882 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1883 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1884 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1885 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1887 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1888 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1889 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1890 kd
[i
].otmAscent
, otm
.otmAscent
);
1891 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1892 kd
[i
].otmDescent
, otm
.otmDescent
);
1893 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1894 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1895 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1896 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1897 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1898 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1900 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1901 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1903 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1904 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1905 ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1906 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1908 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1909 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1911 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1912 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1914 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1917 SetLastError(0xdeadbeef);
1918 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1919 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1920 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1921 ok(ret
== 0, "got %u, expected 0\n", ret
);
1923 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1924 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1926 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1927 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1929 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1930 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1934 for (n
= 0; n
< ret
; n
++)
1938 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1940 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1941 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1943 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1944 "pair %d:%d got %d, expected %d\n",
1945 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1946 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1952 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1953 matches
, kd
[i
].total_kern_pairs
);
1955 HeapFree(GetProcessHeap(), 0, kern_pair
);
1957 SelectObject(hdc
, hfont_old
);
1958 DeleteObject(hfont
);
1966 const char face_name
[LF_FACESIZE
];
1967 int requested_height
;
1968 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1972 static void test_height( HDC hdc
, const struct font_data
*fd
)
1975 HFONT hfont
, old_hfont
;
1979 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1981 if (!is_truetype_font_installed(fd
[i
].face_name
))
1983 skip("%s is not installed\n", fd
[i
].face_name
);
1987 memset(&lf
, 0, sizeof(lf
));
1988 lf
.lfHeight
= fd
[i
].requested_height
;
1989 lf
.lfWeight
= fd
[i
].weight
;
1990 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1992 hfont
= CreateFontIndirectA(&lf
);
1993 ok(hfont
!= NULL
, "failed to create a font, name %s\n", fd
[i
].face_name
);
1995 old_hfont
= SelectObject(hdc
, hfont
);
1996 ret
= GetTextMetricsA(hdc
, &tm
);
1997 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1998 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
2000 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
);
2001 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
);
2002 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
);
2003 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
);
2004 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
);
2005 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
);
2008 SelectObject(hdc
, old_hfont
);
2009 /* force GDI to use new font, otherwise Windows leaks the font reference */
2010 GetTextMetricsA(hdc
, &tm
);
2011 DeleteObject(hfont
);
2015 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
2017 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
2018 DWORD
*table
= (DWORD
*)ttf
+ 3;
2020 for (i
= 0; i
< num_tables
; i
++)
2022 if (table
[0] == tag
)
2023 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
2029 static void test_height_selection_vdmx( HDC hdc
)
2031 static const struct font_data charset_0
[] = /* doesn't use VDMX */
2033 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2034 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2035 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2036 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2037 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2038 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
2039 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2040 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
2041 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
2042 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
2043 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
2044 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
2045 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
2046 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
2047 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2048 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
2049 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
2050 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
2051 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2052 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2053 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2054 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2055 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
2056 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2057 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
2058 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2059 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2060 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2061 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2062 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2063 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
2064 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
2065 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
2066 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
2067 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
2068 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
2069 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2070 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
2071 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
2072 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2073 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2074 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2075 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2076 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
2077 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
2078 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
2079 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
2080 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
2081 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
2082 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2083 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
2084 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2085 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2088 static const struct font_data charset_1
[] = /* Uses VDMX */
2090 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2091 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2092 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2093 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2094 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2095 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2096 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2097 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2098 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2099 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2100 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2101 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2102 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2103 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2104 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2105 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2106 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2107 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2108 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2109 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2110 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2111 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2112 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2113 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
2114 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
2115 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
2116 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2117 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2118 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2119 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2120 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2121 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2122 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2123 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2124 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2125 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2126 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2127 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2128 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2129 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2130 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2131 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
2132 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
2133 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
2134 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
2135 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
2136 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
2137 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
2138 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
2139 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
2140 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
2141 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
2142 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2145 static const struct vdmx_data
2149 const struct font_data
*fd
;
2152 { 0, 0, charset_0
},
2153 { 0, 1, charset_1
},
2154 { 1, 0, charset_0
},
2161 char ttf_name
[MAX_PATH
];
2165 if (!pAddFontResourceExA
)
2167 win_skip("AddFontResourceExA unavailable\n");
2171 for (i
= 0; i
< ARRAY_SIZE(data
); i
++)
2173 res
= get_res_data( "wine_vdmx.ttf", &size
);
2175 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2176 memcpy( copy
, res
, size
);
2177 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2178 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2179 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2180 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2181 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2182 ratio_rec
[0] = data
[i
].bCharSet
;
2184 write_tmp_file( copy
, &size
, ttf_name
);
2185 HeapFree( GetProcessHeap(), 0, copy
);
2187 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2188 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2189 if (!num
) win_skip("Unable to add ttf font resource\n");
2192 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2193 test_height( hdc
, data
[i
].fd
);
2194 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2196 ret
= DeleteFileA( ttf_name
);
2197 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
),
2198 "DeleteFile error %d\n", GetLastError());
2202 static void test_height_selection(void)
2204 static const struct font_data tahoma
[] =
2206 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2207 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2208 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2209 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2210 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2211 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2212 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2213 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2214 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2215 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2216 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2218 HDC hdc
= CreateCompatibleDC(0);
2219 ok(hdc
!= NULL
, "failed to create hdc\n");
2221 test_height( hdc
, tahoma
);
2222 test_height_selection_vdmx( hdc
);
2227 static UINT
get_font_fsselection(LOGFONTA
*lf
)
2229 OUTLINETEXTMETRICA
*otm
;
2230 HFONT hfont
, hfont_old
;
2231 DWORD ret
, otm_size
;
2236 hfont
= CreateFontIndirectA(lf
);
2237 ok(hfont
!= NULL
, "failed to create a font\n");
2239 hfont_old
= SelectObject(hdc
, hfont
);
2241 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2242 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2243 otm
->otmSize
= sizeof(*otm
);
2244 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2245 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2246 fsSelection
= otm
->otmfsSelection
;
2247 HeapFree(GetProcessHeap(), 0, otm
);
2248 SelectObject(hdc
, hfont_old
);
2249 DeleteObject(hfont
);
2255 static void test_GetOutlineTextMetrics(void)
2257 OUTLINETEXTMETRICA
*otm
;
2259 HFONT hfont
, hfont_old
;
2261 DWORD ret
, otm_size
;
2265 /* check fsSelection field with bold simulation */
2266 memset(&lf
, 0, sizeof(lf
));
2267 strcpy(lf
.lfFaceName
, "Wingdings");
2268 lf
.lfCharSet
= SYMBOL_CHARSET
;
2271 fsSelection
= get_font_fsselection(&lf
);
2272 ok((fsSelection
& (1 << 5)) == 0, "got 0x%x\n", fsSelection
);
2274 /* face with bold simulation */
2275 lf
.lfWeight
= FW_BOLD
;
2276 fsSelection
= get_font_fsselection(&lf
);
2277 ok((fsSelection
& (1 << 5)) != 0, "got 0x%x\n", fsSelection
);
2279 /* check fsSelection field with oblique simulation */
2280 memset(&lf
, 0, sizeof(lf
));
2281 strcpy(lf
.lfFaceName
, "Tahoma");
2283 lf
.lfWeight
= FW_NORMAL
;
2284 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2285 lf
.lfQuality
= PROOF_QUALITY
;
2288 fsSelection
= get_font_fsselection(&lf
);
2289 ok((fsSelection
& 1) == 0, "got 0x%x\n", fsSelection
);
2292 /* face with oblique simulation */
2293 fsSelection
= get_font_fsselection(&lf
);
2294 ok((fsSelection
& 1) == 1, "got 0x%x\n", fsSelection
);
2296 if (!is_font_installed("Arial"))
2298 skip("Arial is not installed\n");
2304 memset(&lf
, 0, sizeof(lf
));
2305 strcpy(lf
.lfFaceName
, "Arial");
2307 lf
.lfWeight
= FW_NORMAL
;
2308 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2309 lf
.lfQuality
= PROOF_QUALITY
;
2310 hfont
= CreateFontIndirectA(&lf
);
2311 ok(hfont
!= NULL
, "failed to create a font\n");
2313 hfont_old
= SelectObject(hdc
, hfont
);
2314 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2316 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2318 memset(otm
, 0xAA, otm_size
);
2319 SetLastError(0xdeadbeef);
2320 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2321 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2322 ok(ret
== 1 /* Win9x */ ||
2323 ret
== otm
->otmSize
/* XP*/,
2324 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2325 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2327 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2328 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2329 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2330 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2333 memset(otm
, 0xAA, otm_size
);
2334 SetLastError(0xdeadbeef);
2335 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2336 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2337 ok(ret
== 1 /* Win9x */ ||
2338 ret
== otm
->otmSize
/* XP*/,
2339 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2340 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2342 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2343 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2344 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2345 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2348 /* ask about truncated data */
2349 memset(otm
, 0xAA, otm_size
);
2350 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2351 SetLastError(0xdeadbeef);
2352 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2353 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2354 ok(ret
== 1 /* Win9x */ ||
2355 ret
== otm
->otmSize
/* XP*/,
2356 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2357 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2359 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2360 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2361 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2363 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2365 /* check handling of NULL pointer */
2366 SetLastError(0xdeadbeef);
2367 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, NULL
);
2368 ok(ret
== otm_size
, "expected %u, got %u, error %d\n", otm_size
, ret
, GetLastError());
2370 HeapFree(GetProcessHeap(), 0, otm
);
2372 SelectObject(hdc
, hfont_old
);
2373 DeleteObject(hfont
);
2378 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2382 areaWidth
= clientArea
->right
- clientArea
->left
,
2384 const char *pFirstChar
, *pLastChar
;
2391 int GetTextExtentExPointWWidth
;
2394 GetTextMetricsA(hdc
, &tm
);
2395 y
= clientArea
->top
;
2398 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2404 /* if not at the end of the string, ... */
2405 if (*str
== '\0') break;
2406 /* ... add the next word to the current extent */
2407 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2409 SetTextJustification(hdc
, 0, 0);
2410 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2411 } while ((int) size
.cx
< areaWidth
);
2413 /* ignore trailing break chars */
2415 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2421 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2423 SetTextJustification(hdc
, 0, 0);
2424 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2426 /* do not justify the last extent */
2427 if (*str
!= '\0' && breakCount
> 0)
2429 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2430 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2431 if (size
.cx
!= areaWidth
&& nErrors
< ARRAY_SIZE(error
) - 1)
2433 error
[nErrors
].start
= pFirstChar
;
2434 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2435 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2442 } while (*str
&& y
< clientArea
->bottom
);
2444 for (e
= 0; e
< nErrors
; e
++)
2446 /* The width returned by GetTextExtentPoint32() is exactly the same
2447 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2448 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
2449 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2450 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2454 static void test_SetTextJustification(void)
2464 static const char testText
[] =
2465 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2466 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2467 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2468 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2469 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2470 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2471 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2473 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2474 GetClientRect( hwnd
, &clientArea
);
2475 hdc
= GetDC( hwnd
);
2477 if (!is_font_installed("Times New Roman"))
2479 skip("Times New Roman is not installed\n");
2483 memset(&lf
, 0, sizeof lf
);
2484 lf
.lfCharSet
= ANSI_CHARSET
;
2485 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2486 lf
.lfWeight
= FW_DONTCARE
;
2488 lf
.lfQuality
= DEFAULT_QUALITY
;
2489 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2490 hfont
= create_font("Times New Roman", &lf
);
2491 SelectObject(hdc
, hfont
);
2493 testJustification(hdc
, testText
, &clientArea
);
2495 if (!pGetTextExtentExPointI
) goto done
;
2496 GetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2498 SetTextJustification(hdc
, 0, 0);
2499 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2500 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2501 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2502 SetTextJustification(hdc
, 4, 1);
2503 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2504 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2505 SetTextJustification(hdc
, 9, 2);
2506 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2507 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2508 SetTextJustification(hdc
, 7, 3);
2509 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2510 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2511 SetTextJustification(hdc
, 7, 3);
2512 SetTextCharacterExtra(hdc
, 2 );
2513 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2514 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2515 SetTextJustification(hdc
, 0, 0);
2516 SetTextCharacterExtra(hdc
, 0);
2517 size
.cx
= size
.cy
= 1234;
2518 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2519 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
2520 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2521 SetTextJustification(hdc
, 5, 1);
2522 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2523 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
2524 SetTextJustification(hdc
, 0, 0);
2526 SetMapMode( hdc
, MM_ANISOTROPIC
);
2527 SetWindowExtEx( hdc
, 2, 2, NULL
);
2528 GetClientRect( hwnd
, &clientArea
);
2529 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2530 testJustification(hdc
, testText
, &clientArea
);
2532 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2533 for (i
= 0; i
< 10; i
++)
2535 SetTextCharacterExtra(hdc
, i
);
2536 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2537 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2539 SetTextCharacterExtra(hdc
, 0);
2540 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2541 for (i
= 0; i
< 10; i
++)
2543 SetTextCharacterExtra(hdc
, i
);
2544 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2545 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2547 SetTextCharacterExtra(hdc
, 0);
2549 SetViewportExtEx( hdc
, 3, 3, NULL
);
2550 GetClientRect( hwnd
, &clientArea
);
2551 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2552 testJustification(hdc
, testText
, &clientArea
);
2554 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2555 for (i
= 0; i
< 10; i
++)
2557 SetTextCharacterExtra(hdc
, i
);
2558 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2559 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
2563 DeleteObject(hfont
);
2564 ReleaseDC(hwnd
, hdc
);
2565 DestroyWindow(hwnd
);
2568 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2572 HFONT hfont
, hfont_old
;
2579 assert(count
<= 128);
2581 memset(&lf
, 0, sizeof(lf
));
2583 lf
.lfCharSet
= charset
;
2585 lstrcpyA(lf
.lfFaceName
, "Arial");
2586 SetLastError(0xdeadbeef);
2587 hfont
= CreateFontIndirectA(&lf
);
2588 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2591 hfont_old
= SelectObject(hdc
, hfont
);
2593 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2594 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2596 SetLastError(0xdeadbeef);
2597 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2598 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
2600 if (charset
== SYMBOL_CHARSET
)
2602 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2603 ok(fs
.fsCsb
[0] & (1u << 31), "symbol encoding should be available\n");
2607 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2608 ok(!(fs
.fsCsb
[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2611 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2613 trace("Can't find codepage for charset %d\n", cs
);
2617 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2619 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2621 skip("Font code page %d, looking for code page %d\n",
2622 pGdiGetCodePage(hdc
), code_page
);
2630 WCHAR unicode_buf
[128];
2632 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2634 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2636 SetLastError(0xdeadbeef);
2637 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2638 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2639 count
, ret
, GetLastError());
2645 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2647 SetLastError(0xdeadbeef);
2648 ret
= GetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2649 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2650 count
, ret
, GetLastError());
2653 SelectObject(hdc
, hfont_old
);
2654 DeleteObject(hfont
);
2661 static void test_font_charset(void)
2663 static struct charset_data
2667 WORD font_idxA
[128], font_idxW
[128];
2670 { ANSI_CHARSET
, 1252 },
2671 { RUSSIAN_CHARSET
, 1251 },
2672 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2676 if (!pGetGlyphIndicesW
)
2678 win_skip("Skipping the font charset test on a Win9x platform\n");
2682 if (!is_font_installed("Arial"))
2684 skip("Arial is not installed\n");
2688 for (i
= 0; i
< ARRAY_SIZE(cd
); i
++)
2690 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2692 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2694 skip("Symbol or Wingdings is not installed\n");
2698 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2699 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2700 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2703 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2706 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2707 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2710 skip("Symbol or Wingdings is not installed\n");
2713 static void test_GdiGetCodePage(void)
2715 static const struct _matching_data
2717 UINT current_codepage
;
2720 UINT expected_codepage
;
2721 } matching_data
[] = {
2722 {1251, "Arial", ANSI_CHARSET
, 1252},
2723 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2725 {1252, "Arial", ANSI_CHARSET
, 1252},
2726 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2728 {1253, "Arial", ANSI_CHARSET
, 1252},
2729 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2731 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2732 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2733 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2735 { 936, "Arial", ANSI_CHARSET
, 936},
2736 { 936, "Tahoma", ANSI_CHARSET
, 936},
2737 { 936, "Simsun", ANSI_CHARSET
, 936},
2739 { 949, "Arial", ANSI_CHARSET
, 949},
2740 { 949, "Tahoma", ANSI_CHARSET
, 949},
2741 { 949, "Gulim", ANSI_CHARSET
, 949},
2743 { 950, "Arial", ANSI_CHARSET
, 950},
2744 { 950, "Tahoma", ANSI_CHARSET
, 950},
2745 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2754 if (!pGdiGetCodePage
)
2756 skip("GdiGetCodePage not available on this platform\n");
2762 for (i
= 0; i
< ARRAY_SIZE(matching_data
); i
++)
2764 /* only test data matched current locale codepage */
2765 if (matching_data
[i
].current_codepage
!= acp
)
2768 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2770 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2776 memset(&lf
, 0, sizeof(lf
));
2778 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2779 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2780 hfont
= CreateFontIndirectA(&lf
);
2781 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2783 hfont
= SelectObject(hdc
, hfont
);
2784 codepage
= pGdiGetCodePage(hdc
);
2785 ok(codepage
== matching_data
[i
].expected_codepage
,
2786 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2788 hfont
= SelectObject(hdc
, hfont
);
2789 DeleteObject(hfont
);
2791 /* CLIP_DFA_DISABLE turns off the font association */
2792 lf
.lfClipPrecision
= CLIP_DFA_DISABLE
;
2793 hfont
= CreateFontIndirectA(&lf
);
2794 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2796 hfont
= SelectObject(hdc
, hfont
);
2797 codepage
= pGdiGetCodePage(hdc
);
2798 ok(codepage
== 1252, "GdiGetCodePage returned %d\n", codepage
);
2800 hfont
= SelectObject(hdc
, hfont
);
2801 DeleteObject(hfont
);
2803 ReleaseDC(NULL
, hdc
);
2807 static void test_GetFontUnicodeRanges(void)
2811 HFONT hfont
, hfont_old
;
2815 if (!pGetFontUnicodeRanges
)
2817 win_skip("GetFontUnicodeRanges not available before W2K\n");
2821 memset(&lf
, 0, sizeof(lf
));
2822 lstrcpyA(lf
.lfFaceName
, "Arial");
2823 hfont
= create_font("Arial", &lf
);
2826 hfont_old
= SelectObject(hdc
, hfont
);
2828 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2829 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2831 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2832 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2834 gs
= heap_alloc_zero(size
);
2836 size
= pGetFontUnicodeRanges(hdc
, gs
);
2837 ok(size
, "GetFontUnicodeRanges failed\n");
2838 ok(gs
->cRanges
, "Unexpected ranges count.\n");
2842 SelectObject(hdc
, hfont_old
);
2843 DeleteObject(hfont
);
2844 ReleaseDC(NULL
, hdc
);
2847 struct enum_font_data
2853 struct enum_fullname_data
2859 struct enum_fullname_data_w
2865 struct enum_font_dataW
2871 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2873 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2874 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2876 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2878 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2880 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2882 if (efd
->total
>= efd
->size
)
2884 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2885 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2886 if (!efd
->lf
) return 0;
2888 efd
->lf
[efd
->total
++] = *lf
;
2893 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2895 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2896 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2898 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2900 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2902 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2904 if (efd
->total
>= efd
->size
)
2906 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2907 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2908 if (!efd
->lf
) return 0;
2910 efd
->lf
[efd
->total
++] = *lf
;
2915 static void get_charset_stats(struct enum_font_data
*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 get_charset_statsW(struct enum_font_dataW
*efd
,
2943 int *ansi_charset
, int *symbol_charset
,
2944 int *russian_charset
)
2949 *symbol_charset
= 0;
2950 *russian_charset
= 0;
2952 for (i
= 0; i
< efd
->total
; i
++)
2954 switch (efd
->lf
[i
].lfCharSet
)
2959 case SYMBOL_CHARSET
:
2960 (*symbol_charset
)++;
2962 case RUSSIAN_CHARSET
:
2963 (*russian_charset
)++;
2969 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2971 struct enum_font_data efd
;
2972 struct enum_font_dataW efdw
;
2975 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2977 if (*font_name
&& !is_truetype_font_installed(font_name
))
2979 skip("%s is not installed\n", font_name
);
2982 memset( &efd
, 0, sizeof(efd
) );
2983 memset( &efdw
, 0, sizeof(efdw
) );
2987 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2988 * while EnumFontFamiliesEx doesn't.
2990 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2993 * Use EnumFontFamiliesW since win98 crashes when the
2994 * second parameter is NULL using EnumFontFamilies
2997 SetLastError(0xdeadbeef);
2998 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2999 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
3002 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3003 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
3004 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
3005 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3006 ok(russian_charset
> 0 ||
3007 broken(russian_charset
== 0), /* NT4 */
3008 "NULL family should enumerate RUSSIAN_CHARSET\n");
3012 SetLastError(0xdeadbeef);
3013 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
3014 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
3017 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3018 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
3019 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
3020 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3021 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
3026 SetLastError(0xdeadbeef);
3027 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
3028 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
3029 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3031 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3033 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
3034 for (i
= 0; i
< efd
.total
; i
++)
3036 /* FIXME: remove completely once Wine is fixed */
3037 todo_wine_if(efd
.lf
[i
].lfCharSet
!= font_charset
)
3038 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3039 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3040 font_name
, efd
.lf
[i
].lfFaceName
);
3043 memset(&lf
, 0, sizeof(lf
));
3044 lf
.lfCharSet
= ANSI_CHARSET
;
3045 strcpy(lf
.lfFaceName
, font_name
);
3047 SetLastError(0xdeadbeef);
3048 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3049 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3050 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3051 if (font_charset
== SYMBOL_CHARSET
)
3054 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
3056 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3060 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
3061 for (i
= 0; i
< efd
.total
; i
++)
3063 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3065 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3066 font_name
, efd
.lf
[i
].lfFaceName
);
3070 /* DEFAULT_CHARSET should enumerate all available charsets */
3071 memset(&lf
, 0, sizeof(lf
));
3072 lf
.lfCharSet
= DEFAULT_CHARSET
;
3073 strcpy(lf
.lfFaceName
, font_name
);
3075 SetLastError(0xdeadbeef);
3076 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3077 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3078 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3079 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
3080 for (i
= 0; i
< efd
.total
; i
++)
3083 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3084 font_name
, efd
.lf
[i
].lfFaceName
);
3088 switch (font_charset
)
3091 ok(ansi_charset
> 0,
3092 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3094 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
3095 ok(russian_charset
> 0,
3096 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3098 case SYMBOL_CHARSET
:
3100 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
3102 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3103 ok(!russian_charset
,
3104 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3106 case DEFAULT_CHARSET
:
3107 ok(ansi_charset
> 0,
3108 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3109 ok(symbol_charset
> 0,
3110 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3111 ok(russian_charset
> 0,
3112 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3118 ok(ansi_charset
> 0,
3119 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3120 ok(symbol_charset
> 0,
3121 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3122 ok(russian_charset
> 0,
3123 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3126 memset(&lf
, 0, sizeof(lf
));
3127 lf
.lfCharSet
= SYMBOL_CHARSET
;
3128 strcpy(lf
.lfFaceName
, font_name
);
3130 SetLastError(0xdeadbeef);
3131 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3132 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
3133 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3134 if (*font_name
&& font_charset
== ANSI_CHARSET
)
3135 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
3138 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
3139 for (i
= 0; i
< efd
.total
; i
++)
3141 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3143 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3144 font_name
, efd
.lf
[i
].lfFaceName
);
3148 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3149 ok(symbol_charset
> 0,
3150 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3151 ok(!russian_charset
,
3152 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3157 heap_free( efd
.lf
);
3158 heap_free( efdw
.lf
);
3161 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
3163 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
3164 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
3165 const DWORD valid_bits
= 0x003f01ff;
3169 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
3171 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
3172 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
3173 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
3182 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3184 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
3186 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3188 if (efd
->total
>= efd
->size
)
3190 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
3191 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
3192 if (!efd
->lf
) return 0;
3194 efd
->lf
[efd
->total
++] = *lf
;
3199 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3201 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
3203 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3205 if (efnd
->total
>= efnd
->size
)
3207 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3208 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3209 if (!efnd
->elf
) return 0;
3211 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
3216 static INT CALLBACK
enum_fullname_data_proc_w( const LOGFONTW
*lf
, const TEXTMETRICW
*ntm
, DWORD type
, LPARAM lParam
)
3218 struct enum_fullname_data_w
*efnd
= (struct enum_fullname_data_w
*)lParam
;
3220 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3222 if (efnd
->total
>= efnd
->size
)
3224 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3225 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3226 if (!efnd
->elf
) return 0;
3228 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTW
*)lf
;
3233 static void test_EnumFontFamiliesEx_default_charset(void)
3235 struct enum_font_data efd
;
3236 LOGFONTA target
, enum_font
;
3242 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3243 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3248 memset(&enum_font
, 0, sizeof(enum_font
));
3249 enum_font
.lfCharSet
= csi
.ciCharset
;
3250 target
.lfFaceName
[0] = '\0';
3251 target
.lfCharSet
= csi
.ciCharset
;
3252 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3253 if (target
.lfFaceName
[0] == '\0') {
3254 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3257 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3258 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3259 target
.lfCharSet
= ANSI_CHARSET
;
3262 memset(&efd
, 0, sizeof(efd
));
3263 memset(&enum_font
, 0, sizeof(enum_font
));
3264 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3265 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3266 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3270 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3272 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3273 "(%s) got charset %d expected %d\n",
3274 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3280 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3282 HFONT hfont
, hfont_prev
;
3284 GLYPHMETRICS gm1
, gm2
;
3288 /* negative widths are handled just as positive ones */
3289 lf2
.lfWidth
= -lf
->lfWidth
;
3291 SetLastError(0xdeadbeef);
3292 hfont
= CreateFontIndirectA(lf
);
3293 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3294 check_font("original", lf
, hfont
);
3296 hfont_prev
= SelectObject(hdc
, hfont
);
3298 ret
= GetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3299 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3301 SelectObject(hdc
, hfont_prev
);
3302 DeleteObject(hfont
);
3303 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3307 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3308 memset(&gm1
, 0xab, sizeof(gm1
));
3309 SetLastError(0xdeadbeef);
3310 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3311 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3313 SelectObject(hdc
, hfont_prev
);
3314 DeleteObject(hfont
);
3316 SetLastError(0xdeadbeef);
3317 hfont
= CreateFontIndirectA(&lf2
);
3318 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3319 check_font("negative width", &lf2
, hfont
);
3321 hfont_prev
= SelectObject(hdc
, hfont
);
3323 memset(&gm2
, 0xbb, sizeof(gm2
));
3324 SetLastError(0xdeadbeef);
3325 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3326 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
3328 SelectObject(hdc
, hfont_prev
);
3329 DeleteObject(hfont
);
3331 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3332 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3333 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3334 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3335 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3336 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3337 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
3338 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3339 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3340 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3341 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3344 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3345 #include "pshpack2.h"
3349 SHORT xAvgCharWidth
;
3350 USHORT usWeightClass
;
3351 USHORT usWidthClass
;
3353 SHORT ySubscriptXSize
;
3354 SHORT ySubscriptYSize
;
3355 SHORT ySubscriptXOffset
;
3356 SHORT ySubscriptYOffset
;
3357 SHORT ySuperscriptXSize
;
3358 SHORT ySuperscriptYSize
;
3359 SHORT ySuperscriptXOffset
;
3360 SHORT ySuperscriptYOffset
;
3361 SHORT yStrikeoutSize
;
3362 SHORT yStrikeoutPosition
;
3365 ULONG ulUnicodeRange1
;
3366 ULONG ulUnicodeRange2
;
3367 ULONG ulUnicodeRange3
;
3368 ULONG ulUnicodeRange4
;
3371 USHORT usFirstCharIndex
;
3372 USHORT usLastCharIndex
;
3373 /* According to the Apple spec, original version didn't have the below fields,
3374 * version numbers were taken from the OpenType spec.
3376 /* version 0 (TrueType 1.5) */
3377 USHORT sTypoAscender
;
3378 USHORT sTypoDescender
;
3379 USHORT sTypoLineGap
;
3381 USHORT usWinDescent
;
3382 /* version 1 (TrueType 1.66) */
3383 ULONG ulCodePageRange1
;
3384 ULONG ulCodePageRange2
;
3385 /* version 2 (OpenType 1.2) */
3388 USHORT usDefaultChar
;
3390 USHORT usMaxContext
;
3391 /* version 4 (OpenType 1.6) */
3392 USHORT usLowerOpticalPointSize
;
3393 USHORT usUpperOpticalPointSize
;
3395 #include "poppack.h"
3397 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3410 } cmap_encoding_record
;
3418 BYTE glyph_ids
[256];
3428 USHORT search_range
;
3429 USHORT entry_selector
;
3432 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3435 USHORT start_count[seg_countx2 / 2];
3436 USHORT id_delta[seg_countx2 / 2];
3437 USHORT id_range_offset[seg_countx2 / 2];
3447 USHORT id_range_offset
;
3448 } cmap_format_4_seg
;
3450 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V4
*os2
, WORD family
, const char *name
)
3452 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3453 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3454 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3455 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3456 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3459 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3462 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3466 for(i
= 0; i
< 256; i
++)
3468 if(cmap
->glyph_ids
[i
] == 0) continue;
3470 if(*first
== 256) *first
= i
;
3472 if(*first
== 256) return FALSE
;
3476 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3478 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3479 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3480 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3481 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3482 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3485 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3488 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3489 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3493 for(i
= 0; i
< seg_count
; i
++)
3495 cmap_format_4_seg seg
;
3497 get_seg4(cmap
, i
, &seg
);
3499 if(seg
.start_count
> 0xfffe) break;
3501 if(*first
== 0x10000) *first
= seg
.start_count
;
3503 *last
= min(seg
.end_count
, 0xfffe);
3506 if(*first
== 0x10000) return FALSE
;
3510 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3513 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3515 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3517 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3518 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3531 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3534 cmap_header
*header
;
3539 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3540 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3541 if(size
== GDI_ERROR
) return FALSE
;
3543 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3544 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3545 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3546 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3548 cmap
= get_cmap(header
, 3, 1);
3550 *cmap_type
= cmap_ms_unicode
;
3553 cmap
= get_cmap(header
, 3, 0);
3554 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3558 *cmap_type
= cmap_none
;
3562 format
= GET_BE_WORD(*(WORD
*)cmap
);
3566 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3569 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3572 skip("unhandled cmap format %d\n", format
);
3577 HeapFree(GetProcessHeap(), 0, header
);
3581 #define TT_PLATFORM_APPLE_UNICODE 0
3582 #define TT_PLATFORM_MACINTOSH 1
3583 #define TT_PLATFORM_MICROSOFT 3
3584 #define TT_APPLE_ID_DEFAULT 0
3585 #define TT_APPLE_ID_ISO_10646 2
3586 #define TT_APPLE_ID_UNICODE_2_0 3
3587 #define TT_MS_ID_SYMBOL_CS 0
3588 #define TT_MS_ID_UNICODE_CS 1
3589 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3590 #define TT_NAME_ID_FONT_FAMILY 1
3591 #define TT_NAME_ID_FONT_SUBFAMILY 2
3592 #define TT_NAME_ID_UNIQUE_ID 3
3593 #define TT_NAME_ID_FULL_NAME 4
3594 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3596 typedef struct sfnt_name
3606 static const LANGID mac_langid_table
[] =
3608 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
3609 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
3610 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
3611 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
3612 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
3613 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
3614 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
3615 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
3616 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
3617 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
3618 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
3619 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
3620 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
3621 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
3622 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
3623 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
3624 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
3625 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
3626 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
3627 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3628 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
3629 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
3630 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
3631 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
3632 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
3633 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
3634 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
3635 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
3636 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
3637 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
3638 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
3639 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
3640 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
3641 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3642 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
3643 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
3644 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
3645 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
3646 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
3647 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
3648 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
3649 0, /* TT_MAC_LANGID_YIDDISH */
3650 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
3651 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
3652 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
3653 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
3654 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
3655 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
3656 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
3657 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
3658 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3659 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
3660 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
3661 0, /* TT_MAC_LANGID_MOLDAVIAN */
3662 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
3663 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
3664 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
3665 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
3666 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3667 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
3668 0, /* TT_MAC_LANGID_KURDISH */
3669 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
3670 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
3671 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
3672 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
3673 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
3674 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
3675 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
3676 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
3677 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
3678 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
3679 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
3680 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
3681 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
3682 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
3683 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
3684 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
3685 0, /* TT_MAC_LANGID_BURMESE */
3686 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
3687 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
3688 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
3689 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
3690 0, /* TT_MAC_LANGID_TAGALOG */
3691 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3692 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3693 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
3694 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
3695 0, /* TT_MAC_LANGID_GALLA */
3696 0, /* TT_MAC_LANGID_SOMALI */
3697 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
3698 0, /* TT_MAC_LANGID_RUANDA */
3699 0, /* TT_MAC_LANGID_RUNDI */
3700 0, /* TT_MAC_LANGID_CHEWA */
3701 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
3702 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
3703 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3704 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3705 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
3706 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
3707 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
3708 0, /* TT_MAC_LANGID_LATIN */
3709 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
3710 0, /* TT_MAC_LANGID_GUARANI */
3711 0, /* TT_MAC_LANGID_AYMARA */
3712 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
3713 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
3714 0, /* TT_MAC_LANGID_DZONGKHA */
3715 0, /* TT_MAC_LANGID_JAVANESE */
3716 0, /* TT_MAC_LANGID_SUNDANESE */
3717 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
3718 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
3719 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
3720 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
3721 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3722 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
3723 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
3724 0, /* TT_MAC_LANGID_TONGAN */
3725 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3726 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
3727 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3730 static inline WORD
get_mac_code_page( const sfnt_name
*name
)
3732 if (GET_BE_WORD(name
->encoding_id
) == TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
3733 return 10000 + GET_BE_WORD(name
->encoding_id
);
3736 static int match_name_table_language( const sfnt_name
*name
, LANGID lang
)
3741 switch (GET_BE_WORD(name
->platform_id
))
3743 case TT_PLATFORM_MICROSOFT
:
3744 res
+= 5; /* prefer the Microsoft name */
3745 switch (GET_BE_WORD(name
->encoding_id
))
3747 case TT_MS_ID_UNICODE_CS
:
3748 case TT_MS_ID_SYMBOL_CS
:
3749 name_lang
= GET_BE_WORD(name
->language_id
);
3755 case TT_PLATFORM_MACINTOSH
:
3756 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
3757 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3758 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3760 case TT_PLATFORM_APPLE_UNICODE
:
3761 res
+= 2; /* prefer Unicode encodings */
3762 switch (GET_BE_WORD(name
->encoding_id
))
3764 case TT_APPLE_ID_DEFAULT
:
3765 case TT_APPLE_ID_ISO_10646
:
3766 case TT_APPLE_ID_UNICODE_2_0
:
3767 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3768 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3777 if (name_lang
== lang
) res
+= 30;
3778 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
3779 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
3783 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3785 struct sfnt_name_header
3788 USHORT number_of_record
;
3789 USHORT storage_offset
;
3793 LONG size
, offset
, length
;
3798 int res
, best_lang
= 0, best_index
= -1;
3800 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3801 ok(size
!= GDI_ERROR
, "no name table found\n");
3802 if(size
== GDI_ERROR
) return FALSE
;
3804 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3805 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3806 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3808 header
= (void *)data
;
3809 header
->format
= GET_BE_WORD(header
->format
);
3810 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3811 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3812 if (header
->format
!= 0)
3814 skip("got format %u\n", header
->format
);
3817 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3819 skip("number records out of range: %d\n", header
->number_of_record
);
3822 if (header
->storage_offset
>= size
)
3824 skip("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3828 entry
= (void *)&header
[1];
3829 for (i
= 0; i
< header
->number_of_record
; i
++)
3831 if (GET_BE_WORD(entry
[i
].name_id
) != name_id
) continue;
3832 res
= match_name_table_language( &entry
[i
], language_id
);
3833 if (res
> best_lang
)
3840 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[best_index
].offset
);
3841 length
= GET_BE_WORD(entry
[best_index
].length
);
3842 if (offset
+ length
> size
)
3844 skip("entry %d is out of range\n", best_index
);
3847 if (length
>= out_size
)
3849 skip("buffer too small for entry %d\n", best_index
);
3853 name
= (WCHAR
*)(data
+ offset
);
3854 for (c
= 0; c
< length
/ 2; c
++)
3855 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3861 HeapFree(GetProcessHeap(), 0, data
);
3865 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3868 HFONT hfont
, hfont_old
;
3872 const char *font_name
= lf
->lfFaceName
;
3873 DWORD cmap_first
= 0, cmap_last
= 0;
3874 UINT ascent
, descent
, cell_height
;
3875 cmap_type cmap_type
;
3876 BOOL sys_lang_non_english
;
3878 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3881 SetLastError(0xdeadbeef);
3882 hfont
= CreateFontIndirectA(lf
);
3883 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3885 hfont_old
= SelectObject(hdc
, hfont
);
3887 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3888 if (size
== GDI_ERROR
)
3890 trace("OS/2 chunk was not found\n");
3893 if (size
> sizeof(tt_os2
))
3895 trace("got too large OS/2 chunk of size %u\n", size
);
3896 size
= sizeof(tt_os2
);
3899 memset(&tt_os2
, 0, sizeof(tt_os2
));
3900 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3901 ok(ret
>= TT_OS2_V0_SIZE
&& ret
<= size
, "GetFontData should return size from [%u,%u] not %u\n", TT_OS2_V0_SIZE
,
3904 SetLastError(0xdeadbeef);
3905 ret
= GetTextMetricsA(hdc
, &tmA
);
3906 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3908 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3910 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3914 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3915 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3916 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3920 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3921 descent
= abs((SHORT
)GET_BE_WORD(tt_os2
.usWinDescent
));
3922 cell_height
= ascent
+ descent
;
3923 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3924 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3926 version
= GET_BE_WORD(tt_os2
.version
);
3928 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3929 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3930 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3931 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3933 if (winetest_debug
> 1)
3934 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3935 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3936 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3938 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3943 case 1255: /* Hebrew */
3944 expect_last_W
= 0xf896;
3946 case 1257: /* Baltic */
3947 expect_last_W
= 0xf8fd;
3950 expect_last_W
= 0xf0ff;
3952 expect_break_W
= 0x20;
3953 expect_default_W
= expect_break_W
- 1;
3954 expect_first_A
= 0x1e;
3955 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3959 expect_first_W
= cmap_first
;
3960 expect_last_W
= cmap_last
;
3961 if(os2_first_char
<= 1)
3962 expect_break_W
= os2_first_char
+ 2;
3963 else if(os2_first_char
> 0xff)
3964 expect_break_W
= 0x20;
3966 expect_break_W
= os2_first_char
;
3967 expect_default_W
= expect_break_W
- 1;
3968 expect_first_A
= expect_default_W
- 1;
3969 expect_last_A
= min(expect_last_W
, 0xff);
3971 expect_break_A
= expect_break_W
;
3972 expect_default_A
= expect_default_W
;
3974 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3975 todo_wine_if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3976 ok(tmA
.tmFirstChar
== expect_first_A
||
3977 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3978 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3979 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3980 ok(tmA
.tmLastChar
== expect_last_A
||
3981 tmA
.tmLastChar
== 0xff /* win9x */,
3982 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3984 skip("tmLastChar is DBCS lead byte\n");
3985 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3986 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3987 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3988 "A: tmDefaultChar for %s got %02x expected %02x\n",
3989 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3992 SetLastError(0xdeadbeef);
3993 ret
= GetTextMetricsW(hdc
, &tmW
);
3994 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3995 "GetTextMetricsW error %u\n", GetLastError());
3998 /* Wine uses the os2 first char */
3999 todo_wine_if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
4000 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
4001 font_name
, tmW
.tmFirstChar
, expect_first_W
);
4003 /* Wine uses the os2 last char */
4004 todo_wine_if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
4005 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
4006 font_name
, tmW
.tmLastChar
, expect_last_W
);
4007 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
4008 font_name
, tmW
.tmBreakChar
, expect_break_W
);
4009 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
4010 "W: tmDefaultChar for %s got %02x expected %02x\n",
4011 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
4013 /* Test the aspect ratio while we have tmW */
4014 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
4015 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
4016 tmW
.tmDigitizedAspectX
, ret
);
4017 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
4018 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
4019 tmW
.tmDigitizedAspectX
, ret
);
4023 /* test FF_ values */
4024 switch(tt_os2
.panose
.bFamilyType
)
4028 case PAN_FAMILY_TEXT_DISPLAY
:
4029 case PAN_FAMILY_PICTORIAL
:
4031 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
4032 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
4034 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
4037 switch(tt_os2
.panose
.bSerifStyle
)
4042 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
4045 case PAN_SERIF_COVE
:
4046 case PAN_SERIF_OBTUSE_COVE
:
4047 case PAN_SERIF_SQUARE_COVE
:
4048 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
4049 case PAN_SERIF_SQUARE
:
4050 case PAN_SERIF_THIN
:
4051 case PAN_SERIF_BONE
:
4052 case PAN_SERIF_EXAGGERATED
:
4053 case PAN_SERIF_TRIANGLE
:
4054 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
4057 case PAN_SERIF_NORMAL_SANS
:
4058 case PAN_SERIF_OBTUSE_SANS
:
4059 case PAN_SERIF_PERP_SANS
:
4060 case PAN_SERIF_FLARED
:
4061 case PAN_SERIF_ROUNDED
:
4062 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
4067 case PAN_FAMILY_SCRIPT
:
4068 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
4071 case PAN_FAMILY_DECORATIVE
:
4072 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
4076 test_negative_width(hdc
, lf
);
4079 SelectObject(hdc
, hfont_old
);
4080 DeleteObject(hfont
);
4085 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4087 INT
*enumed
= (INT
*)lParam
;
4089 if (type
== TRUETYPE_FONTTYPE
)
4092 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
4097 static void test_GetTextMetrics(void)
4105 memset(&lf
, 0, sizeof(lf
));
4106 lf
.lfCharSet
= DEFAULT_CHARSET
;
4108 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
4113 static void test_nonexistent_font(void)
4121 { "Times New Roman Baltic", 186 },
4122 { "Times New Roman CE", 238 },
4123 { "Times New Roman CYR", 204 },
4124 { "Times New Roman Greek", 161 },
4125 { "Times New Roman TUR", 162 }
4133 { "MS Shell Dlg", 186 },
4134 { "MS Shell Dlg", 238 },
4135 { "MS Shell Dlg", 204 },
4136 { "MS Shell Dlg", 161 },
4137 { "MS Shell Dlg", 162 }
4143 INT cs
, expected_cs
, i
, ret
;
4144 char buf
[LF_FACESIZE
];
4146 expected_cs
= GetACP();
4147 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
4149 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
4152 expected_cs
= csi
.ciCharset
;
4153 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
4155 hdc
= CreateCompatibleDC(0);
4157 for (i
= 0; i
< ARRAY_SIZE(shell_subst
); i
++)
4159 ret
= is_font_installed(shell_subst
[i
].name
);
4160 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4161 ret
= is_truetype_font_installed(shell_subst
[i
].name
);
4162 ok(ret
|| broken(!ret
) /* win2000 */, "%s should be enumerated\n", shell_subst
[i
].name
);
4164 memset(&lf
, 0, sizeof(lf
));
4166 lf
.lfWeight
= FW_REGULAR
;
4167 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4168 hfont
= CreateFontIndirectA(&lf
);
4169 hfont
= SelectObject(hdc
, hfont
);
4170 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4171 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4172 cs
= GetTextCharset(hdc
);
4173 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, shell_subst
[i
].name
);
4175 DeleteObject(SelectObject(hdc
, hfont
));
4177 memset(&lf
, 0, sizeof(lf
));
4179 lf
.lfWeight
= FW_DONTCARE
;
4180 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4181 hfont
= CreateFontIndirectA(&lf
);
4182 hfont
= SelectObject(hdc
, hfont
);
4183 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4184 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4185 cs
= GetTextCharset(hdc
);
4186 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, shell_subst
[i
].name
);
4187 DeleteObject(SelectObject(hdc
, hfont
));
4190 if (!is_truetype_font_installed("Arial") ||
4191 !is_truetype_font_installed("Times New Roman"))
4194 skip("Arial or Times New Roman not installed\n");
4198 memset(&lf
, 0, sizeof(lf
));
4200 lf
.lfWeight
= FW_REGULAR
;
4201 lf
.lfCharSet
= ANSI_CHARSET
;
4202 lf
.lfPitchAndFamily
= FF_SWISS
;
4203 strcpy(lf
.lfFaceName
, "Nonexistent font");
4204 hfont
= CreateFontIndirectA(&lf
);
4205 hfont
= SelectObject(hdc
, hfont
);
4206 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4207 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
4208 cs
= GetTextCharset(hdc
);
4209 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4210 DeleteObject(SelectObject(hdc
, hfont
));
4212 memset(&lf
, 0, sizeof(lf
));
4214 lf
.lfWeight
= FW_DONTCARE
;
4215 strcpy(lf
.lfFaceName
, "Nonexistent font");
4216 hfont
= CreateFontIndirectA(&lf
);
4217 hfont
= SelectObject(hdc
, hfont
);
4218 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4219 todo_wine
/* Wine uses Arial for all substitutions */
4220 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
4221 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
4222 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4224 cs
= GetTextCharset(hdc
);
4225 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
4226 DeleteObject(SelectObject(hdc
, hfont
));
4228 memset(&lf
, 0, sizeof(lf
));
4230 lf
.lfWeight
= FW_REGULAR
;
4231 strcpy(lf
.lfFaceName
, "Nonexistent font");
4232 hfont
= CreateFontIndirectA(&lf
);
4233 hfont
= SelectObject(hdc
, hfont
);
4234 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4235 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4236 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
4237 cs
= GetTextCharset(hdc
);
4238 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4239 DeleteObject(SelectObject(hdc
, hfont
));
4241 memset(&lf
, 0, sizeof(lf
));
4243 lf
.lfWeight
= FW_DONTCARE
;
4244 strcpy(lf
.lfFaceName
, "Times New Roman");
4245 hfont
= CreateFontIndirectA(&lf
);
4246 hfont
= SelectObject(hdc
, hfont
);
4247 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4248 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
4249 cs
= GetTextCharset(hdc
);
4250 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4251 DeleteObject(SelectObject(hdc
, hfont
));
4253 for (i
= 0; i
< ARRAY_SIZE(font_subst
); i
++)
4255 ret
= is_font_installed(font_subst
[i
].name
);
4257 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4258 "%s should be enumerated\n", font_subst
[i
].name
);
4259 ret
= is_truetype_font_installed(font_subst
[i
].name
);
4261 ok(ret
|| broken(!ret
&& !i
) /* win2000 doesn't have Times New Roman Baltic substitution */,
4262 "%s should be enumerated\n", font_subst
[i
].name
);
4264 memset(&lf
, 0, sizeof(lf
));
4266 lf
.lfWeight
= FW_REGULAR
;
4267 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4268 hfont
= CreateFontIndirectA(&lf
);
4269 hfont
= SelectObject(hdc
, hfont
);
4270 cs
= GetTextCharset(hdc
);
4271 if (font_subst
[i
].charset
== expected_cs
)
4273 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4274 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4275 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
4279 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
4280 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4281 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
4282 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
4284 DeleteObject(SelectObject(hdc
, hfont
));
4286 memset(&lf
, 0, sizeof(lf
));
4288 lf
.lfWeight
= FW_DONTCARE
;
4289 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4290 hfont
= CreateFontIndirectA(&lf
);
4291 hfont
= SelectObject(hdc
, hfont
);
4292 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4293 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
4294 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
4295 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
4296 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4297 "got %s for font %s\n", buf
, font_subst
[i
].name
);
4298 cs
= GetTextCharset(hdc
);
4299 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4300 DeleteObject(SelectObject(hdc
, hfont
));
4306 struct font_realization_info
4321 WCHAR path
[MAX_PATH
];
4324 static void test_RealizationInfo(void)
4326 struct realization_info_t
4333 struct file_info file_info
;
4335 DWORD info
[4], info2
[32], read
;
4336 HFONT hfont
, hfont_old
;
4340 BYTE file
[16], data
[14];
4345 if(!pGdiRealizationInfo
)
4347 win_skip("GdiRealizationInfo not available\n");
4353 memset(info
, 0xcc, sizeof(info
));
4354 r
= pGdiRealizationInfo(hdc
, info
);
4355 ok(r
!= 0, "ret 0\n");
4356 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
4357 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4359 if (!is_truetype_font_installed("Tahoma"))
4361 skip("skipping GdiRealizationInfo with truetype font\n");
4365 memset(&lf
, 0, sizeof(lf
));
4366 strcpy(lf
.lfFaceName
, "Tahoma");
4368 lf
.lfWeight
= FW_BOLD
;
4370 hfont
= CreateFontIndirectA(&lf
);
4371 hfont_old
= SelectObject(hdc
, hfont
);
4373 memset(info
, 0xcc, sizeof(info
));
4374 r
= pGdiRealizationInfo(hdc
, info
);
4375 ok(r
!= 0, "ret 0\n");
4376 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
4377 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4379 if (pGetFontRealizationInfo
)
4381 struct font_realization_info
*fri
= (struct font_realization_info
*)info2
;
4382 struct realization_info_t
*ri
= (struct realization_info_t
*)info
;
4384 /* The first DWORD represents a struct size. On a
4385 newly rebooted system setting this to < 16 results
4386 in GetFontRealizationInfo failing. However there
4387 appears to be some caching going on which results
4388 in calls after a successful call also succeeding even
4389 if the size < 16. This means we can't reliably test
4392 memset(info2
, 0xcc, sizeof(info2
));
4394 r
= pGetFontRealizationInfo(hdc
, info2
);
4395 ok(r
!= 0, "ret 0\n");
4396 /* We may get the '24' version here if that has been previously
4398 ok(fri
->size
== 16 || fri
->size
== 24, "got %d\n", info2
[0]);
4399 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4400 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4401 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4402 ok(info2
[6] == 0xcccccccc, "got wrong dword 6, 0x%08x\n", info2
[6]);
4404 memset(info2
, 0xcc, sizeof(info2
));
4406 r
= pGetFontRealizationInfo(hdc
, info2
);
4407 ok(r
== FALSE
, "got %d\n", r
);
4409 memset(info2
, 0xcc, sizeof(info2
));
4411 r
= pGetFontRealizationInfo(hdc
, info2
);
4412 ok(r
!= 0, "ret 0\n");
4413 ok(fri
->size
== 24, "got %d\n", fri
->size
);
4414 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4415 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4416 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4417 ok(fri
->simulations
== 0x2, "got simulations flags 0x%04x\n", fri
->simulations
);
4418 ok(fri
->face_index
== 0, "got wrong face index %u\n", fri
->face_index
);
4419 ok(info2
[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4421 /* Test GetFontFileInfo() */
4422 /* invalid font id */
4423 SetLastError(0xdeadbeef);
4424 r
= pGetFontFileInfo(0xabababab, 0, &file_info
, sizeof(file_info
), &needed
);
4425 ok(r
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "ret %d gle %d\n", r
, GetLastError());
4428 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, sizeof(file_info
), &needed
);
4429 ok(r
!= 0, "Failed to get font file info, error %d.\n", GetLastError());
4433 ok(needed
> 0 && needed
< sizeof(file_info
), "Unexpected required size.\n");
4435 h
= CreateFileW(file_info
.path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
4436 ok(h
!= INVALID_HANDLE_VALUE
, "Unable to open file %d\n", GetLastError());
4438 GetFileTime(h
, NULL
, NULL
, &time
);
4439 ok(!CompareFileTime(&file_info
.time
, &time
), "time mismatch\n");
4440 GetFileSizeEx(h
, &size
);
4441 ok(file_info
.size
.QuadPart
== size
.QuadPart
, "size mismatch\n");
4443 /* Read first 16 bytes from the file */
4444 ReadFile(h
, file
, sizeof(file
), &read
, NULL
);
4447 /* shorter buffer */
4448 SetLastError(0xdeadbeef);
4449 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, needed
- 1, &needed
);
4450 ok(r
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "ret %d gle %d\n", r
, GetLastError());
4453 /* Get bytes 2 - 16 using GetFontFileData */
4454 r
= pGetFontFileData(fri
->instance_id
, 0, 2, data
, sizeof(data
));
4455 ok(r
!= 0, "ret 0 gle %d\n", GetLastError());
4457 ok(!memcmp(data
, file
+ 2, sizeof(data
)), "mismatch\n");
4460 DeleteObject(SelectObject(hdc
, hfont_old
));
4466 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4467 the nul in the count of characters copied when the face name buffer is not
4468 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4469 always includes it. */
4470 static void test_GetTextFace(void)
4472 static const char faceA
[] = "Tahoma";
4473 static const WCHAR faceW
[] = L
"Tahoma";
4476 char bufA
[LF_FACESIZE
];
4477 WCHAR bufW
[LF_FACESIZE
];
4482 if(!is_font_installed("Tahoma"))
4484 skip("Tahoma is not installed so skipping this test\n");
4489 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
4490 f
= CreateFontIndirectA(&fA
);
4491 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
4494 g
= SelectObject(dc
, f
);
4495 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
4496 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
4497 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
4499 /* Play with the count arg. */
4501 n
= GetTextFaceA(dc
, 0, bufA
);
4502 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4503 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4506 n
= GetTextFaceA(dc
, 1, bufA
);
4507 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4508 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4510 bufA
[0] = 'x'; bufA
[1] = 'y';
4511 n
= GetTextFaceA(dc
, 2, bufA
);
4512 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
4513 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
4515 n
= GetTextFaceA(dc
, 0, NULL
);
4516 ok(n
== sizeof faceA
||
4517 broken(n
== 0), /* win98, winMe */
4518 "GetTextFaceA returned %d\n", n
);
4520 DeleteObject(SelectObject(dc
, g
));
4521 ReleaseDC(NULL
, dc
);
4524 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
4525 SetLastError(0xdeadbeef);
4526 f
= CreateFontIndirectW(&fW
);
4527 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4529 win_skip("CreateFontIndirectW is not implemented\n");
4532 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
4535 g
= SelectObject(dc
, f
);
4536 n
= GetTextFaceW(dc
, ARRAY_SIZE(bufW
), bufW
);
4537 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4538 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
4540 /* Play with the count arg. */
4542 n
= GetTextFaceW(dc
, 0, bufW
);
4543 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
4544 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4547 n
= GetTextFaceW(dc
, 1, bufW
);
4548 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
4549 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4551 bufW
[0] = 'x'; bufW
[1] = 'y';
4552 n
= GetTextFaceW(dc
, 2, bufW
);
4553 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4554 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4556 n
= GetTextFaceW(dc
, 0, NULL
);
4557 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4559 DeleteObject(SelectObject(dc
, g
));
4560 ReleaseDC(NULL
, dc
);
4563 static void test_orientation(void)
4565 static const char test_str
[11] = "Test String";
4568 HFONT hfont
, old_hfont
;
4571 if (!is_truetype_font_installed("Arial"))
4573 skip("Arial is not installed\n");
4577 hdc
= CreateCompatibleDC(0);
4578 memset(&lf
, 0, sizeof(lf
));
4579 lstrcpyA(lf
.lfFaceName
, "Arial");
4581 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4582 hfont
= create_font("orientation", &lf
);
4583 old_hfont
= SelectObject(hdc
, hfont
);
4584 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4585 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
4586 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
4587 SelectObject(hdc
, old_hfont
);
4588 DeleteObject(hfont
);
4592 static void test_oemcharset(void)
4596 HFONT hfont
, old_hfont
;
4599 hdc
= CreateCompatibleDC(0);
4600 ZeroMemory(&lf
, sizeof(lf
));
4602 lf
.lfCharSet
= OEM_CHARSET
;
4603 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4604 lstrcpyA(lf
.lfFaceName
, "Terminal");
4605 hfont
= CreateFontIndirectA(&lf
);
4606 old_hfont
= SelectObject(hdc
, hfont
);
4607 charset
= GetTextCharset(hdc
);
4609 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4610 hfont
= SelectObject(hdc
, old_hfont
);
4611 GetObjectA(hfont
, sizeof(clf
), &clf
);
4612 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4613 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4614 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4615 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
4616 DeleteObject(hfont
);
4620 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4621 const TEXTMETRICA
*lpntme
,
4622 DWORD FontType
, LPARAM lParam
)
4624 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4626 LOGFONTA lf
= *lpelfe
;
4630 /* skip bitmap, proportional or vertical font */
4631 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4632 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4633 lf
.lfFaceName
[0] == '@')
4636 /* skip linked font */
4637 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4638 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4641 /* skip linked font, like SimSun-ExtB */
4642 switch (lpelfe
->lfCharSet
) {
4643 case SHIFTJIS_CHARSET
:
4644 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4646 case GB2312_CHARSET
:
4647 case CHINESEBIG5_CHARSET
:
4648 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4650 case HANGEUL_CHARSET
:
4651 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4654 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4660 /* test with an odd height */
4663 hfont
= CreateFontIndirectA(&lf
);
4666 *(HFONT
*)lParam
= hfont
;
4672 static void test_GetGlyphOutline(void)
4675 GLYPHMETRICS gm
, gm2
;
4677 HFONT hfont
, old_hfont
;
4679 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4680 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4688 {ANSI_CHARSET
, 0x30, 0x30},
4689 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4690 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4691 {GB2312_CHARSET
, 0x8141, 0x4e04},
4692 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4696 if (!is_truetype_font_installed("Tahoma"))
4698 skip("Tahoma is not installed\n");
4702 hdc
= CreateCompatibleDC(0);
4703 memset(&lf
, 0, sizeof(lf
));
4705 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4706 SetLastError(0xdeadbeef);
4707 hfont
= CreateFontIndirectA(&lf
);
4708 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4709 old_hfont
= SelectObject(hdc
, hfont
);
4711 memset(&gm
, 0, sizeof(gm
));
4712 SetLastError(0xdeadbeef);
4713 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4714 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4716 memset(&gm
, 0, sizeof(gm
));
4717 SetLastError(0xdeadbeef);
4718 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4719 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4720 ok(GetLastError() == 0xdeadbeef ||
4721 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
4722 "expected 0xdeadbeef, got %u\n", GetLastError());
4724 memset(&gm
, 0, sizeof(gm
));
4725 SetLastError(0xdeadbeef);
4726 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4727 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4728 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
4730 memset(&gm
, 0, sizeof(gm
));
4731 SetLastError(0xdeadbeef);
4732 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4733 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4735 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4736 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4739 /* test for needed buffer size request on space char */
4740 memset(&gm
, 0, sizeof(gm
));
4741 SetLastError(0xdeadbeef);
4742 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4743 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4745 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4746 ok(gm
.gmBlackBoxX
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxX
);
4747 ok(gm
.gmBlackBoxY
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxY
);
4750 /* requesting buffer size for space char + error */
4751 memset(&gm
, 0, sizeof(gm
));
4752 SetLastError(0xdeadbeef);
4753 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4754 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4756 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4757 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
4758 ok(gm
.gmBlackBoxX
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxX
);
4759 ok(gm
.gmBlackBoxY
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxY
);
4762 /* test GetGlyphOutline with a buffer too small */
4763 SetLastError(0xdeadbeef);
4764 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_NATIVE
, &gm
, sizeof(i
), &i
, &mat
);
4765 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4766 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4768 for (i
= 0; i
< ARRAY_SIZE(fmt
); ++i
)
4772 memset(&gm
, 0xab, sizeof(gm
));
4773 SetLastError(0xdeadbeef);
4774 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4775 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4777 if (fmt
[i
] == GGO_METRICS
)
4778 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4780 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4781 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4782 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4785 memset(&gm
, 0xab, sizeof(gm
));
4786 SetLastError(0xdeadbeef);
4787 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4788 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4790 if (fmt
[i
] == GGO_METRICS
)
4791 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4793 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4794 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4795 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4798 memset(&gm
, 0xab, sizeof(gm
));
4799 SetLastError(0xdeadbeef);
4800 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4801 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4803 if (fmt
[i
] == GGO_METRICS
)
4804 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4806 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4807 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4808 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4811 memset(&gm
, 0xab, sizeof(gm
));
4812 SetLastError(0xdeadbeef);
4813 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4814 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4816 if (fmt
[i
] == GGO_METRICS
) {
4817 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4818 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4819 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4823 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4824 memset(&gm2
, 0xab, sizeof(gm2
));
4825 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4826 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4831 SelectObject(hdc
, old_hfont
);
4832 DeleteObject(hfont
);
4834 for (i
= 0; i
< ARRAY_SIZE(c
); ++i
)
4836 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4839 lf
.lfFaceName
[0] = '\0';
4840 lf
.lfCharSet
= c
[i
].cs
;
4841 lf
.lfPitchAndFamily
= 0;
4842 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4844 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4848 old_hfont
= SelectObject(hdc
, hfont
);
4850 /* expected to ignore superfluous bytes (single-byte character) */
4851 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4852 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4853 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4855 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4856 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4857 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4859 /* expected to ignore superfluous bytes (double-byte character) */
4860 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4861 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4862 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4863 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4865 /* expected to match wide-char version results */
4866 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4867 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4869 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4871 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4874 DeleteObject(SelectObject(hdc
, hfont
));
4877 DeleteObject(SelectObject(hdc
, old_hfont
));
4881 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4882 ok(ret
> 0, "GetObject error %u\n", GetLastError());
4884 ret
= GetTextMetricsA(hdc
, &tm
);
4885 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4886 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4887 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4888 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4889 "expected %d, got %d (%s:%d)\n",
4890 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4892 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4893 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4894 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4895 "expected %d, got %d (%s:%d)\n",
4896 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4899 hfont
= CreateFontIndirectA(&lf
);
4900 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4901 DeleteObject(SelectObject(hdc
, hfont
));
4902 ret
= GetTextMetricsA(hdc
, &tm
);
4903 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4904 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4905 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4906 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4907 "expected %d, got %d (%s:%d)\n",
4908 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4910 lf
.lfItalic
= FALSE
;
4911 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4912 hfont
= CreateFontIndirectA(&lf
);
4913 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
4914 DeleteObject(SelectObject(hdc
, hfont
));
4915 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4916 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
4917 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4918 "expected %d, got %d (%s:%d)\n",
4919 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4921 hfont
= SelectObject(hdc
, old_hfont
);
4922 DeleteObject(hfont
);
4928 /* bug #9995: there is a limit to the character width that can be specified */
4929 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4935 int ave_width
, height
, width
, ratio
;
4937 if (!is_truetype_font_installed( fontname
)) {
4938 skip("%s is not installed\n", fontname
);
4941 hdc
= CreateCompatibleDC(0);
4942 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4943 /* select width = 0 */
4944 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4945 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4946 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4948 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4949 of
= SelectObject( hdc
, hf
);
4950 ret
= GetTextMetricsA( hdc
, &tm
);
4951 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
4952 height
= tm
.tmHeight
;
4953 ave_width
= tm
.tmAveCharWidth
;
4954 SelectObject( hdc
, of
);
4957 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4959 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4960 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4961 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4962 ok(hf
!= 0, "CreateFont failed\n");
4963 of
= SelectObject(hdc
, hf
);
4964 ret
= GetTextMetricsA(hdc
, &tm
);
4965 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4966 SelectObject(hdc
, of
);
4969 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4975 ratio
= width
/ height
;
4977 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4980 static void test_GetCharacterPlacement(void)
4982 GCP_RESULTSA result
;
4988 hdc
= CreateCompatibleDC(0);
4989 ok(!!hdc
, "CreateCompatibleDC failed\n");
4991 memset(&result
, 0, sizeof(result
));
4992 result
.lStructSize
= sizeof(result
);
4993 result
.lpCaretPos
= pos
;
4994 result
.lpGlyphs
= glyphs
;
4995 result
.nGlyphs
= 20;
4999 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, &result
, 0);
5000 ok(size
, "GetCharacterPlacementA failed!\n");
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 ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
5007 result
.nGlyphs
= 20;
5008 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 0, 0, &result
, 0);
5009 ok(!size2
, "Expected GetCharacterPlacementA to fail\n");
5010 ok(result
.nGlyphs
== 20, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5011 ok(glyphs
[0] == '!', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5012 ok(pos
[0] == -1, "Unexpected caret position %d\n", pos
[0]);
5014 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, NULL
, 0);
5015 ok(size2
, "GetCharacterPlacementA failed!\n");
5016 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
5018 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, NULL
, GCP_REORDER
);
5019 ok(size2
, "GetCharacterPlacementA failed!\n");
5020 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
5024 result
.nGlyphs
= 20;
5025 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, &result
, GCP_REORDER
);
5026 ok(size
, "GetCharacterPlacementA failed!\n");
5027 ok(size
== size2
, "GetCharacterPlacementA returned different result: %u vs %u\n", size2
, size
);
5028 ok(result
.nGlyphs
== 9, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5029 ok(glyphs
[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5030 todo_wine
ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
5035 static void test_CreateFontIndirect(void)
5037 LOGFONTA lf
, getobj_lf
;
5040 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
5042 memset(&lf
, 0, sizeof(lf
));
5043 lf
.lfCharSet
= ANSI_CHARSET
;
5044 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5047 lf
.lfQuality
= DEFAULT_QUALITY
;
5048 lf
.lfItalic
= FALSE
;
5049 lf
.lfWeight
= FW_DONTCARE
;
5051 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5053 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5054 hfont
= CreateFontIndirectA(&lf
);
5055 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5056 SetLastError(0xdeadbeef);
5057 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
5058 ok(ret
, "GetObject failed: %d\n", GetLastError());
5059 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
5060 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
5061 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
5062 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
5063 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
5064 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
5065 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
5066 DeleteObject(hfont
);
5070 static void test_CreateFontIndirectEx(void)
5072 ENUMLOGFONTEXDVA lfex
;
5075 if (!pCreateFontIndirectExA
)
5077 win_skip("CreateFontIndirectExA is not available\n");
5081 if (!is_truetype_font_installed("Arial"))
5083 skip("Arial is not installed\n");
5087 SetLastError(0xdeadbeef);
5088 hfont
= pCreateFontIndirectExA(NULL
);
5089 ok(hfont
== NULL
, "got %p\n", hfont
);
5090 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
5092 memset(&lfex
, 0, sizeof(lfex
));
5093 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
5094 hfont
= pCreateFontIndirectExA(&lfex
);
5095 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
5097 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
5098 DeleteObject(hfont
);
5101 static void test_realization_info(const char *name
, DWORD size
, BOOL is_memory_resource
)
5103 struct font_realization_info info
;
5104 struct file_info file_info
;
5105 HFONT hfont
, hfont_prev
;
5112 if (!pGetFontRealizationInfo
)
5115 memset(&lf
, 0, sizeof(lf
));
5117 strcpy(lf
.lfFaceName
, name
);
5119 hfont
= CreateFontIndirectA(&lf
);
5120 ok(hfont
!= 0, "Failed to create a font, %u.\n", GetLastError());
5124 hfont_prev
= SelectObject(hdc
, hfont
);
5125 ok(hfont_prev
!= NULL
, "Failed to select font.\n");
5127 memset(&info
, 0xcc, sizeof(info
));
5128 info
.size
= sizeof(info
);
5129 ret
= pGetFontRealizationInfo(hdc
, (DWORD
*)&info
);
5130 ok(ret
!= 0, "Unexpected return value %d.\n", ret
);
5132 ok((info
.flags
& 0xf) == 0x3, "Unexpected flags %#x.\n", info
.flags
);
5133 ok(info
.cache_num
!= 0, "Unexpected cache num %u.\n", info
.cache_num
);
5134 ok(info
.instance_id
!= 0, "Unexpected instance id %u.\n", info
.instance_id
);
5135 ok(info
.simulations
== 0, "Unexpected simulations %#x.\n", info
.simulations
);
5136 ok(info
.face_index
== 0, "Unexpected face index %u.\n", info
.face_index
);
5138 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, NULL
);
5139 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5140 ret
, GetLastError());
5143 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, &needed
);
5144 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5145 ret
, GetLastError());
5147 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, 0, NULL
);
5148 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5149 ret
, GetLastError());
5151 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
- 1, NULL
);
5152 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %d.\n",
5153 ret
, GetLastError());
5155 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
, NULL
);
5156 ok(ret
!= 0, "Failed to get font file info, ret %d gle %d.\n", ret
, GetLastError());
5158 memset(&file_info
, 0xcc, sizeof(file_info
));
5159 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, sizeof(file_info
), NULL
);
5160 ok(ret
!= 0, "Failed to get font file info, ret %d gle %d.\n", ret
, GetLastError());
5163 ok(is_memory_resource
? file_info
.size
.QuadPart
== size
: file_info
.size
.QuadPart
> 0, "Unexpected file size.\n");
5164 ok(is_memory_resource
? !file_info
.path
[0] : file_info
.path
[0], "Unexpected file path %s.\n",
5165 wine_dbgstr_w(file_info
.path
));
5168 size
= file_info
.size
.LowPart
;
5169 data
= HeapAlloc(GetProcessHeap(), 0, size
+ 16);
5171 memset(data
, 0xcc, size
);
5172 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
);
5173 ok(ret
!= 0, "Failed to get font file data, %d\n", GetLastError());
5174 ok(*(DWORD
*)data
== 0x00000100, "Unexpected sfnt header version %#x.\n", *(DWORD
*)data
);
5175 ok(*(WORD
*)(data
+ 4) == 0x0e00, "Unexpected table count %#x.\n", *(WORD
*)(data
+ 4));
5177 /* Larger than font data size. */
5178 memset(data
, 0xcc, size
);
5179 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
+ 16);
5180 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %d\n",
5181 ret
, GetLastError());
5182 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5185 memset(data
, 0xcc, size
);
5186 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
- 16);
5187 ok(ret
!= 0, "Failed to get font file data, %d\n", GetLastError());
5188 ok(*(DWORD
*)data
== 0x1000000, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5190 memset(data
, 0xcc, size
);
5191 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
);
5192 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %d\n",
5193 ret
, GetLastError());
5194 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5196 /* Zero buffer size. */
5197 memset(data
, 0xcc, size
);
5198 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, 0);
5200 ok(ret
== 0 && GetLastError() == ERROR_NOACCESS
, "Unexpected return value %d, error %d\n", ret
, GetLastError());
5201 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#x.\n", *(DWORD
*)data
);
5203 HeapFree(GetProcessHeap(), 0, data
);
5205 SelectObject(hdc
, hfont_prev
);
5206 DeleteObject(hfont
);
5207 ReleaseDC(NULL
, hdc
);
5210 static void test_AddFontMemResource(void)
5212 char ttf_name
[MAX_PATH
];
5214 DWORD font_size
, num_fonts
;
5218 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
5220 win_skip("AddFontMemResourceEx is not available on this platform\n");
5224 SetLastError(0xdeadbeef);
5225 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
5226 ok(!ret
, "AddFontMemResourceEx should fail\n");
5227 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5228 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5231 SetLastError(0xdeadbeef);
5232 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
5233 ok(!ret
, "AddFontMemResourceEx should fail\n");
5234 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5235 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5238 SetLastError(0xdeadbeef);
5239 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
5240 ok(!ret
, "AddFontMemResourceEx should fail\n");
5241 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5242 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5245 SetLastError(0xdeadbeef);
5246 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
5247 ok(!ret
, "AddFontMemResourceEx should fail\n");
5248 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5249 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5252 /* Now with scalable font */
5253 bRet
= write_ttf_file("wine_test.ttf", ttf_name
);
5254 ok(bRet
, "Failed to create test font file.\n");
5256 font
= load_font(ttf_name
, &font_size
);
5257 ok(font
!= NULL
, "Failed to map font file.\n");
5259 bRet
= is_truetype_font_installed("wine_test");
5260 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5263 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5264 ok(ret
!= 0, "Failed to add resource, %d.\n", GetLastError());
5265 ok(num_fonts
== 1, "Unexpected number of fonts %u.\n", num_fonts
);
5267 bRet
= is_truetype_font_installed("wine_test");
5269 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5271 test_realization_info("wine_test", font_size
, TRUE
);
5273 bRet
= pRemoveFontMemResourceEx(ret
);
5274 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
5278 bRet
= DeleteFileA(ttf_name
);
5279 ok(bRet
, "Failed to delete font file, %d.\n", GetLastError());
5281 font
= load_font("sserife.fon", &font_size
);
5284 skip("Unable to locate and load font sserife.fon\n");
5288 SetLastError(0xdeadbeef);
5289 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
5290 ok(!ret
, "AddFontMemResourceEx should fail\n");
5291 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5292 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5295 SetLastError(0xdeadbeef);
5296 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
5297 ok(!ret
, "AddFontMemResourceEx should fail\n");
5298 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5299 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5302 num_fonts
= 0xdeadbeef;
5303 SetLastError(0xdeadbeef);
5304 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
5305 ok(!ret
, "AddFontMemResourceEx should fail\n");
5306 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5307 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5309 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5311 if (0) /* hangs under windows 2000 */
5313 num_fonts
= 0xdeadbeef;
5314 SetLastError(0xdeadbeef);
5315 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
5316 ok(!ret
, "AddFontMemResourceEx should fail\n");
5317 ok(GetLastError() == 0xdeadbeef,
5318 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5320 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5323 num_fonts
= 0xdeadbeef;
5324 SetLastError(0xdeadbeef);
5325 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5326 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
5327 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5328 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
5332 SetLastError(0xdeadbeef);
5333 bRet
= pRemoveFontMemResourceEx(ret
);
5334 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
5336 /* test invalid pointer to number of loaded fonts */
5337 font
= load_font("sserife.fon", &font_size
);
5338 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
5340 SetLastError(0xdeadbeef);
5341 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
5342 ok(!ret
, "AddFontMemResourceEx should fail\n");
5343 ok(GetLastError() == 0xdeadbeef,
5344 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
5347 SetLastError(0xdeadbeef);
5348 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
5349 ok(!ret
, "AddFontMemResourceEx should fail\n");
5350 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5351 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
5357 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5361 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5363 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5365 lf
= (LOGFONTA
*)lparam
;
5370 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5375 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5377 lf
= (LOGFONTA
*)lparam
;
5378 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
5381 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
5388 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5393 static void test_EnumFonts(void)
5399 if (!is_truetype_font_installed("Arial"))
5401 skip("Arial is not installed\n");
5405 /* Windows uses localized font face names, so Arial Bold won't be found */
5406 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
5408 skip("User locale is not English, skipping the test\n");
5412 hdc
= CreateCompatibleDC(0);
5414 /* check that the enumproc's retval is returned */
5415 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
5416 ok(ret
== 0xcafe, "got %08x\n", ret
);
5418 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
5419 ok(!ret
, "font Arial is not enumerated\n");
5420 ret
= strcmp(lf
.lfFaceName
, "Arial");
5421 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5422 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5424 strcpy(lf
.lfFaceName
, "Arial");
5425 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5426 ok(!ret
, "font Arial is not enumerated\n");
5427 ret
= strcmp(lf
.lfFaceName
, "Arial");
5428 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5429 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
5431 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5432 ok(!ret
, "font Arial Bold is not enumerated\n");
5433 ret
= strcmp(lf
.lfFaceName
, "Arial");
5434 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5435 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5437 strcpy(lf
.lfFaceName
, "Arial Bold");
5438 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5439 ok(ret
, "font Arial Bold should not be enumerated\n");
5441 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
5442 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
5443 ret
= strcmp(lf
.lfFaceName
, "Arial");
5444 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5445 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
5447 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
5448 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5449 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
5451 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5452 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5454 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
5455 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5456 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5461 static INT CALLBACK
enum_ms_shell_dlg_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5463 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5465 if (0) /* Disabled to limit console spam */
5466 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5467 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5469 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5470 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg") != 0) return 1;
5472 if (efnd
->total
>= efnd
->size
)
5474 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5475 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5476 if (!efnd
->elf
) return 0;
5478 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5482 static INT CALLBACK
enum_ms_shell_dlg2_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5484 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5486 if (0) /* Disabled to limit console spam */
5487 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
5488 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5490 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5491 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg 2") != 0) return 1;
5493 if (efnd
->total
>= efnd
->size
)
5495 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5496 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5497 if (!efnd
->elf
) return 0;
5499 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5503 static void test_EnumFonts_subst(void)
5508 struct enum_fullname_data efnd
;
5510 ret
= is_font_installed("MS Shell Dlg");
5511 ok(ret
, "MS Shell Dlg should be enumerated\n");
5512 ret
= is_truetype_font_installed("MS Shell Dlg");
5513 ok(ret
, "MS Shell Dlg should be enumerated as a TrueType font\n");
5515 ret
= is_font_installed("MS Shell Dlg 2");
5516 ok(ret
, "MS Shell Dlg 2 should be enumerated\n");
5517 ret
= is_truetype_font_installed("MS Shell Dlg 2");
5518 ok(ret
, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5520 hdc
= CreateCompatibleDC(0);
5522 memset(&efnd
, 0, sizeof(efnd
));
5523 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5524 ok(ret
, "MS Shell Dlg should not be enumerated\n");
5525 ok(!efnd
.total
, "MS Shell Dlg should not be enumerated\n");
5527 memset(&lf
, 0, sizeof(lf
));
5528 lf
.lfCharSet
= DEFAULT_CHARSET
;
5531 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
5532 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5533 ok(!ret
, "MS Shell Dlg should be enumerated\n");
5534 ok(efnd
.total
> 0, "MS Shell Dlg should be enumerated\n");
5537 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
5538 ok(!ret
, "expected MS Shell Dlg, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5539 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
5540 ok(ret
, "did not expect MS Shell Dlg\n");
5544 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5545 ok(ret
, "MS Shell Dlg 2 should not be enumerated\n");
5546 ok(!efnd
.total
, "MS Shell Dlg 2 should not be enumerated\n");
5549 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
5550 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5551 ok(!ret
, "MS Shell Dlg 2 should be enumerated\n");
5552 ok(efnd
.total
> 0, "MS Shell Dlg 2 should be enumerated\n");
5555 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
5556 ok(!ret
, "expected MS Shell Dlg 2, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5557 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
5558 ok(ret
, "did not expect MS Shell Dlg 2\n");
5561 heap_free(efnd
.elf
);
5565 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5567 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
5568 const char *fullname
= (const char *)lParam
;
5570 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
5575 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
5580 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
5587 static void test_fullname(void)
5589 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5590 WCHAR bufW
[LF_FULLFACESIZE
];
5591 char bufA
[LF_FULLFACESIZE
];
5598 hdc
= CreateCompatibleDC(0);
5599 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5601 memset(&lf
, 0, sizeof(lf
));
5602 lf
.lfCharSet
= ANSI_CHARSET
;
5603 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5606 lf
.lfQuality
= DEFAULT_QUALITY
;
5607 lf
.lfItalic
= FALSE
;
5608 lf
.lfWeight
= FW_DONTCARE
;
5610 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5612 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
5614 skip("%s is not installed\n", TestName
[i
]);
5618 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5619 hfont
= CreateFontIndirectA(&lf
);
5620 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5622 of
= SelectObject(hdc
, hfont
);
5625 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5626 ok(ret
, "face full name could not be read\n");
5627 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
5628 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
5629 SelectObject(hdc
, of
);
5630 DeleteObject(hfont
);
5635 static WCHAR
*prepend_at(WCHAR
*family
)
5640 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
5645 static void test_fullname2_helper(const char *Family
)
5647 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
5648 struct enum_fullname_data efnd
;
5655 DWORD otm_size
, ret
, buf_size
;
5656 OUTLINETEXTMETRICA
*otm
;
5657 BOOL want_vertical
, get_vertical
;
5658 want_vertical
= ( Family
[0] == '@' );
5660 hdc
= CreateCompatibleDC(0);
5661 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5663 memset(&lf
, 0, sizeof(lf
));
5664 lf
.lfCharSet
= DEFAULT_CHARSET
;
5665 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5668 lf
.lfQuality
= DEFAULT_QUALITY
;
5669 lf
.lfItalic
= FALSE
;
5670 lf
.lfWeight
= FW_DONTCARE
;
5671 strcpy(lf
.lfFaceName
, Family
);
5672 memset(&efnd
, 0, sizeof(efnd
));
5673 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
5674 if (efnd
.total
== 0)
5675 skip("%s is not installed\n", lf
.lfFaceName
);
5677 for (i
= 0; i
< efnd
.total
; i
++)
5679 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
5680 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
5681 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
5683 get_vertical
= ( FamilyName
[0] == '@' );
5684 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
5686 lstrcpyA(lf
.lfFaceName
, FaceName
);
5687 hfont
= CreateFontIndirectA(&lf
);
5688 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5690 of
= SelectObject(hdc
, hfont
);
5691 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
5692 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
5693 if (buf_size
== GDI_ERROR
) continue;
5695 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5696 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5698 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5699 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5700 memset(otm
, 0, otm_size
);
5701 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
5702 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
5703 if (ret
== 0) continue;
5707 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5708 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5709 ok(ret
, "%s: FAMILY (family name) could not be read\n", FamilyName
);
5710 if (want_vertical
) bufW
= prepend_at(bufW
);
5711 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5712 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
5713 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
5714 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
5718 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
5719 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5720 ok(ret
, "FULL_NAME (face name) could not be read\n");
5721 if (want_vertical
) bufW
= prepend_at(bufW
);
5722 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5723 ok(!lstrcmpA(FaceName
, bufA
), "%s: font face names don't match: returned %s, expect %s\n", FamilyName
, FaceName
, bufA
);
5724 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
5725 ok(!lstrcmpA(FaceName
, otmStr
), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName
, FaceName
, otmStr
);
5729 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5730 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5731 ok(ret
, "%s: SUBFAMILY (style name) could not be read\n", FamilyName
);
5732 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5733 ok(!lstrcmpA(StyleName
, bufA
), "%s: style names don't match: returned %s, expect %s\n", FamilyName
, StyleName
, bufA
);
5734 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
5735 ok(!lstrcmpA(StyleName
, otmStr
), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName
, StyleName
, otmStr
);
5739 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
5740 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5741 ok(ret
, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName
);
5742 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5743 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
5744 ok(!lstrcmpA(otmStr
, bufA
), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName
, otmStr
, bufA
);
5746 SelectObject(hdc
, of
);
5747 DeleteObject(hfont
);
5749 HeapFree(GetProcessHeap(), 0, otm
);
5750 HeapFree(GetProcessHeap(), 0, bufW
);
5751 HeapFree(GetProcessHeap(), 0, bufA
);
5753 heap_free(efnd
.elf
);
5757 static void test_fullname2(void)
5759 test_fullname2_helper("Arial");
5760 test_fullname2_helper("DejaVu Sans");
5761 test_fullname2_helper("Lucida Sans");
5762 test_fullname2_helper("Tahoma");
5763 test_fullname2_helper("Webdings");
5764 test_fullname2_helper("Wingdings");
5765 test_fullname2_helper("SimSun");
5766 test_fullname2_helper("NSimSun");
5767 test_fullname2_helper("MingLiu");
5768 test_fullname2_helper("PMingLiu");
5769 test_fullname2_helper("WenQuanYi Micro Hei");
5770 test_fullname2_helper("MS UI Gothic");
5771 test_fullname2_helper("Ume UI Gothic");
5772 test_fullname2_helper("MS Gothic");
5773 test_fullname2_helper("Ume Gothic");
5774 test_fullname2_helper("MS PGothic");
5775 test_fullname2_helper("Ume P Gothic");
5776 test_fullname2_helper("Gulim");
5777 test_fullname2_helper("Batang");
5778 test_fullname2_helper("UnBatang");
5779 test_fullname2_helper("UnDotum");
5780 test_fullname2_helper("@SimSun");
5781 test_fullname2_helper("@NSimSun");
5782 test_fullname2_helper("@MingLiu");
5783 test_fullname2_helper("@PMingLiu");
5784 test_fullname2_helper("@WenQuanYi Micro Hei");
5785 test_fullname2_helper("@MS UI Gothic");
5786 test_fullname2_helper("@Ume UI Gothic");
5787 test_fullname2_helper("@MS Gothic");
5788 test_fullname2_helper("@Ume Gothic");
5789 test_fullname2_helper("@MS PGothic");
5790 test_fullname2_helper("@Ume P Gothic");
5791 test_fullname2_helper("@Gulim");
5792 test_fullname2_helper("@Batang");
5793 test_fullname2_helper("@UnBatang");
5794 test_fullname2_helper("@UnDotum");
5798 static void test_GetGlyphOutline_empty_contour(void)
5802 HFONT hfont
, hfont_prev
;
5803 TTPOLYGONHEADER
*header
;
5808 memset(&lf
, 0, sizeof(lf
));
5810 lstrcpyA(lf
.lfFaceName
, "wine_test");
5812 hfont
= CreateFontIndirectA(&lf
);
5813 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5817 hfont_prev
= SelectObject(hdc
, hfont
);
5818 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5820 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5821 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5823 header
= (TTPOLYGONHEADER
*)buf
;
5824 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5825 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
5826 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
5827 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
5828 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5829 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5830 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5831 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
5833 SelectObject(hdc
, hfont_prev
);
5834 DeleteObject(hfont
);
5835 ReleaseDC(NULL
, hdc
);
5838 static void test_GetGlyphOutline_metric_clipping(void)
5842 HFONT hfont
, hfont_prev
;
5848 memset(&lf
, 0, sizeof(lf
));
5850 lstrcpyA(lf
.lfFaceName
, "wine_test");
5852 SetLastError(0xdeadbeef);
5853 hfont
= CreateFontIndirectA(&lf
);
5854 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5858 hfont_prev
= SelectObject(hdc
, hfont
);
5859 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5861 SetLastError(0xdeadbeef);
5862 ret
= GetTextMetricsA(hdc
, &tm
);
5863 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
5865 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5866 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5867 "Glyph top(%d) exceeds ascent(%d)\n",
5868 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5869 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5870 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5871 "Glyph bottom(%d) exceeds descent(%d)\n",
5872 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5874 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5875 GetTextMetricsW(hdc
, &tmW
);
5877 ok( tmW
.tmLastChar
== 0xfffe, "got %04x\n", tmW
.tmLastChar
);
5879 SelectObject(hdc
, hfont_prev
);
5880 DeleteObject(hfont
);
5881 ReleaseDC(NULL
, hdc
);
5884 static void test_GetGlyphOutline_character(void)
5886 HFONT hfont
, hfont_old
;
5890 GLYPHMETRICS gm1
, gm2
, gmn
;
5891 char test_chars
[] = { 'A', 'D', '!', '\0' };
5894 memset(&lf
, 0, sizeof(lf
));
5896 lstrcpyA(lf
.lfFaceName
, "wine_test");
5898 hfont
= CreateFontIndirectA(&lf
);
5899 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5903 hfont_old
= SelectObject(hdc
, hfont
);
5904 ok(hfont_old
!= NULL
, "SelectObject failed\n");
5906 ret
= GetGlyphOutlineW(hdc
, 'Z', GGO_METRICS
, &gmn
, 0, NULL
, &mat
);
5907 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed to default to .notdef for character 'Z'\n");
5909 for (current_char
= test_chars
; *current_char
!= '\0'; current_char
++)
5911 ret
= GetGlyphOutlineW(hdc
, *current_char
, GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
5912 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for '%c'\n", *current_char
);
5913 ok(memcmp(&gm1
, &gmn
, sizeof(gmn
)) != 0, "the test character '%c' matches .notdef\n", *current_char
);
5915 ret
= GetGlyphOutlineW(hdc
, 0x10000 + *current_char
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
5916 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for 0x10000 + '%c'\n", *current_char
);
5917 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for character 0x10000 + '%c'\n", *current_char
);
5920 ret
= GetGlyphOutlineW(hdc
, 0x3, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm1
, 0, NULL
, &mat
);
5921 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for glyph index 0x3\n");
5923 ret
= GetGlyphOutlineW(hdc
, 0xFFFF, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5924 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW for nonexistent glyph index 0xFFFF has succeeded\n");
5926 ret
= GetGlyphOutlineW(hdc
, 0x10003, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5927 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW for index 0x10003 has failed\n");
5928 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for glyph 0x10003\n");
5930 SelectObject(hdc
, hfont_old
);
5931 DeleteObject(hfont
);
5932 ReleaseDC(NULL
, hdc
);
5935 static void test_fstype_fixup(void)
5939 HFONT hfont
, hfont_prev
;
5941 OUTLINETEXTMETRICA
*otm
;
5944 memset(&lf
, 0, sizeof(lf
));
5946 lstrcpyA(lf
.lfFaceName
, "wine_test");
5948 SetLastError(0xdeadbeef);
5949 hfont
= CreateFontIndirectA(&lf
);
5950 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
5954 hfont_prev
= SelectObject(hdc
, hfont
);
5955 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5957 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5958 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5959 otm
->otmSize
= sizeof(*otm
);
5960 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
5961 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
5963 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5964 valid bits are 1, 2, 3, 8, 9. */
5965 ok((otm
->otmfsType
& ~0x30e) == 0, "fsType %#x\n", otm
->otmfsType
);
5967 HeapFree(GetProcessHeap(), 0, otm
);
5969 SelectObject(hdc
, hfont_prev
);
5970 DeleteObject(hfont
);
5971 ReleaseDC(NULL
, hdc
);
5974 static void test_CreateScalableFontResource(void)
5976 char ttf_name
[MAX_PATH
];
5977 char tmp_path
[MAX_PATH
];
5978 char fot_name
[MAX_PATH
];
5983 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
5985 win_skip("AddFontResourceExA is not available on this platform\n");
5989 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5991 skip("Failed to create ttf file for testing\n");
5995 trace("created %s\n", ttf_name
);
5997 ret
= is_truetype_font_installed("wine_test");
5998 ok(!ret
, "font wine_test should not be enumerated\n");
6000 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
6001 ok(ret
, "GetTempPath() error %d\n", GetLastError());
6002 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
6003 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
6005 ret
= GetFileAttributesA(fot_name
);
6006 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
6008 SetLastError(0xdeadbeef);
6009 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
6010 ok(!ret
, "CreateScalableFontResource() should fail\n");
6011 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
6013 SetLastError(0xdeadbeef);
6014 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
6015 ok(!ret
, "CreateScalableFontResource() should fail\n");
6016 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
6018 file_part
= strrchr(ttf_name
, '\\');
6019 SetLastError(0xdeadbeef);
6020 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
6021 ok(!ret
, "CreateScalableFontResource() should fail\n");
6022 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
6024 SetLastError(0xdeadbeef);
6025 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
6026 ok(!ret
, "CreateScalableFontResource() should fail\n");
6027 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
6029 SetLastError(0xdeadbeef);
6030 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
6031 ok(!ret
, "CreateScalableFontResource() should fail\n");
6032 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
6034 ret
= DeleteFileA(fot_name
);
6035 ok(ret
, "DeleteFile() error %d\n", GetLastError());
6037 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6038 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6040 /* test public font resource */
6041 SetLastError(0xdeadbeef);
6042 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
6043 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
6045 ret
= is_truetype_font_installed("wine_test");
6046 ok(!ret
, "font wine_test should not be enumerated\n");
6048 SetLastError(0xdeadbeef);
6049 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6050 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6052 ret
= is_truetype_font_installed("wine_test");
6053 ok(ret
, "font wine_test should be enumerated\n");
6055 test_GetGlyphOutline_empty_contour();
6056 test_GetGlyphOutline_metric_clipping();
6057 test_GetGlyphOutline_character();
6058 test_fstype_fixup();
6060 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6061 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
6063 SetLastError(0xdeadbeef);
6064 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6065 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6067 ret
= is_truetype_font_installed("wine_test");
6068 ok(!ret
, "font wine_test should not be enumerated\n");
6070 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6071 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6073 /* test refcounting */
6074 for (i
= 0; i
< 5; i
++)
6076 SetLastError(0xdeadbeef);
6077 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6078 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6080 for (i
= 0; i
< 5; i
++)
6082 SetLastError(0xdeadbeef);
6083 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6084 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6086 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6087 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6089 DeleteFileA(fot_name
);
6091 /* test hidden font resource */
6092 SetLastError(0xdeadbeef);
6093 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
6094 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
6096 ret
= is_truetype_font_installed("wine_test");
6097 ok(!ret
, "font wine_test should not be enumerated\n");
6099 SetLastError(0xdeadbeef);
6100 ret
= pAddFontResourceExA(fot_name
, 0, 0);
6101 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
6103 ret
= is_truetype_font_installed("wine_test");
6105 ok(!ret
, "font wine_test should not be enumerated\n");
6107 /* XP allows removing a private font added with 0 flags */
6108 SetLastError(0xdeadbeef);
6109 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6110 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6112 ret
= is_truetype_font_installed("wine_test");
6113 ok(!ret
, "font wine_test should not be enumerated\n");
6115 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
6116 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6118 DeleteFileA(fot_name
);
6119 DeleteFileA(ttf_name
);
6122 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
6125 HFONT hfont
, hfont_prev
;
6129 static const WCHAR str
[] = { 0x2025 };
6131 *installed
= is_truetype_font_installed(name
);
6135 lf
.lfEscapement
= 0;
6136 lf
.lfOrientation
= 0;
6137 lf
.lfWeight
= FW_DONTCARE
;
6141 lf
.lfCharSet
= DEFAULT_CHARSET
;
6142 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
6143 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6144 lf
.lfQuality
= DEFAULT_QUALITY
;
6145 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
6146 strcpy(lf
.lfFaceName
, name
);
6148 hfont
= CreateFontIndirectA(&lf
);
6149 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
6153 hfont_prev
= SelectObject(hdc
, hfont
);
6154 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
6156 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
6157 ok(ret
, "GetTextFaceA failed\n");
6158 *selected
= !strcmp(facename
, name
);
6160 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
6161 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6163 memset(gm
, 0, sizeof *gm
);
6165 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
6166 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
6168 SelectObject(hdc
, hfont_prev
);
6169 DeleteObject(hfont
);
6170 ReleaseDC(NULL
, hdc
);
6173 static void check_vertical_metrics(const char *face
)
6176 HFONT hfont
, hfont_prev
;
6179 GLYPHMETRICS rgm
, vgm
;
6180 const UINT code
= 0x5EAD, height
= 1000;
6183 OUTLINETEXTMETRICA otm
;
6184 USHORT numOfLongVerMetrics
;
6188 memset(&lf
, 0, sizeof(lf
));
6189 strcpy(lf
.lfFaceName
, face
);
6190 lf
.lfHeight
= -height
;
6191 lf
.lfCharSet
= DEFAULT_CHARSET
;
6192 lf
.lfEscapement
= lf
.lfOrientation
= 900;
6193 hfont
= CreateFontIndirectA(&lf
);
6194 hfont_prev
= SelectObject(hdc
, hfont
);
6195 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
6196 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6197 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
6198 ok(ret
, "GetCharABCWidthsW failed\n");
6199 DeleteObject(SelectObject(hdc
, hfont_prev
));
6201 memset(&lf
, 0, sizeof(lf
));
6202 strcpy(lf
.lfFaceName
, "@");
6203 strcat(lf
.lfFaceName
, face
);
6204 lf
.lfHeight
= -height
;
6205 lf
.lfCharSet
= DEFAULT_CHARSET
;
6206 hfont
= CreateFontIndirectA(&lf
);
6207 hfont_prev
= SelectObject(hdc
, hfont
);
6208 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
6209 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6210 ret
= GetCharABCWidthsW(hdc
, code
, code
, &vabc
);
6211 ok(ret
, "GetCharABCWidthsW failed\n");
6212 ok(vabc
.abcA
== vgm
.gmptGlyphOrigin
.x
, "expected %d, got %d\n",
6213 vabc
.abcA
, vgm
.gmptGlyphOrigin
.x
);
6214 ok(vabc
.abcB
== vgm
.gmBlackBoxX
, "expected %d, got %d\n",
6215 vabc
.abcB
, vgm
.gmBlackBoxX
);
6216 ok(vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
== vgm
.gmCellIncX
,
6217 "expected %d, got %d\n",
6218 vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
, vgm
.gmCellIncX
);
6220 memset(&otm
, 0, sizeof(otm
));
6221 otm
.otmSize
= sizeof(otm
);
6222 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
6223 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
6225 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
6226 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
6228 SHORT topSideBearing
;
6230 if (!pGetGlyphIndicesW
) {
6231 win_skip("GetGlyphIndices is not available on this platform\n");
6234 ret
= pGetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
6235 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
6236 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
6237 if (numOfLongVerMetrics
> idx
)
6238 offset
= idx
* 2 + 1;
6240 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
6241 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
6242 &topSideBearing
, sizeof(SHORT
));
6243 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
6244 topSideBearing
= GET_BE_WORD(topSideBearing
);
6245 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
6246 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
6247 "expected %d, got %d\n",
6248 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
6253 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
6254 "got %d, expected rgm.origin.x(%d) + vgm.cellIncX(%d) + descent(%d)\n",
6255 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
6258 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
||
6259 broken(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
- otm
.otmTextMetrics
.tmDescent
) /* win2k */,
6260 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6261 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
6263 DeleteObject(SelectObject(hdc
, hfont_prev
));
6264 ReleaseDC(NULL
, hdc
);
6267 static void test_vertical_font(void)
6269 char ttf_name
[MAX_PATH
];
6271 BOOL ret
, installed
, selected
;
6274 const char* face_list
[] = {
6275 "@WineTestVertical", /* has vmtx table */
6276 "@Ume Gothic", /* doesn't have vmtx table */
6277 "@MS UI Gothic", /* has vmtx table, available on native */
6280 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
6282 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
6286 if (!write_ttf_file("vertical.ttf", ttf_name
))
6288 skip("Failed to create ttf file for testing\n");
6292 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6293 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6295 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
6296 ok(installed
, "WineTestVertical is not installed\n");
6297 ok(selected
, "WineTestVertical is not selected\n");
6298 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6299 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6300 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6302 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
6303 ok(installed
, "@WineTestVertical is not installed\n");
6304 ok(selected
, "@WineTestVertical is not selected\n");
6305 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6306 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6307 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6309 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
6311 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++) {
6312 const char* face
= face_list
[i
];
6313 if (!is_truetype_font_installed(face
)) {
6314 skip("%s is not installed\n", face
);
6317 check_vertical_metrics(&face
[1]);
6320 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6321 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
6323 DeleteFileA(ttf_name
);
6326 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
6327 DWORD type
, LPARAM lParam
)
6329 if (lf
->lfFaceName
[0] == '@') {
6335 static void test_east_asian_font_selection(void)
6338 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
6339 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
6344 for (i
= 0; i
< ARRAY_SIZE(charset
); i
++)
6348 char face_name
[LF_FACESIZE
];
6351 memset(&lf
, 0, sizeof lf
);
6352 lf
.lfFaceName
[0] = '\0';
6353 lf
.lfCharSet
= charset
[i
];
6355 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
6357 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
6361 hfont
= CreateFontIndirectA(&lf
);
6362 hfont
= SelectObject(hdc
, hfont
);
6363 memset(face_name
, 0, sizeof face_name
);
6364 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6365 ok(ret
&& face_name
[0] != '@',
6366 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6367 DeleteObject(SelectObject(hdc
, hfont
));
6369 memset(&lf
, 0, sizeof lf
);
6370 strcpy(lf
.lfFaceName
, "@");
6371 lf
.lfCharSet
= charset
[i
];
6372 hfont
= CreateFontIndirectA(&lf
);
6373 hfont
= SelectObject(hdc
, hfont
);
6374 memset(face_name
, 0, sizeof face_name
);
6375 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6376 ok(ret
&& face_name
[0] == '@',
6377 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6378 DeleteObject(SelectObject(hdc
, hfont
));
6380 ReleaseDC(NULL
, hdc
);
6383 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
6385 HDC hdc
= CreateCompatibleDC(0);
6390 hfont
= CreateFontIndirectA(lf
);
6391 ok(hfont
!= 0, "CreateFontIndirect failed\n");
6393 SelectObject(hdc
, hfont
);
6394 ret
= GetTextMetricsA(hdc
, &tm
);
6395 ok(ret
, "GetTextMetrics failed\n");
6396 ret
= tm
.tmDigitizedAspectX
;
6397 if (height
) *height
= tm
.tmHeight
;
6400 DeleteObject(hfont
);
6405 static void test_stock_fonts(void)
6407 static const int font
[] =
6409 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
6410 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6412 static const struct test_data
6414 int charset
, weight
, height
, height_pixels
, dpi
;
6415 const char face_name
[LF_FACESIZE
];
6419 { /* ANSI_FIXED_FONT */
6420 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_ARABIC
},
6421 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_HEBREW
},
6422 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
6423 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
6426 { /* ANSI_VAR_FONT */
6427 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
6428 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
6432 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6433 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6434 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6435 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6436 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6437 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6440 { /* DEVICE_DEFAULT_FONT */
6441 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6442 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6443 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6444 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6445 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6446 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6449 { /* DEFAULT_GUI_FONT */
6450 { SHIFTJIS_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6451 { SHIFTJIS_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6452 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
6453 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
6454 { HANGEUL_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6455 { HANGEUL_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6456 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
6457 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
6458 { GB2312_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6459 { GB2312_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6460 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
6461 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
6462 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
6463 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
6464 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6465 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6471 for (i
= 0; i
< ARRAY_SIZE(font
); i
++)
6477 hfont
= GetStockObject(font
[i
]);
6478 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
6480 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
6481 if (ret
!= sizeof(lf
))
6484 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
6488 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
6490 if ((lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
) ||
6491 (system_lang_id
!= td
[i
][j
].lang_id
&& td
[i
][j
].lang_id
!= LANG_NEUTRAL
) ||
6492 (td
[i
][j
].face_name
[0] != '?' && strcmp(lf
.lfFaceName
, td
[i
][j
].face_name
)))
6497 ret
= get_font_dpi(&lf
, &height
);
6498 if (ret
!= td
[i
][j
].dpi
)
6500 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6501 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
6505 /* FIXME: Remove once Wine is fixed */
6506 todo_wine_if (td
[i
][j
].dpi
!= 96 &&
6507 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6508 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
6509 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6510 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
6511 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
6513 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
6514 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
6515 if (td
[i
][j
].face_name
[0] == '?')
6517 /* Wine doesn't have this font, skip this case for now.
6518 Actually, the face name is localized on Windows and varies
6519 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6520 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
6524 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
);
6531 static void test_max_height(void)
6535 HFONT hfont
, hfont_old
;
6536 TEXTMETRICA tm1
, tm
;
6538 LONG invalid_height
[] = { -65536, -123456, 123456 };
6541 memset(&tm1
, 0, sizeof(tm1
));
6542 memset(&lf
, 0, sizeof(lf
));
6543 strcpy(lf
.lfFaceName
, "Tahoma");
6548 /* get 1 ppem value */
6549 hfont
= CreateFontIndirectA(&lf
);
6550 hfont_old
= SelectObject(hdc
, hfont
);
6551 r
= GetTextMetricsA(hdc
, &tm1
);
6552 ok(r
, "GetTextMetrics failed\n");
6553 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6554 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
6555 DeleteObject(SelectObject(hdc
, hfont_old
));
6557 /* test the largest value */
6558 lf
.lfHeight
= -((1 << 16) - 1);
6559 hfont
= CreateFontIndirectA(&lf
);
6560 hfont_old
= SelectObject(hdc
, hfont
);
6561 memset(&tm
, 0, sizeof(tm
));
6562 r
= GetTextMetricsA(hdc
, &tm
);
6563 ok(r
, "GetTextMetrics failed\n");
6564 ok(tm
.tmHeight
> tm1
.tmHeight
,
6565 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6566 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
6567 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6568 DeleteObject(SelectObject(hdc
, hfont_old
));
6570 /* test an invalid value */
6571 for (i
= 0; i
< ARRAY_SIZE(invalid_height
); i
++) {
6572 lf
.lfHeight
= invalid_height
[i
];
6573 hfont
= CreateFontIndirectA(&lf
);
6574 hfont_old
= SelectObject(hdc
, hfont
);
6575 memset(&tm
, 0, sizeof(tm
));
6576 r
= GetTextMetricsA(hdc
, &tm
);
6577 ok(r
, "GetTextMetrics failed\n");
6578 ok(tm
.tmHeight
== tm1
.tmHeight
,
6579 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
6580 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
6581 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6582 DeleteObject(SelectObject(hdc
, hfont_old
));
6585 ReleaseDC(NULL
, hdc
);
6589 static void test_vertical_order(void)
6591 struct enum_font_data efd
;
6596 hdc
= CreateCompatibleDC(0);
6597 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6599 memset(&lf
, 0, sizeof(lf
));
6600 lf
.lfCharSet
= DEFAULT_CHARSET
;
6601 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6604 lf
.lfQuality
= DEFAULT_QUALITY
;
6605 lf
.lfItalic
= FALSE
;
6606 lf
.lfWeight
= FW_DONTCARE
;
6607 memset( &efd
, 0, sizeof(efd
) );
6608 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
6609 for (i
= 0; i
< efd
.total
; i
++)
6611 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
6612 for (j
= 0; j
< efd
.total
; j
++)
6614 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
6616 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
6621 heap_free( efd
.lf
);
6625 static void test_GetCharWidth32(void)
6635 if (!pGetCharWidth32W
)
6637 win_skip("GetCharWidth32W not available on this platform\n");
6641 memset(&lf
, 0, sizeof(lf
));
6642 strcpy(lf
.lfFaceName
, "System");
6645 hfont
= CreateFontIndirectA(&lf
);
6647 hfont
= SelectObject(hdc
, hfont
);
6649 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6650 ok(ret
, "GetCharWidth32W should have succeeded\n");
6651 ret
= GetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
6652 ok(ret
, "GetCharWidth32A should have succeeded\n");
6653 ok (bufferA
== bufferW
, "Widths should be the same\n");
6654 ok (bufferA
> 0," Width should be greater than zero\n");
6656 hfont
= SelectObject(hdc
, hfont
);
6657 DeleteObject(hfont
);
6658 ReleaseDC(NULL
, hdc
);
6660 memset(&lf
, 0, sizeof(lf
));
6661 strcpy(lf
.lfFaceName
, "Tahoma");
6664 hfont
= CreateFontIndirectA(&lf
);
6665 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
6668 SetMapMode( hdc
, MM_ANISOTROPIC
);
6669 SelectObject(hdc
, hfont
);
6671 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6672 ok(ret
, "GetCharWidth32W should have succeeded\n");
6673 ok (bufferW
> 0," Width should be greater than zero\n");
6674 SetWindowExtEx(hdc
, -1,-1,NULL
);
6675 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6676 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6677 ok(ret
, "GetCharWidth32W should have succeeded\n");
6678 ok (bufferW
> 0," Width should be greater than zero\n");
6679 SetGraphicsMode(hdc
, GM_ADVANCED
);
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 SetWindowExtEx(hdc
, 1,1,NULL
);
6684 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6685 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6686 ok(ret
, "GetCharWidth32W should have succeeded\n");
6687 ok (bufferW
> 0," Width should be greater than zero\n");
6688 SetGraphicsMode(hdc
, GM_ADVANCED
);
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");
6693 ReleaseDC(hwnd
, hdc
);
6694 DestroyWindow(hwnd
);
6696 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
6699 SetMapMode( hdc
, MM_ANISOTROPIC
);
6700 SelectObject(hdc
, hfont
);
6702 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6703 ok(ret
, "GetCharWidth32W should have succeeded\n");
6704 ok (bufferW
> 0," Width should be greater than zero\n");
6705 SetWindowExtEx(hdc
, -1,-1,NULL
);
6706 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6707 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6708 ok(ret
, "GetCharWidth32W should have succeeded\n");
6709 ok (bufferW
> 0," Width should be greater than zero\n");
6710 SetGraphicsMode(hdc
, GM_ADVANCED
);
6711 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6712 ok(ret
, "GetCharWidth32W should have succeeded\n");
6713 ok (bufferW
> 0," Width should be greater than zero\n");
6714 SetWindowExtEx(hdc
, 1,1,NULL
);
6715 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6716 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6717 ok(ret
, "GetCharWidth32W should have succeeded\n");
6718 ok (bufferW
> 0," Width should be greater than zero\n");
6719 SetGraphicsMode(hdc
, GM_ADVANCED
);
6720 ret
= pGetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6721 ok(ret
, "GetCharWidth32W should have succeeded\n");
6722 ok (bufferW
> 0," Width should be greater than zero\n");
6724 ReleaseDC(hwnd
, hdc
);
6725 DestroyWindow(hwnd
);
6726 DeleteObject(hfont
);
6729 static void test_fake_bold_font(void)
6731 static const MAT2 x2_mat
= { {0,2}, {0,0}, {0,0}, {0,2} };
6744 /* Test outline font */
6745 memset(&lf
, 0, sizeof(lf
));
6746 strcpy(lf
.lfFaceName
, "Wingdings");
6747 lf
.lfCharSet
= SYMBOL_CHARSET
;
6751 for (i
= 0; i
<= 1; i
++)
6753 HFONT hfont
, hfont_old
;
6755 lf
.lfWeight
= i
? FW_BOLD
: FW_NORMAL
;
6756 hfont
= CreateFontIndirectA(&lf
);
6757 hfont_old
= SelectObject(hdc
, hfont
);
6759 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6760 ok(ret
, "got %d\n", ret
);
6761 ret
= GetCharABCWidthsA(hdc
, 0x76, 0x76, &data
[i
].abc
);
6762 ok(ret
, "got %d\n", ret
);
6763 data
[i
].w
= data
[i
].abc
.abcA
+ data
[i
].abc
.abcB
+ data
[i
].abc
.abcC
;
6764 r
= GetGlyphOutlineA(hdc
, 0x76, GGO_METRICS
, &data
[i
].gm
, 0, NULL
, &x2_mat
);
6765 ok(r
!= GDI_ERROR
, "got %d\n", ret
);
6767 SelectObject(hdc
, hfont_old
);
6768 DeleteObject(hfont
);
6770 ReleaseDC(NULL
, hdc
);
6772 /* compare results (outline) */
6773 ok(data
[0].tm
.tmHeight
== data
[1].tm
.tmHeight
,
6774 "expected %d, got %d\n", data
[0].tm
.tmHeight
, data
[1].tm
.tmHeight
);
6775 ok(data
[0].tm
.tmAscent
== data
[1].tm
.tmAscent
,
6776 "expected %d, got %d\n", data
[0].tm
.tmAscent
, data
[1].tm
.tmAscent
);
6777 ok(data
[0].tm
.tmDescent
== data
[1].tm
.tmDescent
,
6778 "expected %d, got %d\n", data
[0].tm
.tmDescent
, data
[1].tm
.tmDescent
);
6779 ok(data
[0].tm
.tmAveCharWidth
+ 1 == data
[1].tm
.tmAveCharWidth
,
6780 "expected %d, got %d\n", data
[0].tm
.tmAveCharWidth
+ 1, data
[1].tm
.tmAveCharWidth
);
6781 ok(data
[0].tm
.tmMaxCharWidth
+ 1 == data
[1].tm
.tmMaxCharWidth
,
6782 "expected %d, got %d\n", data
[0].tm
.tmMaxCharWidth
+ 1, data
[1].tm
.tmMaxCharWidth
);
6783 ok(data
[0].tm
.tmOverhang
== data
[1].tm
.tmOverhang
,
6784 "expected %d, got %d\n", data
[0].tm
.tmOverhang
, data
[1].tm
.tmOverhang
);
6785 ok(data
[0].w
+ 1 == data
[1].w
,
6786 "expected %d, got %d\n", data
[0].w
+ 1, data
[1].w
);
6788 ok(data
[0].gm
.gmCellIncX
+ 1 == data
[1].gm
.gmCellIncX
,
6789 "expected %d, got %d\n", data
[0].gm
.gmCellIncX
+ 1, data
[1].gm
.gmCellIncX
);
6790 ok(data
[0].gm
.gmCellIncY
== data
[1].gm
.gmCellIncY
,
6791 "expected %d, got %d\n", data
[0].gm
.gmCellIncY
, data
[1].gm
.gmCellIncY
);
6793 /* Test bitmap font */
6794 memset(&data
, 0xaa, sizeof(data
));
6795 memset(&lf
, 0, sizeof(lf
));
6796 strcpy(lf
.lfFaceName
, "Courier");
6797 lf
.lfCharSet
= ANSI_CHARSET
;
6801 for (i
= 0; i
< 4; i
++)
6803 HFONT hfont
, hfont_old
;
6805 lf
.lfWeight
= (i
% 2) ? FW_BOLD
: FW_NORMAL
;
6806 lf
.lfHeight
= (i
> 1) ? data
[0].tm
.tmHeight
* x2_mat
.eM11
.value
: 0;
6807 hfont
= CreateFontIndirectA(&lf
);
6808 hfont_old
= SelectObject(hdc
, hfont
);
6810 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6811 ok(ret
, "got %d\n", ret
);
6812 ret
= GetCharWidth32A(hdc
, 0x76, 0x76, &data
[i
].w
);
6813 ok(ret
, "got %d\n", ret
);
6815 SelectObject(hdc
, hfont_old
);
6816 DeleteObject(hfont
);
6818 ReleaseDC(NULL
, hdc
);
6820 /* compare results (bitmap) */
6821 for (i
= 0; i
< 4; i
+=2)
6823 int diff
= (i
> 1) ? x2_mat
.eM11
.value
: 1;
6824 if (data
[i
].tm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
6826 skip("TrueType font is selected (expected a bitmap one)\n");
6829 ok(data
[i
].tm
.tmHeight
== data
[i
+1].tm
.tmHeight
,
6830 "expected %d, got %d\n", data
[i
].tm
.tmHeight
, data
[i
+1].tm
.tmHeight
);
6831 ok(data
[i
].tm
.tmAscent
== data
[i
+1].tm
.tmAscent
,
6832 "expected %d, got %d\n", data
[i
].tm
.tmAscent
, data
[i
+1].tm
.tmAscent
);
6833 ok(data
[i
].tm
.tmDescent
== data
[i
+1].tm
.tmDescent
,
6834 "expected %d, got %d\n", data
[i
].tm
.tmDescent
, data
[i
+1].tm
.tmDescent
);
6835 ok(data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
== diff
,
6836 "expected %d, got %d\n", diff
, data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
);
6837 ok(data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
== diff
,
6838 "expected %d, got %d\n", diff
, data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
);
6839 ok(data
[i
].tm
.tmOverhang
== 0,
6840 "expected 0, got %d\n", data
[i
].tm
.tmOverhang
);
6841 ok(data
[i
+1].tm
.tmOverhang
== 1,
6842 "expected 1, got %d\n", data
[i
+1].tm
.tmOverhang
);
6843 ok(data
[i
].w
+ 1 == data
[i
+1].w
,
6844 "expected %d, got %d\n", data
[i
].w
+ 1, data
[i
+1].w
);
6848 static void test_bitmap_font_glyph_index(void)
6850 const WCHAR text
[] = L
"#!/bin/sh";
6854 } bitmap_font_list
[] = {
6855 { "Courier", ANSI_CHARSET
},
6856 { "Small Fonts", ANSI_CHARSET
},
6857 { "Fixedsys", DEFAULT_CHARSET
},
6858 { "System", DEFAULT_CHARSET
}
6863 CHAR facename
[LF_FACESIZE
];
6874 if (!pGetGlyphIndicesW
) {
6875 win_skip("GetGlyphIndices is unavailable\n");
6879 hdc
= CreateCompatibleDC(0);
6880 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6882 memset(&bmi
, 0, sizeof(bmi
));
6883 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
6884 bmi
.bmiHeader
.biBitCount
= 32;
6885 bmi
.bmiHeader
.biPlanes
= 1;
6886 bmi
.bmiHeader
.biWidth
= 128;
6887 bmi
.bmiHeader
.biHeight
= 32;
6888 bmi
.bmiHeader
.biCompression
= BI_RGB
;
6890 for (i
= 0; i
< ARRAY_SIZE(bitmap_font_list
); i
++) {
6891 memset(&lf
, 0, sizeof(lf
));
6892 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
6893 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
6894 hFont
= CreateFontIndirectA(&lf
);
6895 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
6896 hFont
= SelectObject(hdc
, hFont
);
6897 ret
= GetTextMetricsA(hdc
, &tm
);
6898 ok(ret
, "GetTextMetric failed\n");
6899 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
6900 ok(ret
, "GetTextFace failed\n");
6901 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
6902 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
6905 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
6906 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
6910 for (j
= 0; j
< 2; j
++) {
6912 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
6913 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
6914 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6917 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
6921 int len
= lstrlenW(text
);
6922 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
6923 ret
= pGetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
6924 ok(ret
, "GetGlyphIndices failed\n");
6925 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
6926 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
6927 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
6928 HeapFree(GetProcessHeap(), 0, indices
);
6932 ok(ret
, "ExtTextOutW failed\n");
6933 SelectObject(hdc
, hBmpPrev
);
6936 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
6937 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6938 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6940 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
6942 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6945 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
6946 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
6950 for (j
= 0; j
< 2; j
++) {
6953 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6956 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6959 ret
= GetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6960 ok(ret
, "GetGlyphIndices failed\n");
6961 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6962 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6965 ok(ret
, "ExtTextOutA failed\n");
6966 SelectObject(hdc
, hBmpPrev
);
6969 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6970 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6972 for (j
= 0; j
< 2; j
++)
6973 DeleteObject(hBmp
[j
]);
6974 hFont
= SelectObject(hdc
, hFont
);
6975 DeleteObject(hFont
);
6981 static void test_GetCharWidthI(void)
6983 static const char *teststr
= "wine ";
6984 HFONT hfont
, prev_hfont
;
6994 memset(&lf
, 0, sizeof(lf
));
6995 strcpy(lf
.lfFaceName
, "Tahoma");
7000 hfont
= CreateFontIndirectA(&lf
);
7001 prev_hfont
= SelectObject(hdc
, hfont
);
7003 len
= strlen(teststr
);
7004 nb
= GetGlyphIndicesA(hdc
, teststr
, len
, glyphs
, 0);
7005 ok(nb
== len
, "\n");
7007 memset(abc
, 0xcc, sizeof(abc
));
7008 ret
= GetCharABCWidthsI(hdc
, 0, len
, glyphs
, abc
);
7009 ok(ret
, "GetCharABCWidthsI failed\n");
7011 memset(widths
, 0xcc, sizeof(widths
));
7012 ret
= GetCharWidthI(hdc
, 0, len
, glyphs
, widths
);
7013 ok(ret
, "GetCharWidthI failed\n");
7015 for (i
= 0; i
< len
; i
++)
7016 ok(widths
[i
] == abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
, "%u, glyph %u, got width %d\n",
7017 i
, glyphs
[i
], widths
[i
]);
7019 DeleteObject(SelectObject(hdc
, prev_hfont
));
7023 static INT CALLBACK
long_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lparam
)
7025 BOOL
*found_font
= (BOOL
*)lparam
;
7030 static void test_long_names(void)
7032 char ttf_name
[MAX_PATH
];
7033 LOGFONTA font
= {0};
7039 if (!write_ttf_file("wine_longname.ttf", ttf_name
))
7041 skip("Failed to create ttf file for testing\n");
7047 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7048 ok(ret
, "AddFontResourceEx() failed\n");
7050 strcpy(font
.lfFaceName
, "wine_3_this_is_a_very_long_name");
7052 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7053 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7055 strcpy(font
.lfFaceName
, "wine_2_this_is_a_very_long_name");
7057 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7058 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7060 strcpy(font
.lfFaceName
, "wine_1_this_is_a_very_long_name");
7062 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7063 ok(found_font
== FALSE
, "EnumFontFamiliesExA must not find font.\n");
7065 handle_font
= CreateFontIndirectA(&font
);
7066 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7067 DeleteObject(handle_font
);
7069 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7070 ok(ret
, "RemoveFontResourceEx() failed\n");
7072 DeleteFileA(ttf_name
);
7073 ReleaseDC(NULL
, dc
);
7076 static void test_ttf_names(void)
7078 struct enum_fullname_data efnd
;
7079 char ttf_name
[MAX_PATH
], ttf_name_bold
[MAX_PATH
];
7080 LOGFONTA font
= {0};
7085 if (!write_ttf_file("wine_ttfnames.ttf", ttf_name
))
7087 skip("Failed to create ttf file for testing\n");
7091 if (!write_ttf_file("wine_ttfnames_bold.ttf", ttf_name_bold
))
7093 skip("Failed to create ttf file for testing\n");
7094 DeleteFileA(ttf_name
);
7098 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7099 ok(ret
, "AddFontResourceEx() failed\n");
7101 ret
= AddFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7102 ok(ret
, "AddFontResourceEx() failed\n");
7106 strcpy(font
.lfFaceName
, "Wine_TTF_Names_Long_Family1_Con");
7107 memset(&efnd
, 0, sizeof(efnd
));
7108 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7109 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7111 /* Windows doesn't match with Typographic/Preferred Family tags */
7112 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1");
7113 memset(&efnd
, 0, sizeof(efnd
));
7114 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7115 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7117 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Ext");
7118 memset(&efnd
, 0, sizeof(efnd
));
7119 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7120 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7122 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Con");
7123 memset(&efnd
, 0, sizeof(efnd
));
7124 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7125 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7127 handle_font
= CreateFontIndirectA(&font
);
7128 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7129 DeleteObject(handle_font
);
7131 ret
= RemoveFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7132 ok(ret
, "RemoveFontResourceEx() failed\n");
7134 DeleteFileA(ttf_name_bold
);
7136 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7137 ok(ret
, "RemoveFontResourceEx() failed\n");
7139 DeleteFileA(ttf_name
);
7140 ReleaseDC(NULL
, dc
);
7143 static void test_lang_names(void)
7145 static const WCHAR name_cond_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja)";
7146 static const WCHAR name_cond_ja_reg_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg";
7147 static const WCHAR name_cond_ja_reg_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg (ja)";
7148 static const WCHAR name_wws_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d WWS (ja)";
7150 struct enum_fullname_data efnd
;
7151 struct enum_fullname_data_w efnd_w
;
7152 char ttf_name
[MAX_PATH
], ttf_name2
[MAX_PATH
], ttf_name3
[MAX_PATH
];
7153 LOGFONTA font
= {0};
7154 LOGFONTW font_w
= {0};
7157 const WCHAR
*primary_family
, *primary_fullname
;
7159 if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
&& PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE
)
7161 skip( "Primary language is neither English nor Japanese, skipping test\n" );
7165 if (!write_ttf_file( "wine_langnames.ttf", ttf_name
))
7167 skip( "Failed to create ttf file for testing\n" );
7171 if (!write_ttf_file( "wine_langnames2.ttf", ttf_name2
))
7173 skip( "Failed to create ttf file for testing\n" );
7174 DeleteFileA( ttf_name
);
7178 if (!write_ttf_file( "wine_langnames3.ttf", ttf_name3
))
7180 skip( "Failed to create ttf file for testing\n" );
7181 DeleteFileA( ttf_name2
);
7182 DeleteFileA( ttf_name
);
7186 ret
= AddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7187 ok( ret
, "AddFontResourceEx() failed\n" );
7191 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7193 primary_family
= L
"Wine Lang Cond (en)";
7194 primary_fullname
= L
"Wine Lang Cond Reg (en)";
7198 primary_family
= name_cond_ja_w
;
7199 primary_fullname
= name_cond_ja_reg_w
;
7202 for (i
= 0; i
< 3; ++i
)
7204 /* check that lookup by preferred or WWS family / full names or postscript FontName doesn't work */
7206 strcpy( font
.lfFaceName
, "Wine Lang (en)" );
7207 memset( &efnd
, 0, sizeof(efnd
) );
7208 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7209 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7211 strcpy( font
.lfFaceName
, "Wine Lang Condensed Bold (ko)" );
7212 memset( &efnd
, 0, sizeof(efnd
) );
7213 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7214 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7216 wcscpy( font_w
.lfFaceName
, name_wws_ja_w
);
7217 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7218 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7219 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7221 strcpy( font
.lfFaceName
, "Reg WWS (zh-tw)" );
7222 memset( &efnd
, 0, sizeof(efnd
) );
7223 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7224 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7226 strcpy( font
.lfFaceName
, "Wine Lang (en) Reg WWS (en)" );
7227 memset( &efnd
, 0, sizeof(efnd
) );
7228 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7229 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7231 strcpy( font
.lfFaceName
, "WineLangNamesRegular" );
7232 memset( &efnd
, 0, sizeof(efnd
) );
7233 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7234 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7236 /* then, the primary ttf family name always works */
7238 wcscpy( font_w
.lfFaceName
, primary_family
);
7239 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7240 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7241 ok( efnd_w
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7243 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7245 wcscpy( font_w
.lfFaceName
, name_cond_ja_w
);
7246 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7247 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7248 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7251 /* if there is no primary ttf family name, the english ttf name, or postscript FamilyName are used instead */
7253 strcpy( font
.lfFaceName
, "Wine_Lang_Names" );
7254 memset( &efnd
, 0, sizeof(efnd
) );
7255 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7257 ok( efnd
.total
== 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7259 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7261 /* same goes for ttf full names */
7263 wcscpy( font_w
.lfFaceName
, primary_fullname
);
7264 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7265 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7266 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7268 if (efnd_w
.total
>= 1)
7270 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
, primary_family
),
7271 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
) );
7272 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfFullName
, primary_fullname
),
7273 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfFullName
) );
7274 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
? L
"Reg (en)" : 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_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 wcscpy( font_w
.lfFaceName
, L
"Wine_Lang_Names_Regular" );
7287 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7288 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7289 ok( efnd_w
.total
== i
, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7291 while (efnd_w
.total
--)
7293 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
, efnd_w
.total
== 1 ? L
"Wine_Lang_Names" : primary_family
),
7294 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
) );
7295 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
, L
"Wine_Lang_Names_Regular" ),
7296 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
) );
7297 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7298 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
, efnd_w
.total
== 1 ? L
"Regular" : L
"Reg (en)" ),
7299 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
) );
7301 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, L
"Reg (ja)" ),
7302 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfStyle
) );
7305 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7307 wcscpy( font_w
.lfFaceName
, name_cond_ja_reg_ja_w
);
7308 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7309 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7310 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7313 /* another language can also be used for lookup, if the primary langid isn't english, then
7314 english seems to have priority, otherwise or if english is already the primary langid,
7315 the family name with the smallest langid is used as secondary lookup language. */
7317 strcpy( font
.lfFaceName
, "Wine Lang Cond (zh-tw)" );
7318 memset( &efnd
, 0, sizeof(efnd
) );
7319 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7320 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7321 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7322 else /* (zh-tw) doesn't match here probably because there's an (en) name too */
7323 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7325 strcpy( font
.lfFaceName
, "Wine Lang Cond (en)" );
7326 memset( &efnd
, 0, sizeof(efnd
) );
7327 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7328 /* either because it's the primary language, or because it's a secondary */
7329 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7331 wcscpy( font_w
.lfFaceName
, L
"Wine Police d'\xe9" "criture (fr)" );
7332 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7333 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7334 /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */
7335 if (i
== 2) ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7336 else ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7338 /* case matching should not depend on the current locale */
7341 wcscpy( font_w
.lfFaceName
, L
"Wine POLICE D'\xc9" "CRITURE (fr)" );
7342 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7343 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7344 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7347 strcpy( font
.lfFaceName
, "Wine Lang Cond (ko)" );
7348 memset( &efnd
, 0, sizeof(efnd
) );
7349 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7350 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7352 /* that doesn't apply to full names */
7354 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (zh-tw)" );
7355 memset( &efnd
, 0, sizeof(efnd
) );
7356 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7357 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7359 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (fr)" );
7360 memset( &efnd
, 0, sizeof(efnd
) );
7361 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7362 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7366 ret
= AddFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7367 ok( ret
, "AddFontResourceEx() failed\n" );
7371 ret
= AddFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7372 ok( ret
, "AddFontResourceEx() failed\n" );
7376 ret
= RemoveFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7377 ok( ret
, "RemoveFontResourceEx() failed\n" );
7379 DeleteFileA( ttf_name3
);
7381 ret
= RemoveFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7382 ok( ret
, "RemoveFontResourceEx() failed\n" );
7384 DeleteFileA( ttf_name2
);
7386 ret
= RemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7387 ok( ret
, "RemoveFontResourceEx() failed\n" );
7389 DeleteFileA( ttf_name
);
7390 ReleaseDC( NULL
, dc
);
7395 USHORT majorVersion
;
7396 USHORT minorVersion
;
7400 USHORT advanceWidthMax
;
7401 SHORT minLeftSideBearing
;
7402 SHORT minRightSideBearing
;
7404 SHORT caretSlopeRise
;
7405 SHORT caretSlopeRun
;
7408 SHORT metricDataFormat
;
7409 SHORT numberOfHMetrics
;
7412 static void test_GetCharWidthInfo(void)
7415 HFONT hfont
, hfont_prev
;
7419 OUTLINETEXTMETRICA otm
;
7420 TT_Hori_Header hhea
;
7421 struct char_width_info
7425 SHORT minLeftSideBearing
, minRightSideBearing
;
7427 const char* face_list
[] = { "Symbol", "Ume Gothic", "MS Gothic" };
7429 if (!pGetCharWidthInfo
)
7431 win_skip("GetCharWidthInfo is unavailable\n");
7437 /* test default (System) font */
7438 memset(&info
, 0xaa, sizeof(info
));
7439 r
= pGetCharWidthInfo(hdc
, &info
);
7440 if (r
) /* win10 1803 succeeds */
7442 ok(info
.lsb
== 0, "expected 0, got %d\n", info
.lsb
);
7443 ok(info
.rsb
== 0, "expected 0, got %d\n", info
.rsb
);
7444 ok(info
.unk
== 0, "expected 0, got %d\n", info
.unk
);
7447 memset(&lf
, 0, sizeof(lf
));
7448 lf
.lfWeight
= FW_NORMAL
;
7449 lf
.lfCharSet
= ANSI_CHARSET
;
7450 strcpy(lf
.lfFaceName
, "Tahoma");
7451 hfont
= CreateFontIndirectA(&lf
);
7452 hfont_prev
= SelectObject(hdc
, hfont
);
7453 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7455 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
7456 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
7457 DeleteObject(SelectObject(hdc
, hfont_prev
));
7459 /* test Tahoma at the em square size */
7460 lf
.lfHeight
= -(int)otm
.otmEMSquare
;
7461 hfont
= CreateFontIndirectA(&lf
);
7462 hfont_prev
= SelectObject(hdc
, hfont
);
7463 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7465 ret
= GetFontData(hdc
, MS_MAKE_TAG('h','h','e','a'), 0, &hhea
, sizeof(hhea
));
7466 ok(ret
== sizeof(hhea
), "got %u\n", ret
);
7467 minLeftSideBearing
= GET_BE_WORD(hhea
.minLeftSideBearing
);
7468 minRightSideBearing
= GET_BE_WORD(hhea
.minRightSideBearing
);
7470 memset(&info
, 0xaa, sizeof(info
));
7471 r
= pGetCharWidthInfo(hdc
, &info
);
7472 ok(r
, "GetCharWidthInfo failed\n");
7473 ok(info
.lsb
== minLeftSideBearing
, "expected %d, got %d\n", minLeftSideBearing
, info
.lsb
);
7474 ok(info
.rsb
== minRightSideBearing
, "expected %d, got %d\n", minRightSideBearing
, info
.rsb
);
7476 DeleteObject(SelectObject(hdc
, hfont_prev
));
7478 /* these values are scaled, try with smaller size */
7480 hfont
= CreateFontIndirectA(&lf
);
7481 hfont_prev
= SelectObject(hdc
, hfont
);
7482 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7484 memset(&info2
, 0xaa, sizeof(info2
));
7485 r
= pGetCharWidthInfo(hdc
, &info2
);
7486 ok(r
, "pGetCharWidthInfo failed\n");
7487 ok(info2
.lsb
== info
.lsb
/3, "expected %d, got %d\n", info
.lsb
/3, info2
.lsb
);
7488 ok(info2
.rsb
== info
.rsb
/3, "expected %d, got %d\n", info
.rsb
/3, info2
.rsb
);
7490 DeleteObject(SelectObject(hdc
, hfont_prev
));
7491 ReleaseDC(NULL
, hdc
);
7493 /* test with another mapping mode */
7495 SetMapMode(hdc
, MM_ISOTROPIC
);
7496 SetWindowExtEx(hdc
, 2, 2, NULL
);
7497 SetViewportExtEx(hdc
, 1, 1, NULL
);
7499 memset(pt
, 0, sizeof(pt
));
7500 pt
[0].y
= otm
.otmEMSquare
;
7503 memset(&lf
, 0, sizeof(lf
));
7504 lf
.lfWeight
= FW_NORMAL
;
7505 lf
.lfCharSet
= ANSI_CHARSET
;
7506 lf
.lfHeight
= -abs(pt
[0].y
);
7507 strcpy(lf
.lfFaceName
, "Tahoma");
7508 hfont
= CreateFontIndirectA(&lf
);
7509 hfont_prev
= SelectObject(hdc
, hfont
);
7510 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7512 memset(&info2
, 0xaa, sizeof(info2
));
7513 r
= pGetCharWidthInfo(hdc
, &info2
);
7514 ok(r
, "GetCharWidthInfo failed\n");
7515 pt
[0].x
= info
.lsb
; pt
[0].y
= 0;
7516 pt
[1].x
= info
.rsb
; pt
[1].y
= 0;
7518 ok(pt
[0].x
== info2
.lsb
, "expected %d, got %d\n", pt
[0].x
, info2
.lsb
);
7519 ok(pt
[1].x
== info2
.rsb
, "expected %d, got %d\n", pt
[1].x
, info2
.rsb
);
7521 DeleteObject(SelectObject(hdc
, hfont_prev
));
7522 ReleaseDC(NULL
, hdc
);
7524 /* test with synthetic fonts */
7526 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++)
7528 const char* face
= face_list
[i
];
7529 if (!is_truetype_font_installed(face
))
7531 skip("%s is not installed\n", face
);
7534 memset(&lf
, 0, sizeof(lf
));
7535 lf
.lfWeight
= FW_NORMAL
;
7536 lf
.lfItalic
= FALSE
;
7537 lf
.lfCharSet
= DEFAULT_CHARSET
;
7539 strcpy(lf
.lfFaceName
, face
);
7540 hfont
= CreateFontIndirectA(&lf
);
7541 hfont_prev
= SelectObject(hdc
, hfont
);
7543 memset(&info
, 0xaa, sizeof(info
));
7544 r
= pGetCharWidthInfo(hdc
, &info
);
7545 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7547 /* test with synthetic bold */
7548 lf
.lfWeight
= FW_BOLD
;
7549 lf
.lfItalic
= FALSE
;
7550 hfont
= CreateFontIndirectA(&lf
);
7551 DeleteObject(SelectObject(hdc
, hfont
));
7553 memset(&info2
, 0xaa, sizeof(info2
));
7554 r
= pGetCharWidthInfo(hdc
, &info2
);
7555 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7556 ok(info
.lsb
== info2
.lsb
, "%s: expected %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7557 ok(info
.rsb
== info2
.rsb
, "%s: expected %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7559 /* test with synthetic italic */
7560 lf
.lfWeight
= FW_NORMAL
;
7562 hfont
= CreateFontIndirectA(&lf
);
7563 DeleteObject(SelectObject(hdc
, hfont
));
7565 memset(&info2
, 0xaa, sizeof(info2
));
7566 r
= pGetCharWidthInfo(hdc
, &info2
);
7567 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7568 todo_wine
ok(info
.lsb
> info2
.lsb
, "%s: expected less than %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7569 todo_wine
ok(info
.rsb
> info2
.rsb
, "%s: expected less than %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7570 DeleteObject(SelectObject(hdc
, hfont_prev
));
7573 ReleaseDC(NULL
, hdc
);
7576 static int CALLBACK
get_char_width_proc(const LOGFONTA
*lf
,
7577 const TEXTMETRICA
*tm
, DWORD type
, LPARAM ctx
)
7579 HFONT font
= CreateFontIndirectA(lf
);
7580 HDC dc
= GetDC(NULL
);
7588 SelectObject(dc
, font
);
7590 ret
= GetCharWidthFloatA(dc
, c
, c
, &f
);
7591 ok(ret
, "%s: GetCharWidthFloat() failed\n", lf
->lfFaceName
);
7592 ret
= GetCharWidth32A(dc
, c
, c
, &i32
);
7593 ok(ret
, "%s: GetCharWidth32A() failed\n", lf
->lfFaceName
);
7594 ret
= GetCharWidthA(dc
, c
, c
, &i
);
7595 ok(ret
, "%s: GetCharWidthA() failed\n", lf
->lfFaceName
);
7596 ok(i
== i32
, "%s: mismatched widths %d/%d\n", lf
->lfFaceName
, i
, i32
);
7597 ok((float)i
/ 16.0f
== f
, "%s: mismatched widths %d/%.8e\n", lf
->lfFaceName
, i
, f
);
7599 ret
= GetCharABCWidthsFloatA(dc
, c
, c
, &abcf
);
7600 ok(ret
, "%s: GetCharABCWidths() failed\n", lf
->lfFaceName
);
7601 if (GetCharABCWidthsA(dc
, c
, c
, &abc
))
7602 ok((float)abc
.abcB
== abcf
.abcfB
, "%s: mismatched widths %d/%.8e\n",
7603 lf
->lfFaceName
, abc
.abcB
, abcf
.abcfB
);
7605 ReleaseDC(NULL
, dc
);
7610 static void test_char_width(void)
7612 HDC dc
= GetDC(NULL
);
7615 lf
.lfCharSet
= DEFAULT_CHARSET
;
7616 EnumFontFamiliesExA(dc
, &lf
, get_char_width_proc
, 0, 0);
7618 ReleaseDC(NULL
, dc
);
7621 static void test_GetCharacterPlacement_kerning(void)
7624 HFONT hfont
, hfont_old
;
7627 DWORD count
, ret
, i
, size
, width
, width_kern
, idx
;
7629 GCP_RESULTSW result
;
7630 int kern
[30], pos
[30], pos_kern
[30], dx
[30], dx_kern
[30], kern_amount
;
7632 if (!is_font_installed("Arial"))
7634 skip("Arial is not installed, skipping the test\n");
7640 memset(&lf
, 0, sizeof(lf
));
7641 strcpy(lf
.lfFaceName
, "Arial");
7643 hfont
= CreateFontIndirectA(&lf
);
7644 ok(hfont
!= NULL
, "CreateFontIndirect failed\n");
7646 hfont_old
= SelectObject(hdc
, hfont
);
7648 count
= GetKerningPairsW(hdc
, 0, NULL
);
7649 kp
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*kp
));
7651 ret
= GetKerningPairsW(hdc
, count
, kp
);
7652 ok(ret
== count
, "got %u, expected %u\n", ret
, count
);
7654 size
= kern_amount
= idx
= 0;
7655 for (i
= 0; i
< count
; i
++)
7657 if (kp
[i
].wFirst
>= 'A' && kp
[i
].wFirst
<= 'z' &&
7658 kp
[i
].wSecond
>= 'A' && kp
[i
].wSecond
<= 'z')
7660 str
[size
++] = kp
[i
].wFirst
;
7661 str
[size
++] = kp
[i
].wSecond
;
7663 kern
[idx
] = kp
[i
].iKernAmount
;
7665 kern_amount
+= kp
[i
].iKernAmount
;
7666 if (size
>= ARRAY_SIZE(str
)) break;
7670 HeapFree(GetProcessHeap(), 0, kp
);
7674 memset(&result
, 0, sizeof(result
));
7675 result
.lStructSize
= sizeof(result
);
7676 result
.lpCaretPos
= pos
;
7678 result
.nGlyphs
= count
;
7679 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, 0);
7680 ok(ret
, "GetCharacterPlacement failed\n");
7681 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7682 width
= LOWORD(ret
);
7684 memset(&result
, 0, sizeof(result
));
7685 result
.lStructSize
= sizeof(result
);
7686 result
.lpCaretPos
= pos_kern
;
7687 result
.lpDx
= dx_kern
;
7688 result
.nGlyphs
= count
;
7689 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, GCP_USEKERNING
);
7690 ok(ret
, "GetCharacterPlacement failed\n");
7691 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7692 width_kern
= LOWORD(ret
);
7694 if (width
== width_kern
)
7696 win_skip("GCP_USEKERNING is broken on this platform\n");
7700 ok(width
+ kern_amount
== width_kern
, "%d + %d != %d\n", width
, kern_amount
, width_kern
);
7702 kern_amount
= idx
= 0;
7703 for (i
= 0; i
< count
; i
+= 3, idx
++)
7705 ok(pos
[i
] + kern_amount
== pos_kern
[i
], "%d: %d + %d != %d\n", i
, pos
[i
], kern_amount
, pos_kern
[i
]);
7706 kern_amount
+= kern
[idx
];
7707 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]);
7708 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]);
7710 ok(dx
[i
] + kern
[idx
] == dx_kern
[i
], "%d: %d + %d != %d\n", i
, dx
[i
], kern
[idx
], dx_kern
[i
]);
7711 ok(dx
[i
+1] == dx_kern
[i
+1], "%d: %d != %d\n", i
, dx
[i
+1], dx_kern
[i
+1]);
7712 ok(dx
[i
+2] == dx_kern
[i
+2], "%d: %d != %d\n", i
, dx
[i
+2], dx_kern
[i
+2]);
7716 SelectObject(hdc
, hfont_old
);
7717 DeleteObject(hfont
);
7723 static const char *test_names
[] =
7725 "AddFontMemResource",
7727 char path_name
[MAX_PATH
];
7728 STARTUPINFOA startup
;
7734 argc
= winetest_get_mainargs(&argv
);
7737 if (!strcmp(argv
[2], "AddFontMemResource"))
7738 test_AddFontMemResource();
7745 test_outline_font();
7746 test_bitmap_font_metrics();
7747 test_GdiGetCharDimensions();
7748 test_GetCharABCWidths();
7749 test_text_extents();
7750 test_GetGlyphIndices();
7751 test_GetKerningPairs();
7752 test_GetOutlineTextMetrics();
7753 test_SetTextJustification();
7754 test_font_charset();
7755 test_GdiGetCodePage();
7756 test_GetFontUnicodeRanges();
7757 test_nonexistent_font();
7759 test_height_selection();
7761 test_EnumFonts_subst();
7763 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
7764 * I'd like to avoid them in this test.
7766 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
7767 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
7768 if (is_truetype_font_installed("Arial Black") &&
7769 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
7771 test_EnumFontFamilies("", ANSI_CHARSET
);
7772 test_EnumFontFamilies("", SYMBOL_CHARSET
);
7773 test_EnumFontFamilies("", DEFAULT_CHARSET
);
7776 skip("Arial Black or Symbol/Wingdings is not installed\n");
7777 test_EnumFontFamiliesEx_default_charset();
7778 test_GetTextMetrics();
7779 test_RealizationInfo();
7781 test_GetGlyphOutline();
7782 test_GetTextMetrics2("Tahoma", -11);
7783 test_GetTextMetrics2("Tahoma", -55);
7784 test_GetTextMetrics2("Tahoma", -110);
7785 test_GetTextMetrics2("Arial", -11);
7786 test_GetTextMetrics2("Arial", -55);
7787 test_GetTextMetrics2("Arial", -110);
7788 test_GetCharacterPlacement();
7789 test_GetCharacterPlacement_kerning();
7790 test_GetCharWidthInfo();
7791 test_CreateFontIndirect();
7792 test_CreateFontIndirectEx();
7796 test_east_asian_font_selection();
7798 test_vertical_order();
7799 test_GetCharWidth32();
7800 test_fake_bold_font();
7801 test_bitmap_font_glyph_index();
7802 test_GetCharWidthI();
7808 /* These tests should be last test until RemoveFontResource
7809 * is properly implemented.
7811 test_vertical_font();
7812 test_CreateScalableFontResource();
7814 winetest_get_mainargs( &argv
);
7815 for (i
= 0; i
< ARRAY_SIZE(test_names
); ++i
)
7817 PROCESS_INFORMATION info
;
7819 memset(&startup
, 0, sizeof(startup
));
7820 startup
.cb
= sizeof(startup
);
7821 sprintf(path_name
, "%s font %s", argv
[0], test_names
[i
]);
7822 ok(CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
),
7823 "CreateProcess failed.\n");
7824 wait_child_process(info
.hProcess
);
7825 CloseHandle(info
.hProcess
);
7826 CloseHandle(info
.hThread
);