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
*pGetCharWidthInfo
)(HDC hdc
, void *);
46 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
47 static BOOL (WINAPI
*pGetFontRealizationInfo
)(HDC hdc
, DWORD
*);
48 static BOOL (WINAPI
*pGetFontFileInfo
)(DWORD
, DWORD
, void *, SIZE_T
, SIZE_T
*);
49 static BOOL (WINAPI
*pGetFontFileData
)(DWORD
, DWORD
, UINT64
, void *, DWORD
);
51 static HMODULE hgdi32
= 0;
52 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
53 static WORD system_lang_id
;
55 #ifdef WORDS_BIGENDIAN
56 #define GET_BE_WORD(x) (x)
57 #define GET_BE_DWORD(x) (x)
59 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
60 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
63 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
64 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
65 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
66 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
67 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
68 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
70 static void init(void)
72 hgdi32
= GetModuleHandleA("gdi32.dll");
74 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
75 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
76 pGetCharWidthInfo
= (void *)GetProcAddress(hgdi32
, "GetCharWidthInfo");
77 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
78 pGetFontRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GetFontRealizationInfo");
79 pGetFontFileInfo
= (void *)GetProcAddress(hgdi32
, "GetFontFileInfo");
80 pGetFontFileData
= (void *)GetProcAddress(hgdi32
, "GetFontFileData");
82 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
85 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
87 if (type
!= TRUETYPE_FONTTYPE
) return 1;
92 static BOOL
is_truetype_font_installed(const char *name
)
97 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
104 static INT CALLBACK
is_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
109 static BOOL
is_font_installed(const char *name
)
114 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
121 static void *get_res_data(const char *fontname
, DWORD
*rsrc_size
)
126 rsrc
= FindResourceA(GetModuleHandleA(NULL
), fontname
, (LPCSTR
)RT_RCDATA
);
127 if (!rsrc
) return NULL
;
129 rsrc_data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
130 if (!rsrc_data
) return NULL
;
132 *rsrc_size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
133 if (!*rsrc_size
) return NULL
;
138 static BOOL
write_tmp_file( const void *data
, DWORD
*size
, char *tmp_name
)
140 char tmp_path
[MAX_PATH
];
144 GetTempPathA(MAX_PATH
, tmp_path
);
145 GetTempFileNameA(tmp_path
, "ttf", 0, tmp_name
);
147 hfile
= CreateFileA(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
148 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
150 ret
= WriteFile(hfile
, data
, *size
, size
, NULL
);
156 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
161 rsrc_data
= get_res_data( fontname
, &rsrc_size
);
162 if (!rsrc_data
) return FALSE
;
164 return write_tmp_file( rsrc_data
, &rsrc_size
, tmp_name
);
167 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
175 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
176 ok(ret
== sizeof(LOGFONTA
), "%s: GetObject returned %d\n", test
, ret
);
177 ok(lf
->lfHeight
== getobj_lf
.lfHeight
, "lfHeight: expect %08lx got %08lx\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
178 ok(lf
->lfWidth
== getobj_lf
.lfWidth
, "lfWidth: expect %08lx got %08lx\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
179 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
, "lfEscapement: expect %08lx got %08lx\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
180 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
, "lfOrientation: expect %08lx got %08lx\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
181 ok(lf
->lfWeight
== getobj_lf
.lfWeight
, "lfWeight: expect %08lx got %08lx\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
182 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
183 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
184 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
185 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
186 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
187 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
188 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
189 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
190 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
), "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
193 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
195 HFONT hfont
= CreateFontIndirectA(lf
);
196 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
198 check_font(test
, lf
, hfont
);
202 static void test_logfont(void)
207 memset(&lf
, 0, sizeof lf
);
209 lf
.lfCharSet
= ANSI_CHARSET
;
210 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
211 lf
.lfWeight
= FW_DONTCARE
;
214 lf
.lfQuality
= DEFAULT_QUALITY
;
216 lstrcpyA(lf
.lfFaceName
, "Arial");
217 hfont
= create_font("Arial", &lf
);
220 memset(&lf
, 'A', sizeof(lf
));
221 hfont
= CreateFontIndirectA(&lf
);
222 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
224 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
225 check_font("AAA...", &lf
, hfont
);
229 static INT CALLBACK
font_enum_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
231 if (type
& RASTER_FONTTYPE
)
233 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
235 return 0; /* stop enumeration */
238 return 1; /* continue enumeration */
241 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
243 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %ld != %ld\n", tm
->tmHeight
, otm
->tmHeight
);
244 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %ld != %ld\n", tm
->tmAscent
, otm
->tmAscent
);
245 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %ld != %ld\n", tm
->tmDescent
, otm
->tmDescent
);
246 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %ld != %ld\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
247 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %ld != %ld\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
248 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %ld != %ld\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
249 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %ld != %ld\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
250 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %ld != %ld\n", tm
->tmWeight
, otm
->tmWeight
);
251 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %ld != %ld\n", tm
->tmOverhang
, otm
->tmOverhang
);
252 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %ld != %ld\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
253 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %ld != %ld\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
254 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
255 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
256 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
257 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
258 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
259 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
260 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
261 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
262 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
265 static void test_font_metrics(const char *context
,
266 HDC hdc
, HFONT hfont
, LONG lfHeight
,
267 LONG lfWidth
, const char *test_str
,
268 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
269 const SIZE
*size_orig
, INT width_of_A_orig
,
270 INT scale_x
, INT scale_y
)
273 OUTLINETEXTMETRICA otm
;
276 INT width_of_A
, cx
, cy
;
282 if (context
) winetest_push_context("%s", context
);
283 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
285 GetObjectA(hfont
, sizeof(lf
), &lf
);
287 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
289 otm
.otmSize
= sizeof(otm
) / 2;
290 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
291 ok(ret
== sizeof(otm
)/2, "expected sizeof(otm)/2, got %u\n", ret
);
293 memset(&otm
, 0x1, sizeof(otm
));
294 otm
.otmSize
= sizeof(otm
);
295 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
296 ok(ret
== sizeof(otm
), "expected sizeof(otm), got %u\n", ret
);
298 memset(&tm
, 0x2, sizeof(tm
));
299 ret
= GetTextMetricsA(hdc
, &tm
);
300 ok(ret
, "GetTextMetricsA failed\n");
301 /* the structure size is aligned */
302 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
304 ok(0, "tm != otm\n");
305 compare_tm(&tm
, &otm
.otmTextMetrics
);
308 tm
= otm
.otmTextMetrics
;
309 if (0) /* these metrics are scaled too, but with rounding errors */
311 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %ld\n", otm
.otmAscent
, tm
.tmAscent
);
312 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %ld\n", otm
.otmDescent
, -tm
.tmDescent
);
314 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %ld\n", otm
.otmMacAscent
, tm
.tmAscent
);
315 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
316 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
317 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
318 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %ld\n", otm
.otmMacDescent
, -tm
.tmDescent
);
319 if (otm
.otmTextMetrics
.tmPitchAndFamily
& TMPF_TRUETYPE
)
320 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
324 ret
= GetTextMetricsA(hdc
, &tm
);
325 ok(ret
, "GetTextMetricsA failed\n");
328 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
329 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
330 ok(cx
== scale_x
&& cy
== scale_y
, "height %ld: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
331 lfHeight
, scale_x
, scale_y
, cx
, cy
);
332 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %ld != %ld\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
333 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %ld != %ld\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
334 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %ld != %ld\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
335 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %ld != %ld\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
336 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %ld != %ld\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
338 ok(lf
.lfHeight
== lfHeight
, "lfHeight %ld != %ld\n", lf
.lfHeight
, lfHeight
);
342 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %ld != tm %ld\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
345 ok(lf
.lfWidth
== lfWidth
, "lfWidth %ld != %ld\n", lf
.lfWidth
, lfWidth
);
347 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
349 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %ld != %ld\n", size
.cx
, size_orig
->cx
* scale_x
);
350 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %ld != %ld\n", size
.cy
, size_orig
->cy
* scale_y
);
352 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
354 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
);
355 if (context
) winetest_pop_context();
358 /* Test how GDI scales bitmap font metrics */
359 static void test_bitmap_font(void)
361 static const char test_str
[11] = "Test String";
364 HFONT hfont
, old_hfont
;
367 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
369 hdc
= CreateCompatibleDC(0);
371 /* "System" has only 1 pixel size defined, otherwise the test breaks */
372 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
376 skip("no bitmap fonts were found, skipping the test\n");
380 trace("found bitmap font %s, height %ld\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
382 height_orig
= bitmap_lf
.lfHeight
;
383 lfWidth
= bitmap_lf
.lfWidth
;
385 hfont
= create_font("bitmap", &bitmap_lf
);
386 old_hfont
= SelectObject(hdc
, hfont
);
387 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
388 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
389 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
390 SelectObject(hdc
, old_hfont
);
393 bitmap_lf
.lfHeight
= 0;
394 bitmap_lf
.lfWidth
= 4;
395 hfont
= create_font("bitmap", &bitmap_lf
);
396 old_hfont
= SelectObject(hdc
, hfont
);
397 test_font_metrics("bitmap", hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
398 SelectObject(hdc
, old_hfont
);
401 bitmap_lf
.lfHeight
= height_orig
;
402 bitmap_lf
.lfWidth
= lfWidth
;
404 /* test fractional scaling */
405 for (i
= 1; i
<= height_orig
* 6; i
++)
409 bitmap_lf
.lfHeight
= i
;
410 hfont
= create_font("fractional", &bitmap_lf
);
411 scale
= (i
+ height_orig
- 1) / height_orig
;
412 nearest_height
= scale
* height_orig
;
413 /* Only jump to the next height if the difference <= 25% original height */
414 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
415 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
416 so we'll not test this particular height. */
417 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
418 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
419 old_hfont
= SelectObject(hdc
, hfont
);
420 winetest_push_context("height %i", i
);
421 test_font_metrics(NULL
, hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
422 winetest_pop_context();
423 SelectObject(hdc
, old_hfont
);
427 /* test integer scaling 3x2 */
428 bitmap_lf
.lfHeight
= height_orig
* 2;
429 bitmap_lf
.lfWidth
*= 3;
430 hfont
= create_font("3x2", &bitmap_lf
);
431 old_hfont
= SelectObject(hdc
, hfont
);
432 test_font_metrics("bitmap 3x2", hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
433 SelectObject(hdc
, old_hfont
);
436 /* test integer scaling 3x3 */
437 bitmap_lf
.lfHeight
= height_orig
* 3;
438 bitmap_lf
.lfWidth
= 0;
439 hfont
= create_font("3x3", &bitmap_lf
);
440 old_hfont
= SelectObject(hdc
, hfont
);
441 test_font_metrics("bitmap 3x3", hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
442 SelectObject(hdc
, old_hfont
);
448 /* Test how GDI scales outline font metrics */
449 static void test_outline_font(void)
451 static const char test_str
[11] = "Test String";
454 HFONT hfont
, old_hfont
, old_hfont_2
;
455 OUTLINETEXTMETRICA otm
;
457 INT width_orig
, height_orig
, lfWidth
;
460 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
464 if (!is_truetype_font_installed("Arial"))
466 skip("Arial is not installed\n");
470 hdc
= CreateCompatibleDC(0);
472 memset(&lf
, 0, sizeof(lf
));
473 strcpy(lf
.lfFaceName
, "Arial");
475 hfont
= create_font("outline", &lf
);
476 old_hfont
= SelectObject(hdc
, hfont
);
477 otm
.otmSize
= sizeof(otm
);
478 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
479 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
480 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
482 test_font_metrics("outline", hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
483 SelectObject(hdc
, old_hfont
);
486 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
487 lf
.lfHeight
= otm
.otmEMSquare
;
488 lf
.lfHeight
= -lf
.lfHeight
;
489 hfont
= create_font("outline", &lf
);
490 old_hfont
= SelectObject(hdc
, hfont
);
491 otm
.otmSize
= sizeof(otm
);
492 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
493 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
494 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
495 SelectObject(hdc
, old_hfont
);
498 height_orig
= otm
.otmTextMetrics
.tmHeight
;
499 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
501 /* test integer scaling 3x2 */
502 lf
.lfHeight
= height_orig
* 2;
503 lf
.lfWidth
= lfWidth
* 3;
504 hfont
= create_font("3x2", &lf
);
505 old_hfont
= SelectObject(hdc
, hfont
);
506 test_font_metrics("outline 3x2", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
507 SelectObject(hdc
, old_hfont
);
510 /* test integer scaling 3x3 */
511 lf
.lfHeight
= height_orig
* 3;
512 lf
.lfWidth
= lfWidth
* 3;
513 hfont
= create_font("3x3", &lf
);
514 old_hfont
= SelectObject(hdc
, hfont
);
515 test_font_metrics("outline 3x3", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
516 SelectObject(hdc
, old_hfont
);
519 /* test integer scaling 1x1 */
520 lf
.lfHeight
= height_orig
* 1;
521 lf
.lfWidth
= lfWidth
* 1;
522 hfont
= create_font("1x1", &lf
);
523 old_hfont
= SelectObject(hdc
, hfont
);
524 test_font_metrics("outline 1x1", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
525 SelectObject(hdc
, old_hfont
);
528 /* test integer scaling 1x1 */
529 lf
.lfHeight
= height_orig
;
531 hfont
= create_font("1x1", &lf
);
532 old_hfont
= SelectObject(hdc
, hfont
);
533 test_font_metrics("outline 1x0", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
535 /* with an identity matrix */
536 memset(&gm
, 0, sizeof(gm
));
537 SetLastError(0xdeadbeef);
538 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
539 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
540 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
541 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
542 /* with a custom matrix */
543 memset(&gm
, 0, sizeof(gm
));
544 SetLastError(0xdeadbeef);
545 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
546 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
547 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
548 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
550 /* Test that changing the DC transformation affects only the font
551 * selected on this DC and doesn't affect the same font selected on
554 hdc_2
= CreateCompatibleDC(0);
555 old_hfont_2
= SelectObject(hdc_2
, hfont
);
556 test_font_metrics("dc2.base", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
558 SetMapMode(hdc
, MM_ANISOTROPIC
);
560 /* font metrics on another DC should be unchanged */
561 test_font_metrics("dc2.aniso", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
563 /* test restrictions of compatibility mode GM_COMPATIBLE */
564 /* part 1: rescaling only X should not change font scaling on screen.
565 So compressing the X axis by 2 is not done, and this
566 appears as X scaling of 2 that no one requested. */
567 SetWindowExtEx(hdc
, 100, 100, NULL
);
568 SetViewportExtEx(hdc
, 50, 100, NULL
);
569 test_font_metrics("xscaling", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
570 /* font metrics on another DC should be unchanged */
571 test_font_metrics("dc2.xscaling", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
573 /* part 2: rescaling only Y should change font scaling.
574 As also X is scaled by a factor of 2, but this is not
575 requested by the DC transformation, we get a scaling factor
576 of 2 in the X coordinate. */
577 SetViewportExtEx(hdc
, 100, 200, NULL
);
578 test_font_metrics("yscaling", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
579 /* font metrics on another DC should be unchanged */
580 test_font_metrics("dc2.yscaling", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
582 /* restore scaling */
583 SetMapMode(hdc
, MM_TEXT
);
585 /* font metrics on another DC should be unchanged */
586 test_font_metrics("dc2.text", hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
588 SelectObject(hdc_2
, old_hfont_2
);
591 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
593 SelectObject(hdc
, old_hfont
);
596 skip("GM_ADVANCED is not supported on this platform\n");
607 SetLastError(0xdeadbeef);
608 ret
= SetWorldTransform(hdc
, &xform
);
609 ok(ret
, "SetWorldTransform error %lu\n", GetLastError());
611 test_font_metrics("xform", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
613 /* with an identity matrix */
614 memset(&gm
, 0, sizeof(gm
));
615 SetLastError(0xdeadbeef);
616 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
617 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
618 pt
.x
= width_orig
; pt
.y
= 0;
620 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %ld\n", gm
.gmCellIncX
, pt
.x
);
621 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
622 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
623 /* with a custom matrix */
624 memset(&gm
, 0, sizeof(gm
));
625 SetLastError(0xdeadbeef);
626 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
627 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
628 pt
.x
= width_orig
; pt
.y
= 0;
630 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %ld\n", gm
.gmCellIncX
, pt
.x
/2);
631 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
632 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
634 SetLastError(0xdeadbeef);
635 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
636 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %lu\n", ret
, GetLastError());
638 test_font_metrics("lometric", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
640 /* with an identity matrix */
641 memset(&gm
, 0, sizeof(gm
));
642 SetLastError(0xdeadbeef);
643 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
644 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
645 pt
.x
= width_orig
; pt
.y
= 0;
647 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %ld\n", gm
.gmCellIncX
, pt
.x
);
648 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
649 /* with a custom matrix */
650 memset(&gm
, 0, sizeof(gm
));
651 SetLastError(0xdeadbeef);
652 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
653 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
654 pt
.x
= width_orig
; pt
.y
= 0;
656 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %ld\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
657 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
659 SetLastError(0xdeadbeef);
660 ret
= SetMapMode(hdc
, MM_TEXT
);
661 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %lu\n", ret
, GetLastError());
663 test_font_metrics("text", hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
665 /* with an identity matrix */
666 memset(&gm
, 0, sizeof(gm
));
667 SetLastError(0xdeadbeef);
668 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
669 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
670 pt
.x
= width_orig
; pt
.y
= 0;
672 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %ld\n", gm
.gmCellIncX
, pt
.x
);
673 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
674 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
675 /* with a custom matrix */
676 memset(&gm
, 0, sizeof(gm
));
677 SetLastError(0xdeadbeef);
678 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
679 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %ld\n", GetLastError());
680 pt
.x
= width_orig
; pt
.y
= 0;
682 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %ld\n", gm
.gmCellIncX
, pt
.x
/2);
683 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
684 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
686 SelectObject(hdc
, old_hfont
);
691 static INT CALLBACK
find_font_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
693 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
695 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
698 return 0; /* stop enumeration */
700 return 1; /* continue enumeration */
703 static BOOL
is_CJK(void)
705 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
708 #define FH_SCALE 0x80000000
709 static void test_bitmap_font_metrics(void)
711 static const WORD skip_rtl
[] = {LANG_ARABIC
, LANG_HEBREW
, 0};
712 static const struct font_data
714 const char face_name
[LF_FACESIZE
];
715 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
716 int ave_char_width
, max_char_width
, dpi
;
717 BYTE first_char
, last_char
, def_char
, break_char
;
719 const WORD
*skip_lang_id
;
723 { "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 },
724 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
725 { "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 },
726 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
727 { "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 },
728 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
729 { "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 },
730 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
731 { "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 },
732 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
734 { "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 },
735 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
736 { "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 },
737 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
738 { "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 },
739 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
740 { "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 },
741 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
742 { "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 },
743 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
745 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
746 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
747 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
748 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
749 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
750 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
751 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
752 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
753 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
754 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
755 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
756 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
757 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
758 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
759 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
760 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
762 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
763 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
764 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
765 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
766 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
767 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
768 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
769 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
770 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
771 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
772 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
773 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
775 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
776 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
777 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
778 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
779 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
780 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
781 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
782 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
783 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
784 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
785 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
786 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
787 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
788 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
789 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
790 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
791 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
793 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
794 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
795 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
796 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
797 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
798 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
799 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
800 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
801 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
802 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
803 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
805 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
806 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
807 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
809 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
810 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
811 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
813 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
814 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
815 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
817 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
818 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
820 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
821 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
822 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
823 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
824 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
825 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
826 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
827 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
828 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
829 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
830 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
831 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
832 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
833 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
834 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
},
835 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
836 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
837 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
838 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, skip_rtl
},
839 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
840 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
842 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
843 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
844 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
845 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
846 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
847 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
848 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
849 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
850 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
851 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
852 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
853 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
855 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
856 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
857 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
859 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
861 /* FIXME: add "Terminal" */
863 static const int font_log_pixels
[] = { 96, 120 };
866 HFONT hfont
, old_hfont
;
868 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
869 char face_name
[LF_FACESIZE
];
872 trace("system language id %04x\n", system_lang_id
);
874 expected_cs
= GetACP();
875 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
877 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
880 expected_cs
= csi
.ciCharset
;
881 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
883 hdc
= CreateCompatibleDC(0);
884 ok(hdc
!= NULL
, "failed to create hdc\n");
886 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
887 GetDeviceCaps(hdc
, LOGPIXELSY
));
889 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
892 for (i
= 0; i
< ARRAY_SIZE(font_log_pixels
); i
++)
894 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
898 font_res
= font_log_pixels
[i
];
901 trace("best font resolution is %d\n", font_res
);
903 for (i
= 0; i
< ARRAY_SIZE(fd
); i
++)
907 memset(&lf
, 0, sizeof(lf
));
909 height
= fd
[i
].height
& ~FH_SCALE
;
910 lf
.lfHeight
= height
;
911 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
913 for(bit
= 0; bit
< 32; bit
++)
921 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
922 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
924 lf
.lfCharSet
= csi
.ciCharset
;
925 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
926 if (fd
[i
].height
& FH_SCALE
)
927 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
930 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
932 todo_wine_if (ret
) /* FIXME: Remove once Wine is fixed */
933 ok(!ret
, "%s height %ld charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
936 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
939 hfont
= create_font(lf
.lfFaceName
, &lf
);
940 old_hfont
= SelectObject(hdc
, hfont
);
942 SetLastError(0xdeadbeef);
943 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
944 ok(ret
, "GetTextFace error %lu\n", GetLastError());
946 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
948 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
949 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
950 SelectObject(hdc
, old_hfont
);
955 memset(&gm
, 0, sizeof(gm
));
956 SetLastError(0xdeadbeef);
957 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
959 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
960 ret
= GetLastError();
961 ok(ret
== ERROR_CAN_NOT_COMPLETE
|| ret
== 0xdeadbeef /* Win10 */, "Unexpected error %d.\n", ret
);
963 bRet
= GetTextMetricsA(hdc
, &tm
);
964 ok(bRet
, "GetTextMetrics error %ld\n", GetLastError());
966 SetLastError(0xdeadbeef);
967 ret
= GetTextCharset(hdc
);
968 if ((is_CJK() || expected_cs
== 254) && lf
.lfCharSet
== ANSI_CHARSET
)
969 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
971 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
973 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
976 if (fd
[i
].skip_lang_id
)
980 while(!skipme
&& fd
[i
].skip_lang_id
[si
])
981 if (fd
[i
].skip_lang_id
[si
++] == system_lang_id
)
986 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
987 if (fd
[i
].height
& FH_SCALE
)
988 ok(tm
.tmHeight
== fd
[i
].scaled_height
, "%s(%d): tm.tmHeight %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmHeight
, fd
[i
].scaled_height
);
990 ok(tm
.tmHeight
== fd
[i
].height
, "%s(%d): tm.tmHeight %ld != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmHeight
, fd
[i
].height
);
991 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
992 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
993 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
994 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
995 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
996 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
997 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
998 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
999 make default char test fail */
1000 if (tm
.tmCharSet
== lf
.lfCharSet
)
1001 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1002 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1003 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
);
1005 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1006 that make the max width bigger */
1007 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1008 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %ld != %d\n", fd
[i
].face_name
, height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
1011 skip("Skipping font metrics test for system langid 0x%x\n",
1014 SelectObject(hdc
, old_hfont
);
1015 DeleteObject(hfont
);
1022 static void test_GdiGetCharDimensions(void)
1028 LONG avgwidth
, height
;
1029 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1031 if (!pGdiGetCharDimensions
)
1033 win_skip("GdiGetCharDimensions not available on this platform\n");
1037 hdc
= CreateCompatibleDC(NULL
);
1039 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1040 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1042 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1043 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
1044 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", tm
.tmHeight
, height
);
1046 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1047 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
1049 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1050 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
1053 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1054 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %ld instead of %ld\n", avgwidth
, ret
);
1055 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %ld instead of %ld\n", size
.cy
, height
);
1060 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1061 const TEXTMETRICA
*lpntme
,
1062 DWORD FontType
, LPARAM lParam
)
1064 if (FontType
& TRUETYPE_FONTTYPE
)
1068 hfont
= CreateFontIndirectA(lpelfe
);
1071 *(HFONT
*)lParam
= hfont
;
1079 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, const ABC
*base_abci
, const ABC
*base_abcw
, const ABCFLOAT
*base_abcf
)
1085 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1086 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1087 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1088 ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1089 ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1091 ret
= GetCharABCWidthsI(hdc
, glyphs
[0], 1, NULL
, abc
);
1092 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1093 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1094 ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1095 ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1097 ret
= GetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1098 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1099 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1100 ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1101 ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1103 ret
= GetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1104 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1105 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1106 ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1107 ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1110 static void test_GetCharABCWidths(void)
1135 {0xffffff, 0xffffff},
1136 {0x1000000, 0x1000000},
1137 {0xffffff, 0x1000000},
1138 {0xffffffff, 0xffffffff},
1146 BOOL r
[ARRAY_SIZE(range
)];
1149 {ANSI_CHARSET
, 0x30, 0x30,
1150 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1151 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1152 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1153 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1154 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1155 {GB2312_CHARSET
, 0x8141, 0x4e04,
1156 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1157 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1158 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1162 memset(&lf
, 0, sizeof(lf
));
1163 strcpy(lf
.lfFaceName
, "System");
1166 hfont
= CreateFontIndirectA(&lf
);
1168 hfont
= SelectObject(hdc
, hfont
);
1170 nb
= GetGlyphIndicesW(hdc
, L
"i", 1, glyphs
, 0);
1171 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1173 ret
= GetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1174 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1176 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1177 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1179 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1180 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1182 ret
= GetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1183 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1185 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1186 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1188 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1189 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1191 ret
= GetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1192 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1194 ret
= GetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1195 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1197 ret
= GetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1198 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1200 hfont
= SelectObject(hdc
, hfont
);
1201 DeleteObject(hfont
);
1203 for (i
= 0; i
< ARRAY_SIZE(c
); ++i
)
1207 UINT code
= 0x41, j
;
1209 lf
.lfFaceName
[0] = '\0';
1210 lf
.lfCharSet
= c
[i
].cs
;
1211 lf
.lfPitchAndFamily
= 0;
1212 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1214 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1218 memset(a
, 0, sizeof a
);
1219 memset(w
, 0, sizeof w
);
1220 hfont
= SelectObject(hdc
, hfont
);
1221 ok(GetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) && GetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
)
1222 && !memcmp(a
, w
, sizeof(a
)),
1223 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1225 memset(a
, 0xbb, sizeof a
);
1226 ret
= GetCharABCWidthsA(hdc
, code
, code
, a
);
1227 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1228 memset(full
, 0xcc, sizeof full
);
1229 ret
= GetCharABCWidthsA(hdc
, 0x00, code
, full
);
1230 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1231 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1232 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1234 for (j
= 0; j
< ARRAY_SIZE(range
); ++j
)
1236 memset(full
, 0xdd, sizeof full
);
1237 ret
= GetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1238 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1239 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1242 UINT last
= range
[j
].last
- range
[j
].first
;
1243 ret
= GetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1244 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1245 "GetCharABCWidthsA %x should match. codepage = %u\n",
1246 range
[j
].last
, c
[i
].cs
);
1250 hfont
= SelectObject(hdc
, hfont
);
1251 DeleteObject(hfont
);
1254 memset(&lf
, 0, sizeof(lf
));
1255 strcpy(lf
.lfFaceName
, "Tahoma");
1257 hfont
= CreateFontIndirectA(&lf
);
1259 /* test empty glyph's metrics */
1260 hfont
= SelectObject(hdc
, hfont
);
1261 ret
= GetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1262 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1263 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1264 ret
= GetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1265 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1266 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1268 /* 1) prepare unrotated font metrics */
1269 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1270 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1271 DeleteObject(SelectObject(hdc
, hfont
));
1273 /* 2) get rotated font metrics */
1274 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1275 hfont
= CreateFontIndirectA(&lf
);
1276 hfont
= SelectObject(hdc
, hfont
);
1277 ret
= GetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1278 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1280 /* 3) compare ABC results */
1281 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1282 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1283 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1284 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1285 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1286 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1288 DeleteObject(SelectObject(hdc
, hfont
));
1290 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1291 in various widths. */
1292 for (i
= 1; i
<= 2; i
++)
1297 memset(&lf
, 0, sizeof(lf
));
1301 strcpy(lf
.lfFaceName
, "Tahoma");
1306 strcpy(lf
.lfFaceName
, "Times New Roman");
1310 if (!is_truetype_font_installed(lf
.lfFaceName
))
1312 skip("%s is not installed\n", lf
.lfFaceName
);
1315 for (j
= 1; j
<= 80; j
++)
1320 hfont
= CreateFontIndirectA(&lf
);
1321 hfont
= SelectObject(hdc
, hfont
);
1323 nb
= GetGlyphOutlineA(hdc
, code
, GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1324 ok(nb
, "GetGlyphOutlineA should have succeeded at width %d\n", i
);
1326 ret
= GetCharABCWidthsA(hdc
, code
, code
, abc
);
1327 ok(ret
, "GetCharABCWidthsA should have succeeded at width %d\n", i
);
1329 ok(abc
[0].abcA
== gm
.gmptGlyphOrigin
.x
,
1330 "abcA(%d) and gmptGlyphOrigin.x(%ld) values are different at width %d\n",
1331 abc
[0].abcA
, gm
.gmptGlyphOrigin
.x
, i
);
1332 ok(abc
[0].abcB
== gm
.gmBlackBoxX
,
1333 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1334 abc
[0].abcB
, gm
.gmBlackBoxX
, i
);
1335 DeleteObject(SelectObject(hdc
, hfont
));
1338 ReleaseDC(NULL
, hdc
);
1340 /* ABC sign test for a variety of transforms */
1341 memset(&lf
, 0, sizeof(lf
));
1342 strcpy(lf
.lfFaceName
, "Tahoma");
1344 hfont
= CreateFontIndirectA(&lf
);
1345 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1348 SetMapMode(hdc
, MM_ANISOTROPIC
);
1349 SelectObject(hdc
, hfont
);
1351 nb
= GetGlyphIndicesW(hdc
, L
"i", 1, glyphs
, 0);
1352 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1354 ret
= GetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1355 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1356 ret
= GetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1357 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1358 ret
= GetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1359 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1361 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
);
1362 SetWindowExtEx(hdc
, -1, -1, NULL
);
1363 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1364 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1365 SetGraphicsMode(hdc
, GM_ADVANCED
);
1366 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1367 SetWindowExtEx(hdc
, 1, 1, NULL
);
1368 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1369 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1370 SetGraphicsMode(hdc
, GM_ADVANCED
);
1371 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1373 ReleaseDC(hwnd
, hdc
);
1374 DestroyWindow(hwnd
);
1377 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1380 SetMapMode(hdc
, MM_ANISOTROPIC
);
1381 SelectObject(hdc
, hfont
);
1383 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
);
1384 SetWindowExtEx(hdc
, -1, -1, NULL
);
1385 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1386 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1387 SetGraphicsMode(hdc
, GM_ADVANCED
);
1388 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1389 SetWindowExtEx(hdc
, 1, 1, NULL
);
1390 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1391 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1392 SetGraphicsMode(hdc
, GM_ADVANCED
);
1393 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1395 ReleaseDC(hwnd
, hdc
);
1396 DestroyWindow(hwnd
);
1397 DeleteObject(hfont
);
1400 static void test_text_extents(void)
1402 static const WCHAR wt
[] = L
"One\ntwo 3";
1404 INT i
, len
, fit1
, fit2
, extents2
[3];
1413 memset(&lf
, 0, sizeof(lf
));
1414 strcpy(lf
.lfFaceName
, "Arial");
1417 hfont
= CreateFontIndirectA(&lf
);
1419 hfont
= SelectObject(hdc
, hfont
);
1420 GetTextMetricsA(hdc
, &tm
);
1421 ret
= GetTextExtentPointA(hdc
, "o", 1, &sz
);
1422 ok(ret
, "got %d\n", ret
);
1423 ok(sz
.cy
== tm
.tmHeight
, "cy %ld tmHeight %ld\n", sz
.cy
, tm
.tmHeight
);
1425 memset(&sz
, 0xcc, sizeof(sz
));
1426 ret
= GetTextExtentPointA(hdc
, "o", 0, &sz
);
1427 ok(ret
, "got %d\n", ret
);
1428 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %ld, cy %ld\n", sz
.cx
, sz
.cy
);
1430 memset(&sz
, 0xcc, sizeof(sz
));
1431 ret
= GetTextExtentPointA(hdc
, "", 0, &sz
);
1432 ok(ret
, "got %d\n", ret
);
1433 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %ld, cy %ld\n", sz
.cx
, sz
.cy
);
1435 memset(&sz
, 0xcc, sizeof(sz
));
1436 ret
= GetTextExtentPointW(hdc
, wt
, 0, &sz
);
1437 ok(ret
, "got %d\n", ret
);
1438 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %ld, cy %ld\n", sz
.cx
, sz
.cy
);
1440 memset(&sz
, 0xcc, sizeof(sz
));
1441 ret
= GetTextExtentPointW(hdc
, L
"", 0, &sz
);
1442 ok(ret
, "got %d\n", ret
);
1443 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %ld, cy %ld\n", sz
.cx
, sz
.cy
);
1446 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1447 extents
[0] = 1; /* So that the increasing sequence test will fail
1448 if the extents array is untouched. */
1449 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1450 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1451 ok(sz1
.cy
== sz2
.cy
,
1452 "cy from GetTextExtentExPointW (%ld) and GetTextExtentPointW (%ld) differ\n", sz1
.cy
, sz2
.cy
);
1453 /* Because of the '\n' in the string GetTextExtentExPoint and
1454 GetTextExtentPoint return different widths under Win2k, but
1455 under WinXP they return the same width. So we don't test that
1458 for (i
= 1; i
< len
; ++i
)
1459 ok(extents
[i
-1] <= extents
[i
],
1460 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1462 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1463 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1464 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1465 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1466 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1467 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1468 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1469 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1470 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1471 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1472 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1473 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1474 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1475 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1477 /* extents functions fail with -ve counts (the interesting case being -1) */
1478 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1479 ok(ret
== FALSE
, "got %d\n", ret
);
1480 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1481 ok(ret
== FALSE
, "got %d\n", ret
);
1482 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1483 ok(ret
== FALSE
, "got %d\n", ret
);
1485 /* max_extent = 0 succeeds and returns zero */
1487 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1488 ok(ret
== TRUE
, "got %d\n", ret
);
1489 ok(fit1
== 0, "fit = %d\n", fit1
);
1490 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1491 ok(ret
== TRUE
, "got %d\n", ret
);
1492 ok(fit2
== 0, "fit = %d\n", fit2
);
1494 /* max_extent = -1 is interpreted as a very large width that will
1495 * definitely fit our three characters */
1497 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1498 ok(ret
== TRUE
, "got %d\n", ret
);
1499 ok(fit1
== 3, "fit = %d\n", fit1
);
1500 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1501 ok(ret
== TRUE
, "got %d\n", ret
);
1502 ok(fit2
== 3, "fit = %d\n", fit2
);
1504 /* max_extent = -2 is interpreted similarly, but the Ansi version
1505 * rejects it while the Unicode one accepts it */
1507 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1508 ok(ret
== FALSE
, "got %d\n", ret
);
1509 ok(fit1
== -215, "fit = %d\n", fit1
);
1510 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1511 ok(ret
== TRUE
, "got %d\n", ret
);
1512 ok(fit2
== 3, "fit = %d\n", fit2
);
1514 hfont
= SelectObject(hdc
, hfont
);
1515 DeleteObject(hfont
);
1517 /* non-MM_TEXT mapping mode */
1519 hfont
= CreateFontIndirectA(&lf
);
1520 hfont
= SelectObject(hdc
, hfont
);
1522 SetMapMode( hdc
, MM_HIMETRIC
);
1523 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1524 ok(ret
, "got %d\n", ret
);
1525 ok(sz
.cx
== extents
[2], "got %ld vs %d\n", sz
.cx
, extents
[2]);
1527 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1528 ok(ret
, "got %d\n", ret
);
1529 ok(fit1
== 2, "got %d\n", fit1
);
1530 ok(sz2
.cx
== sz
.cx
, "got %ld vs %ld\n", sz2
.cx
, sz
.cx
);
1531 for(i
= 0; i
< 2; i
++)
1532 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1534 hfont
= SelectObject(hdc
, hfont
);
1535 DeleteObject(hfont
);
1536 HeapFree(GetProcessHeap(), 0, extents
);
1537 ReleaseDC(NULL
, hdc
);
1540 static void free_font(void *font
)
1542 UnmapViewOfFile(font
);
1545 static void *load_font(const char *font_name
, DWORD
*font_size
)
1547 char file_name
[MAX_PATH
];
1548 HANDLE file
, mapping
;
1551 if (font_name
[1] == ':')
1552 strcpy(file_name
, font_name
);
1555 if (!GetWindowsDirectoryA(file_name
, sizeof(file_name
))) return NULL
;
1556 strcat(file_name
, "\\fonts\\");
1557 strcat(file_name
, font_name
);
1560 file
= CreateFileA(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
1561 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
1563 *font_size
= GetFileSize(file
, NULL
);
1565 mapping
= CreateFileMappingA(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
1572 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
1575 CloseHandle(mapping
);
1579 static void test_GetGlyphIndices(void)
1586 WCHAR testtext
[] = L
"Test\xffff";
1587 WCHAR c
[] = { 0x25bc /* Black Down-Pointing Triangle */, 0x212a /* Kelvin Sign */ };
1588 WORD glyphs
[(sizeof(testtext
)/2)-1];
1592 DWORD ret
, font_size
, num_fonts
;
1594 char ttf_name
[MAX_PATH
];
1598 memset(&lf
, 0, sizeof(lf
));
1599 strcpy(lf
.lfFaceName
, "System");
1601 lf
.lfCharSet
= ANSI_CHARSET
;
1603 hfont
= CreateFontIndirectA(&lf
);
1604 ok(hfont
!= 0, "CreateFontIndirect failed\n");
1605 hOldFont
= SelectObject(hdc
, hfont
);
1606 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetrics failed\n");
1607 if (textm
.tmCharSet
== ANSI_CHARSET
)
1609 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1610 charcount
= GetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1611 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount
);
1612 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1614 charcount
= GetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1615 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount
);
1616 ok(glyphs
[4] == textm
.tmDefaultChar
|| glyphs
[4] == 0x20 /* CJK Windows */,
1617 "GetGlyphIndicesW should have returned a %04x not %04x\n", textm
.tmDefaultChar
, glyphs
[4]);
1620 /* FIXME: Write tests for non-ANSI charsets. */
1621 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1623 DeleteObject(SelectObject(hdc
, hOldFont
));
1625 memset(&lf
, 0, sizeof(lf
));
1626 strcpy(lf
.lfFaceName
, "MS Sans Serif");
1628 lf
.lfCharSet
= DEFAULT_CHARSET
;
1629 hfont
= CreateFontIndirectA(&lf
);
1630 ok(hfont
!= 0, "CreateFontIndirect failed\n");
1631 hOldFont
= SelectObject(hdc
, hfont
);
1632 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetrics failed\n");
1634 glyphs
[0] = glyphs
[1] = 0;
1635 charcount
= GetGlyphIndicesW(hdc
, c
, ARRAY_SIZE(c
), glyphs
, GGI_MARK_NONEXISTING_GLYPHS
);
1636 ok(charcount
== ARRAY_SIZE(c
), "got %lu\n", charcount
);
1637 ok(glyphs
[0] == 0x001f || glyphs
[0] == 0xffff /* Vista */, "got %#x\n", glyphs
[0]);
1638 ok(glyphs
[1] == 0x001f || glyphs
[1] == 0xffff /* Vista */, "got %#x\n", glyphs
[1]);
1640 glyphs
[0] = glyphs
[1] = 0;
1641 charcount
= GetGlyphIndicesW(hdc
, c
, ARRAY_SIZE(c
), glyphs
, 0);
1642 ok(charcount
== ARRAY_SIZE(c
), "got %lu\n", charcount
);
1643 ok(glyphs
[0] == textm
.tmDefaultChar
|| glyphs
[0] == 0x20 /* CJK Windows */, "got %#x\n", glyphs
[0]);
1644 ok(glyphs
[1] == textm
.tmDefaultChar
|| glyphs
[1] == 0x20 /* CJK Windows */, "got %#x\n", glyphs
[1]);
1646 DeleteObject(SelectObject(hdc
, hOldFont
));
1648 if(!is_font_installed("Tahoma"))
1650 skip("Tahoma is not installed so skipping this test\n");
1654 memset(&lf
, 0, sizeof(lf
));
1655 strcpy(lf
.lfFaceName
, "Tahoma");
1658 hfont
= CreateFontIndirectA(&lf
);
1659 hOldFont
= SelectObject(hdc
, hfont
);
1660 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1661 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1662 charcount
= GetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1663 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount
);
1664 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1666 testtext
[0] = textm
.tmDefaultChar
;
1667 charcount
= GetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1668 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount
);
1669 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1670 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1671 DeleteObject(SelectObject(hdc
, hOldFont
));
1673 ret
= write_ttf_file("wine_nul.ttf", ttf_name
);
1674 ok(ret
, "Failed to create test font file.\n");
1675 font
= load_font(ttf_name
, &font_size
);
1676 ok(font
!= NULL
, "Failed to map font file.\n");
1678 rsrc
= AddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
1679 ok(ret
!= 0, "Failed to add resource, %ld.\n", GetLastError());
1680 ok(num_fonts
== 1, "Unexpected number of fonts %lu.\n", num_fonts
);
1682 memset(&lf
, 0, sizeof(lf
));
1683 strcpy(lf
.lfFaceName
, "wine_nul");
1686 hfont
= CreateFontIndirectA(&lf
);
1687 hOldFont
= SelectObject(hdc
, hfont
);
1688 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1690 charcount
= GetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1691 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %ld\n", charcount
);
1692 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1693 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1694 DeleteObject(SelectObject(hdc
, hOldFont
));
1698 ret
= RemoveFontMemResourceEx(rsrc
);
1699 ok(ret
, "RemoveFontMemResourceEx error %ld\n", GetLastError());
1701 ret
= DeleteFileA(ttf_name
);
1702 ok(ret
, "Failed to delete font file, %ld.\n", GetLastError());
1705 static void test_GetKerningPairs(void)
1707 static const struct kerning_data
1709 const char face_name
[LF_FACESIZE
];
1711 /* some interesting fields from OUTLINETEXTMETRIC */
1712 LONG tmHeight
, tmAscent
, tmDescent
;
1717 UINT otmsCapEmHeight
;
1722 UINT otmusMinimumPPEM
;
1723 /* small subset of kerning pairs to test */
1724 DWORD total_kern_pairs
;
1725 const KERNINGPAIR kern_pair
[26];
1728 {"Arial", 12, 12, 9, 3,
1729 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1732 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1733 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1734 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1735 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1736 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1737 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1738 {933,970,+1},{933,972,-1}
1741 {"Arial", -34, 39, 32, 7,
1742 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1745 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1746 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1747 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1748 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1749 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1750 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1751 {933,970,+2},{933,972,-3}
1754 { "Arial", 120, 120, 97, 23,
1755 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1758 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1759 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1760 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1761 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1762 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1763 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1764 {933,970,+6},{933,972,-10}
1767 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1768 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1769 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1772 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1773 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1774 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1775 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1776 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1777 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1778 {933,970,+54},{933,972,-83}
1784 HFONT hfont
, hfont_old
;
1785 KERNINGPAIR
*kern_pair
;
1787 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1791 for (i
= 0; i
< ARRAY_SIZE(kd
); i
++)
1793 OUTLINETEXTMETRICW otm
;
1796 if (!is_font_installed(kd
[i
].face_name
))
1798 skip("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1802 memset(&lf
, 0, sizeof(lf
));
1803 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1804 lf
.lfHeight
= kd
[i
].height
;
1805 hfont
= CreateFontIndirectA(&lf
);
1806 ok(hfont
!= NULL
, "failed to create a font, name %s\n", kd
[i
].face_name
);
1808 hfont_old
= SelectObject(hdc
, hfont
);
1810 SetLastError(0xdeadbeef);
1811 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1812 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %ld\n", GetLastError());
1814 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %ld, got %ld\n",
1815 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1816 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %ld, got %ld\n",
1817 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1818 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %ld, got %ld\n",
1819 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1821 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1822 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1823 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1824 kd
[i
].otmAscent
, otm
.otmAscent
);
1825 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1826 kd
[i
].otmDescent
, otm
.otmDescent
);
1827 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1828 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1829 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1830 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1831 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1832 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1834 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1835 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1837 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1838 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1839 ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1840 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1842 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1843 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1845 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1846 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1848 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1851 SetLastError(0xdeadbeef);
1852 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1853 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1854 "got error %lu, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1855 ok(ret
== 0, "got %lu, expected 0\n", ret
);
1857 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1858 ok(ret
== total_kern_pairs
, "got %lu, expected %lu\n", ret
, total_kern_pairs
);
1860 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1861 ok(ret
== total_kern_pairs
/2, "got %lu, expected %lu\n", ret
, total_kern_pairs
/2);
1863 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1864 ok(ret
== total_kern_pairs
, "got %lu, expected %lu\n", ret
, total_kern_pairs
);
1868 for (n
= 0; n
< ret
; n
++)
1872 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1874 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1875 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1877 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1878 "pair %d:%d got %d, expected %d\n",
1879 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1880 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1886 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %lu, expected %lu\n",
1887 matches
, kd
[i
].total_kern_pairs
);
1889 HeapFree(GetProcessHeap(), 0, kern_pair
);
1891 SelectObject(hdc
, hfont_old
);
1892 DeleteObject(hfont
);
1900 const char face_name
[LF_FACESIZE
];
1901 int requested_height
;
1902 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1906 static void test_height( HDC hdc
, const struct font_data
*fd
)
1909 HFONT hfont
, old_hfont
;
1913 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1915 if (!is_truetype_font_installed(fd
[i
].face_name
))
1917 skip("%s is not installed\n", fd
[i
].face_name
);
1921 memset(&lf
, 0, sizeof(lf
));
1922 lf
.lfHeight
= fd
[i
].requested_height
;
1923 lf
.lfWeight
= fd
[i
].weight
;
1924 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1926 hfont
= CreateFontIndirectA(&lf
);
1927 ok(hfont
!= NULL
, "failed to create a font, name %s\n", fd
[i
].face_name
);
1929 old_hfont
= SelectObject(hdc
, hfont
);
1930 ret
= GetTextMetricsA(hdc
, &tm
);
1931 ok(ret
, "GetTextMetrics error %ld\n", GetLastError());
1932 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1934 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %ld != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmWeight
, fd
[i
].weight
);
1935 ok(match_off_by_1(tm
.tmHeight
, fd
[i
].height
, fd
[i
].exact
), "%s(%d): tm.tmHeight %ld != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmHeight
, fd
[i
].height
);
1936 ok(match_off_by_1(tm
.tmAscent
, fd
[i
].ascent
, fd
[i
].exact
), "%s(%d): tm.tmAscent %ld != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmAscent
, fd
[i
].ascent
);
1937 ok(match_off_by_1(tm
.tmDescent
, fd
[i
].descent
, fd
[i
].exact
), "%s(%d): tm.tmDescent %ld != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmDescent
, fd
[i
].descent
);
1938 ok(match_off_by_1(tm
.tmInternalLeading
, fd
[i
].int_leading
, fd
[i
].exact
), "%s(%d): tm.tmInternalLeading %ld != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1939 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %ld != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1942 SelectObject(hdc
, old_hfont
);
1943 /* force GDI to use new font, otherwise Windows leaks the font reference */
1944 GetTextMetricsA(hdc
, &tm
);
1945 DeleteObject(hfont
);
1949 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1951 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1952 DWORD
*table
= (DWORD
*)ttf
+ 3;
1954 for (i
= 0; i
< num_tables
; i
++)
1956 if (table
[0] == tag
)
1957 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
1963 static void test_height_selection_vdmx( HDC hdc
)
1965 static const struct font_data charset_0
[] = /* doesn't use VDMX */
1967 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1968 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1969 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1970 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1971 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1972 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
1973 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1974 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1975 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1976 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1977 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
1978 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1979 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1980 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1981 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1982 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1983 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
1984 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1985 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1986 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1987 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1988 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1989 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
1990 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
1991 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
1992 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
1993 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1994 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1995 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1996 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1997 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1998 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1999 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
2000 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
2001 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
2002 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
2003 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2004 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
2005 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
2006 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2007 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2008 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2009 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2010 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
2011 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
2012 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
2013 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
2014 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
2015 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
2016 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2017 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
2018 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2019 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2022 static const struct font_data charset_1
[] = /* Uses VDMX */
2024 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2025 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2026 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2027 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2028 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2029 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2030 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2031 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2032 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2033 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2034 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2035 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2036 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2037 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2038 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2039 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2040 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2041 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2042 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2043 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2044 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2045 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2046 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2047 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
2048 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
2049 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
2050 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2051 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2052 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2053 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2054 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2055 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2056 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2057 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2058 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2059 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2060 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2061 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2062 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2063 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2064 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2065 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
2066 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
2067 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
2068 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
2069 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
2070 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
2071 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
2072 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
2073 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
2074 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
2075 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
2076 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2079 static const struct vdmx_data
2083 const struct font_data
*fd
;
2086 { 0, 0, charset_0
},
2087 { 0, 1, charset_1
},
2088 { 1, 0, charset_0
},
2095 char ttf_name
[MAX_PATH
];
2099 for (i
= 0; i
< ARRAY_SIZE(data
); i
++)
2101 res
= get_res_data( "wine_vdmx.ttf", &size
);
2103 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2104 memcpy( copy
, res
, size
);
2105 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2106 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2107 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2108 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2109 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2110 ratio_rec
[0] = data
[i
].bCharSet
;
2112 write_tmp_file( copy
, &size
, ttf_name
);
2113 HeapFree( GetProcessHeap(), 0, copy
);
2115 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2116 num
= AddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2117 if (!num
) win_skip("Unable to add ttf font resource\n");
2120 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2121 test_height( hdc
, data
[i
].fd
);
2122 RemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2124 ret
= DeleteFileA( ttf_name
);
2125 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
),
2126 "DeleteFile error %ld\n", GetLastError());
2130 static void test_height_selection(void)
2132 static const struct font_data tahoma
[] =
2134 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2135 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2136 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2137 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2138 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2139 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2140 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2141 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2142 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2143 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2144 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2146 HDC hdc
= CreateCompatibleDC(0);
2147 ok(hdc
!= NULL
, "failed to create hdc\n");
2149 test_height( hdc
, tahoma
);
2150 test_height_selection_vdmx( hdc
);
2155 static UINT
get_font_fsselection(LOGFONTA
*lf
)
2157 OUTLINETEXTMETRICA
*otm
;
2158 HFONT hfont
, hfont_old
;
2159 DWORD ret
, otm_size
;
2164 hfont
= CreateFontIndirectA(lf
);
2165 ok(hfont
!= NULL
, "failed to create a font\n");
2167 hfont_old
= SelectObject(hdc
, hfont
);
2169 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2170 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2171 otm
->otmSize
= sizeof(*otm
);
2172 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2173 ok(ret
== otm
->otmSize
, "expected %u, got %lu, error %ld\n", otm
->otmSize
, ret
, GetLastError());
2174 fsSelection
= otm
->otmfsSelection
;
2175 HeapFree(GetProcessHeap(), 0, otm
);
2176 SelectObject(hdc
, hfont_old
);
2177 DeleteObject(hfont
);
2183 static void test_GetOutlineTextMetrics(void)
2185 OUTLINETEXTMETRICA
*otm
;
2187 HFONT hfont
, hfont_old
;
2189 DWORD ret
, otm_size
;
2193 /* check fsSelection field with bold simulation */
2194 memset(&lf
, 0, sizeof(lf
));
2195 strcpy(lf
.lfFaceName
, "Wingdings");
2196 lf
.lfCharSet
= SYMBOL_CHARSET
;
2199 fsSelection
= get_font_fsselection(&lf
);
2200 ok((fsSelection
& (1 << 5)) == 0, "got 0x%x\n", fsSelection
);
2202 /* face with bold simulation */
2203 lf
.lfWeight
= FW_BOLD
;
2204 fsSelection
= get_font_fsselection(&lf
);
2205 ok((fsSelection
& (1 << 5)) != 0, "got 0x%x\n", fsSelection
);
2207 /* check fsSelection field with oblique simulation */
2208 memset(&lf
, 0, sizeof(lf
));
2209 strcpy(lf
.lfFaceName
, "Tahoma");
2211 lf
.lfWeight
= FW_NORMAL
;
2212 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2213 lf
.lfQuality
= PROOF_QUALITY
;
2216 fsSelection
= get_font_fsselection(&lf
);
2217 ok((fsSelection
& 1) == 0, "got 0x%x\n", fsSelection
);
2220 /* face with oblique simulation */
2221 fsSelection
= get_font_fsselection(&lf
);
2222 ok((fsSelection
& 1) == 1, "got 0x%x\n", fsSelection
);
2224 if (!is_font_installed("Arial"))
2226 skip("Arial is not installed\n");
2232 memset(&lf
, 0, sizeof(lf
));
2233 strcpy(lf
.lfFaceName
, "Arial");
2235 lf
.lfWeight
= FW_NORMAL
;
2236 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2237 lf
.lfQuality
= PROOF_QUALITY
;
2238 hfont
= CreateFontIndirectA(&lf
);
2239 ok(hfont
!= NULL
, "failed to create a font\n");
2241 hfont_old
= SelectObject(hdc
, hfont
);
2242 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2244 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2246 memset(otm
, 0xAA, otm_size
);
2247 SetLastError(0xdeadbeef);
2248 otm
->otmSize
= sizeof(*otm
);
2249 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2250 ok(ret
== otm
->otmSize
, "expected %u, got %lu, error %ld\n", otm
->otmSize
, ret
, GetLastError());
2251 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2252 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2253 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2254 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2256 memset(otm
, 0xAA, otm_size
);
2257 SetLastError(0xdeadbeef);
2258 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2259 ok(ret
== otm
->otmSize
, "expected %u, got %lu, error %ld\n", otm
->otmSize
, ret
, GetLastError());
2260 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2261 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2262 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2263 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2265 /* ask about truncated data */
2266 memset(otm
, 0xAA, otm_size
);
2267 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2268 SetLastError(0xdeadbeef);
2269 otm
->otmSize
= sizeof(*otm
) - sizeof(char*);
2270 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2271 ok(ret
== otm
->otmSize
, "expected %u, got %lu, error %ld\n", otm
->otmSize
, ret
, GetLastError());
2272 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2273 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2274 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2275 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2277 /* check handling of NULL pointer */
2278 SetLastError(0xdeadbeef);
2279 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, NULL
);
2280 ok(ret
== otm_size
, "expected %lu, got %lu, error %ld\n", otm_size
, ret
, GetLastError());
2282 HeapFree(GetProcessHeap(), 0, otm
);
2284 SelectObject(hdc
, hfont_old
);
2285 DeleteObject(hfont
);
2290 static void testJustification(const char *context
, HDC hdc
, PCSTR str
, RECT
*clientArea
)
2294 areaWidth
= clientArea
->right
- clientArea
->left
,
2296 const char *pFirstChar
, *pLastChar
;
2303 int GetTextExtentExPointWWidth
;
2306 GetTextMetricsA(hdc
, &tm
);
2307 y
= clientArea
->top
;
2310 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2316 /* if not at the end of the string, ... */
2317 if (*str
== '\0') break;
2318 /* ... add the next word to the current extent */
2319 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2321 SetTextJustification(hdc
, 0, 0);
2322 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2323 } while ((int) size
.cx
< areaWidth
);
2325 /* ignore trailing break chars */
2327 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2333 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2335 SetTextJustification(hdc
, 0, 0);
2336 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2338 /* do not justify the last extent */
2339 if (*str
!= '\0' && breakCount
> 0)
2341 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2342 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2343 if (size
.cx
!= areaWidth
&& nErrors
< ARRAY_SIZE(error
) - 1)
2345 error
[nErrors
].start
= pFirstChar
;
2346 error
[nErrors
].len
= pLastChar
- pFirstChar
;
2347 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
2354 } while (*str
&& y
< clientArea
->bottom
);
2356 for (e
= 0; e
< nErrors
; e
++)
2358 /* The width returned by GetTextExtentPoint32() is exactly the same
2359 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
2360 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
||
2361 broken(abs(areaWidth
- error
[e
].GetTextExtentExPointWWidth
) <= 2) /* win10 */,
2362 "%s: GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
2363 context
, error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
2367 static void test_SetTextJustification(void)
2377 static const char testText
[] =
2378 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
2379 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
2380 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
2381 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
2382 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
2383 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
2384 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
2386 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
2387 GetClientRect( hwnd
, &clientArea
);
2388 hdc
= GetDC( hwnd
);
2390 if (!is_font_installed("Times New Roman"))
2392 skip("Times New Roman is not installed\n");
2396 memset(&lf
, 0, sizeof lf
);
2397 lf
.lfCharSet
= ANSI_CHARSET
;
2398 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2399 lf
.lfWeight
= FW_DONTCARE
;
2401 lf
.lfQuality
= DEFAULT_QUALITY
;
2402 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
2403 hfont
= create_font("Times New Roman", &lf
);
2404 SelectObject(hdc
, hfont
);
2406 testJustification("default", hdc
, testText
, &clientArea
);
2408 GetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
2410 SetTextJustification(hdc
, 0, 0);
2411 GetTextExtentPoint32A(hdc
, " ", 1, &expect
);
2412 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2413 ok( size
.cx
== 3 * expect
.cx
, "wrong size %ld/%ld\n", size
.cx
, expect
.cx
);
2414 SetTextJustification(hdc
, 4, 1);
2415 GetTextExtentPoint32A(hdc
, " ", 1, &size
);
2416 ok( size
.cx
== expect
.cx
+ 4, "wrong size %ld/%ld\n", size
.cx
, expect
.cx
);
2417 SetTextJustification(hdc
, 9, 2);
2418 GetTextExtentPoint32A(hdc
, " ", 2, &size
);
2419 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %ld/%ld\n", size
.cx
, expect
.cx
);
2420 SetTextJustification(hdc
, 7, 3);
2421 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2422 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %ld/%ld\n", size
.cx
, expect
.cx
);
2423 SetTextJustification(hdc
, 7, 3);
2424 SetTextCharacterExtra(hdc
, 2 );
2425 GetTextExtentPoint32A(hdc
, " ", 3, &size
);
2426 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %ld/%ld\n", size
.cx
, expect
.cx
);
2427 SetTextJustification(hdc
, 0, 0);
2428 SetTextCharacterExtra(hdc
, 0);
2429 size
.cx
= size
.cy
= 1234;
2430 GetTextExtentPoint32A(hdc
, " ", 0, &size
);
2431 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %ld,%ld\n", size
.cx
, size
.cy
);
2432 GetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
2433 SetTextJustification(hdc
, 5, 1);
2434 GetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
2435 ok( size
.cx
== expect
.cx
+ 5, "wrong size %ld/%ld\n", size
.cx
, expect
.cx
);
2436 SetTextJustification(hdc
, 0, 0);
2438 SetMapMode( hdc
, MM_ANISOTROPIC
);
2439 SetWindowExtEx( hdc
, 2, 2, NULL
);
2440 GetClientRect( hwnd
, &clientArea
);
2441 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2442 testJustification("2x2", hdc
, testText
, &clientArea
);
2444 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2445 for (i
= 0; i
< 10; i
++)
2447 SetTextCharacterExtra(hdc
, i
);
2448 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2449 ok( size
.cx
== expect
.cx
+ i
, "wrong size %ld/%ld+%d\n", size
.cx
, expect
.cx
, i
);
2451 SetTextCharacterExtra(hdc
, 0);
2452 GetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
2453 for (i
= 0; i
< 10; i
++)
2455 SetTextCharacterExtra(hdc
, i
);
2456 GetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
2457 ok( size
.cx
== expect
.cx
+ i
, "wrong size %ld/%ld+%d\n", size
.cx
, expect
.cx
, i
);
2459 SetTextCharacterExtra(hdc
, 0);
2461 SetViewportExtEx( hdc
, 3, 3, NULL
);
2462 GetClientRect( hwnd
, &clientArea
);
2463 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
2464 testJustification("3x3", hdc
, testText
, &clientArea
);
2466 GetTextExtentPoint32A(hdc
, "A", 1, &expect
);
2467 for (i
= 0; i
< 10; i
++)
2469 SetTextCharacterExtra(hdc
, i
);
2470 GetTextExtentPoint32A(hdc
, "A", 1, &size
);
2471 ok( size
.cx
== expect
.cx
+ i
, "wrong size %ld/%ld+%d\n", size
.cx
, expect
.cx
, i
);
2474 DeleteObject(hfont
);
2475 ReleaseDC(hwnd
, hdc
);
2476 DestroyWindow(hwnd
);
2479 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
2483 HFONT hfont
, hfont_old
;
2490 assert(count
<= 128);
2492 memset(&lf
, 0, sizeof(lf
));
2494 lf
.lfCharSet
= charset
;
2496 lstrcpyA(lf
.lfFaceName
, "Arial");
2497 SetLastError(0xdeadbeef);
2498 hfont
= CreateFontIndirectA(&lf
);
2499 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
2502 hfont_old
= SelectObject(hdc
, hfont
);
2504 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
2505 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
2507 SetLastError(0xdeadbeef);
2508 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
2509 ok(ret
, "GetTextFaceA error %lu\n", GetLastError());
2511 if (charset
== SYMBOL_CHARSET
)
2513 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
2514 ok(fs
.fsCsb
[0] & (1u << 31), "symbol encoding should be available\n");
2518 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
2519 ok(!(fs
.fsCsb
[0] & (1u << 31)), "symbol encoding should NOT be available\n");
2522 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
2524 trace("Can't find codepage for charset %d\n", cs
);
2528 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2530 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2532 skip("Font code page %ld, looking for code page %d\n",
2533 pGdiGetCodePage(hdc
), code_page
);
2541 WCHAR unicode_buf
[128];
2543 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2545 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2547 SetLastError(0xdeadbeef);
2548 ret
= GetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2549 ok(ret
== count
, "GetGlyphIndicesW expected %d got %ld, error %lu\n",
2550 count
, ret
, GetLastError());
2556 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2558 SetLastError(0xdeadbeef);
2559 ret
= GetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2560 ok(ret
== count
, "GetGlyphIndicesA expected %d got %ld, error %lu\n",
2561 count
, ret
, GetLastError());
2564 SelectObject(hdc
, hfont_old
);
2565 DeleteObject(hfont
);
2572 static void test_TranslateCharsetInfo(void)
2574 static CHARSETINFO tests
[] =
2576 { ANSI_CHARSET
, 1252, { {0}, { FS_LATIN1
}}},
2577 { EASTEUROPE_CHARSET
, 1250, { {0}, { FS_LATIN2
}}},
2578 { RUSSIAN_CHARSET
, 1251, { {0}, { FS_CYRILLIC
}}},
2579 { GREEK_CHARSET
, 1253, { {0}, { FS_GREEK
}}},
2580 { TURKISH_CHARSET
, 1254, { {0}, { FS_TURKISH
}}},
2581 { HEBREW_CHARSET
, 1255, { {0}, { FS_HEBREW
}}},
2582 { ARABIC_CHARSET
, 1256, { {0}, { FS_ARABIC
}}},
2583 { BALTIC_CHARSET
, 1257, { {0}, { FS_BALTIC
}}},
2584 { VIETNAMESE_CHARSET
, 1258, { {0}, { FS_VIETNAMESE
}}},
2585 { THAI_CHARSET
, 874, { {0}, { FS_THAI
}}},
2586 { SHIFTJIS_CHARSET
, 932, { {0}, { FS_JISJAPAN
}}},
2587 { GB2312_CHARSET
, 936, { {0}, { FS_CHINESESIMP
}}},
2588 { HANGEUL_CHARSET
, 949, { {0}, { FS_WANSUNG
}}},
2589 { CHINESEBIG5_CHARSET
, 950, { {0}, { FS_CHINESETRAD
}}},
2590 { JOHAB_CHARSET
, 1361, { {0}, { FS_JOHAB
}}},
2591 { 254, CP_UTF8
, { {0}, { 0x04000000 }}},
2592 { SYMBOL_CHARSET
, CP_SYMBOL
, { {0}, { FS_SYMBOL
}}}
2598 /* try all codepages */
2599 for (i
= 0; i
< 65536; i
++)
2601 memset( &csi
, 0xcc, sizeof(csi
) );
2602 ret
= TranslateCharsetInfo( ULongToPtr(i
), &csi
, TCI_SRCCODEPAGE
);
2605 for (j
= 0; j
< ARRAY_SIZE(tests
); j
++)
2607 if (tests
[j
].ciACP
!= i
) continue;
2608 ok( !memcmp( &csi
, &tests
[j
], sizeof(csi
) ),
2609 "%lu: wrong info %u %u %08lx %08lx %08lx %08lx %08lx %08lx\n", i
,
2610 csi
.ciCharset
, csi
.ciACP
, csi
.fs
.fsUsb
[0], csi
.fs
.fsUsb
[1],
2611 csi
.fs
.fsUsb
[2], csi
.fs
.fsUsb
[3], csi
.fs
.fsCsb
[0], csi
.fs
.fsCsb
[1] );
2614 ok( j
< ARRAY_SIZE(tests
), "%lu: TranslateCharsetInfo succeeded\n", i
);
2616 else ok( !ret
, "%lu: TranslateCharsetInfo succeeded\n", i
);
2619 /* try all charsets */
2620 for (i
= 0; i
< 256; i
++)
2622 memset( &csi
, 0xcc, sizeof(csi
) );
2623 ret
= TranslateCharsetInfo( ULongToPtr(i
), &csi
, TCI_SRCCHARSET
);
2626 for (j
= 0; j
< ARRAY_SIZE(tests
); j
++)
2628 if (tests
[j
].ciCharset
!= i
) continue;
2629 ok( !memcmp( &csi
, &tests
[j
], sizeof(csi
) ),
2630 "%lu: wrong info %u %u %08lx %08lx %08lx %08lx %08lx %08lx\n", i
,
2631 csi
.ciCharset
, csi
.ciACP
, csi
.fs
.fsUsb
[0], csi
.fs
.fsUsb
[1],
2632 csi
.fs
.fsUsb
[2], csi
.fs
.fsUsb
[3], csi
.fs
.fsCsb
[0], csi
.fs
.fsCsb
[1] );
2635 ok( j
< ARRAY_SIZE(tests
), "%lu: TranslateCharsetInfo succeeded\n", i
);
2637 else ok( !ret
, "%lu: TranslateCharsetInfo succeeded\n", i
);
2640 /* try all fontsigs */
2641 for (i
= 0; i
< 64; i
++)
2643 DWORD csb
[2] = { 0, 0 };
2644 csb
[i
/ 32] = 1 << (i
% 32);
2645 memset( &csi
, 0xcc, sizeof(csi
) );
2646 ret
= TranslateCharsetInfo( csb
, &csi
, TCI_SRCFONTSIG
);
2649 for (j
= 0; j
< ARRAY_SIZE(tests
); j
++)
2651 if (tests
[j
].fs
.fsCsb
[0] != csb
[0]) continue;
2652 ok( !memcmp( &csi
, &tests
[j
], sizeof(csi
) ),
2653 "%lu: wrong info %u %u %08lx %08lx %08lx %08lx %08lx %08lx\n", i
,
2654 csi
.ciCharset
, csi
.ciACP
, csi
.fs
.fsUsb
[0], csi
.fs
.fsUsb
[1],
2655 csi
.fs
.fsUsb
[2], csi
.fs
.fsUsb
[3], csi
.fs
.fsCsb
[0], csi
.fs
.fsCsb
[1] );
2658 ok( j
< ARRAY_SIZE(tests
), "%lu: TranslateCharsetInfo succeeded\n", i
);
2660 else ok( !ret
, "%lu: TranslateCharsetInfo succeeded\n", i
);
2664 static void test_font_charset(void)
2666 static struct charset_data
2670 WORD font_idxA
[128], font_idxW
[128];
2673 { ANSI_CHARSET
, 1252 },
2674 { RUSSIAN_CHARSET
, 1251 },
2675 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2679 if (!is_font_installed("Arial"))
2681 skip("Arial is not installed\n");
2685 for (i
= 0; i
< ARRAY_SIZE(cd
); i
++)
2687 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2689 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2691 skip("Symbol or Wingdings is not installed\n");
2695 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2696 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2697 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2700 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2703 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2704 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2707 skip("Symbol or Wingdings is not installed\n");
2710 static void test_GdiGetCodePage(void)
2712 static const struct _matching_data
2714 UINT current_codepage
;
2717 UINT expected_codepage
;
2718 } matching_data
[] = {
2719 {1251, "Arial", ANSI_CHARSET
, 1252},
2720 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2722 {1252, "Arial", ANSI_CHARSET
, 1252},
2723 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2725 {1253, "Arial", ANSI_CHARSET
, 1252},
2726 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2728 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2729 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2730 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2732 { 936, "Arial", ANSI_CHARSET
, 936},
2733 { 936, "Tahoma", ANSI_CHARSET
, 936},
2734 { 936, "Simsun", ANSI_CHARSET
, 936},
2736 { 949, "Arial", ANSI_CHARSET
, 949},
2737 { 949, "Tahoma", ANSI_CHARSET
, 949},
2738 { 949, "Gulim", ANSI_CHARSET
, 949},
2740 { 950, "Arial", ANSI_CHARSET
, 950},
2741 { 950, "Tahoma", ANSI_CHARSET
, 950},
2742 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2751 if (!pGdiGetCodePage
)
2753 skip("GdiGetCodePage not available on this platform\n");
2759 for (i
= 0; i
< ARRAY_SIZE(matching_data
); i
++)
2761 /* only test data matched current locale codepage */
2762 if (matching_data
[i
].current_codepage
!= acp
)
2765 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2767 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2773 memset(&lf
, 0, sizeof(lf
));
2775 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2776 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2777 hfont
= CreateFontIndirectA(&lf
);
2778 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
2780 hfont
= SelectObject(hdc
, hfont
);
2781 codepage
= pGdiGetCodePage(hdc
);
2782 ok(codepage
== matching_data
[i
].expected_codepage
,
2783 "GdiGetCodePage should have returned %d, got %ld\n", matching_data
[i
].expected_codepage
, codepage
);
2785 hfont
= SelectObject(hdc
, hfont
);
2786 DeleteObject(hfont
);
2788 /* CLIP_DFA_DISABLE turns off the font association */
2789 lf
.lfClipPrecision
= CLIP_DFA_DISABLE
;
2790 hfont
= CreateFontIndirectA(&lf
);
2791 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
2793 hfont
= SelectObject(hdc
, hfont
);
2794 codepage
= pGdiGetCodePage(hdc
);
2795 ok(codepage
== 1252, "GdiGetCodePage returned %ld\n", codepage
);
2797 hfont
= SelectObject(hdc
, hfont
);
2798 DeleteObject(hfont
);
2800 ReleaseDC(NULL
, hdc
);
2804 static void test_GetFontUnicodeRanges(void)
2808 HFONT hfont
, hfont_old
;
2812 memset(&lf
, 0, sizeof(lf
));
2813 lstrcpyA(lf
.lfFaceName
, "Arial");
2814 hfont
= create_font("Arial", &lf
);
2817 hfont_old
= SelectObject(hdc
, hfont
);
2819 size
= GetFontUnicodeRanges(NULL
, NULL
);
2820 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2822 size
= GetFontUnicodeRanges(hdc
, NULL
);
2823 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2825 gs
= heap_alloc_zero(size
);
2827 size
= GetFontUnicodeRanges(hdc
, gs
);
2828 ok(size
, "GetFontUnicodeRanges failed\n");
2829 ok(gs
->cRanges
, "Unexpected ranges count.\n");
2833 SelectObject(hdc
, hfont_old
);
2834 DeleteObject(hfont
);
2835 ReleaseDC(NULL
, hdc
);
2838 struct enum_font_data
2844 struct enum_fullname_data
2850 struct enum_fullname_data_w
2856 struct enum_font_dataW
2862 static INT CALLBACK
arial_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
2864 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2865 const NEWTEXTMETRICA
*ntm
= (const NEWTEXTMETRICA
*)tm
;
2867 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %ld != tmHeight %ld\n", lf
->lfHeight
, tm
->tmHeight
);
2869 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2871 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2873 if (efd
->total
>= efd
->size
)
2875 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2876 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2877 if (!efd
->lf
) return 0;
2879 efd
->lf
[efd
->total
++] = *lf
;
2884 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2886 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2887 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2889 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %ld != tmHeight %ld\n", lf
->lfHeight
, tm
->tmHeight
);
2891 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2893 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2895 if (efd
->total
>= efd
->size
)
2897 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
2898 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
2899 if (!efd
->lf
) return 0;
2901 efd
->lf
[efd
->total
++] = *lf
;
2906 static void get_charset_stats(struct enum_font_data
*efd
,
2907 int *ansi_charset
, int *symbol_charset
,
2908 int *russian_charset
)
2913 *symbol_charset
= 0;
2914 *russian_charset
= 0;
2916 for (i
= 0; i
< efd
->total
; i
++)
2918 switch (efd
->lf
[i
].lfCharSet
)
2923 case SYMBOL_CHARSET
:
2924 (*symbol_charset
)++;
2926 case RUSSIAN_CHARSET
:
2927 (*russian_charset
)++;
2933 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2934 int *ansi_charset
, int *symbol_charset
,
2935 int *russian_charset
)
2940 *symbol_charset
= 0;
2941 *russian_charset
= 0;
2943 for (i
= 0; i
< efd
->total
; i
++)
2945 switch (efd
->lf
[i
].lfCharSet
)
2950 case SYMBOL_CHARSET
:
2951 (*symbol_charset
)++;
2953 case RUSSIAN_CHARSET
:
2954 (*russian_charset
)++;
2960 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2962 struct enum_font_data efd
;
2963 struct enum_font_dataW efdw
;
2966 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2968 if (*font_name
&& !is_truetype_font_installed(font_name
))
2970 skip("%s is not installed\n", font_name
);
2973 memset( &efd
, 0, sizeof(efd
) );
2974 memset( &efdw
, 0, sizeof(efdw
) );
2978 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2979 * while EnumFontFamiliesEx doesn't.
2981 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2984 * Use EnumFontFamiliesW since win98 crashes when the
2985 * second parameter is NULL using EnumFontFamilies
2988 SetLastError(0xdeadbeef);
2989 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2990 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %lu\n", GetLastError());
2993 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2994 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2995 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2996 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2997 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
3001 SetLastError(0xdeadbeef);
3002 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
3003 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %lu\n", GetLastError());
3006 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3007 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
3008 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
3009 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
3010 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
3015 SetLastError(0xdeadbeef);
3016 ret
= EnumFontFamiliesA(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
3017 ok(ret
, "EnumFontFamilies error %lu\n", GetLastError());
3018 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3020 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3022 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
3023 for (i
= 0; i
< efd
.total
; i
++)
3025 /* FIXME: remove completely once Wine is fixed */
3026 todo_wine_if(efd
.lf
[i
].lfCharSet
!= font_charset
)
3027 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3028 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3029 font_name
, efd
.lf
[i
].lfFaceName
);
3032 memset(&lf
, 0, sizeof(lf
));
3033 lf
.lfCharSet
= ANSI_CHARSET
;
3034 strcpy(lf
.lfFaceName
, font_name
);
3036 SetLastError(0xdeadbeef);
3037 ret
= EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3038 ok(ret
, "EnumFontFamiliesEx error %lu\n", GetLastError());
3039 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3040 if (font_charset
== SYMBOL_CHARSET
)
3043 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
3045 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
3049 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
3050 for (i
= 0; i
< efd
.total
; i
++)
3052 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3054 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3055 font_name
, efd
.lf
[i
].lfFaceName
);
3059 /* DEFAULT_CHARSET should enumerate all available charsets */
3060 memset(&lf
, 0, sizeof(lf
));
3061 lf
.lfCharSet
= DEFAULT_CHARSET
;
3062 strcpy(lf
.lfFaceName
, font_name
);
3064 SetLastError(0xdeadbeef);
3065 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3066 ok(ret
, "EnumFontFamiliesEx error %lu\n", GetLastError());
3067 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3068 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
3069 for (i
= 0; i
< efd
.total
; i
++)
3072 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3073 font_name
, efd
.lf
[i
].lfFaceName
);
3077 switch (font_charset
)
3080 ok(ansi_charset
> 0,
3081 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3083 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
3084 ok(russian_charset
> 0,
3085 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3087 case SYMBOL_CHARSET
:
3089 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
3091 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3092 ok(!russian_charset
,
3093 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3095 case DEFAULT_CHARSET
:
3096 ok(ansi_charset
> 0,
3097 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
3098 ok(symbol_charset
> 0,
3099 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
3100 ok(russian_charset
> 0,
3101 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
3107 ok(ansi_charset
> 0,
3108 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3109 ok(symbol_charset
> 0,
3110 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3111 ok(russian_charset
> 0,
3112 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3115 memset(&lf
, 0, sizeof(lf
));
3116 lf
.lfCharSet
= SYMBOL_CHARSET
;
3117 strcpy(lf
.lfFaceName
, font_name
);
3119 SetLastError(0xdeadbeef);
3120 EnumFontFamiliesExA(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
3121 ok(ret
, "EnumFontFamiliesEx error %lu\n", GetLastError());
3122 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
3123 if (*font_name
&& font_charset
== ANSI_CHARSET
)
3124 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
3127 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
3128 for (i
= 0; i
< efd
.total
; i
++)
3130 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
3132 ok(!strcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
3133 font_name
, efd
.lf
[i
].lfFaceName
);
3137 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3138 ok(symbol_charset
> 0,
3139 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3140 ok(!russian_charset
,
3141 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
3146 heap_free( efd
.lf
);
3147 heap_free( efdw
.lf
);
3150 static INT CALLBACK
enum_multi_charset_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lParam
)
3152 const NEWTEXTMETRICEXA
*ntm
= (const NEWTEXTMETRICEXA
*)tm
;
3153 LOGFONTA
*target
= (LOGFONTA
*)lParam
;
3154 const DWORD valid_bits
= 0x003f01ff;
3158 if (type
!= TRUETYPE_FONTTYPE
) return TRUE
;
3160 if (TranslateCharsetInfo(ULongToPtr(target
->lfCharSet
), &csi
, TCI_SRCCHARSET
)) {
3161 fs
= ntm
->ntmFontSig
.fsCsb
[0] & valid_bits
;
3162 if ((fs
& csi
.fs
.fsCsb
[0]) && (fs
& ~csi
.fs
.fsCsb
[0]) && (fs
& FS_LATIN1
)) {
3171 static INT CALLBACK
enum_font_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3173 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
3175 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3177 if (efd
->total
>= efd
->size
)
3179 efd
->size
= max( (efd
->total
+ 1) * 2, 256 );
3180 efd
->lf
= heap_realloc( efd
->lf
, efd
->size
* sizeof(*efd
->lf
) );
3181 if (!efd
->lf
) return 0;
3183 efd
->lf
[efd
->total
++] = *lf
;
3188 static INT CALLBACK
enum_fullname_data_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
3190 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
3192 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3194 if (efnd
->total
>= efnd
->size
)
3196 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3197 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3198 if (!efnd
->elf
) return 0;
3200 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
3205 static INT CALLBACK
enum_fullname_data_proc_w( const LOGFONTW
*lf
, const TEXTMETRICW
*ntm
, DWORD type
, LPARAM lParam
)
3207 struct enum_fullname_data_w
*efnd
= (struct enum_fullname_data_w
*)lParam
;
3209 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3211 if (efnd
->total
>= efnd
->size
)
3213 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
3214 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
3215 if (!efnd
->elf
) return 0;
3217 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTW
*)lf
;
3222 static void test_EnumFontFamiliesEx_default_charset(void)
3224 struct enum_font_data efd
;
3225 LOGFONTA target
, enum_font
;
3231 if (!TranslateCharsetInfo(ULongToPtr(acp
), &csi
, TCI_SRCCODEPAGE
)) {
3232 skip("TranslateCharsetInfo failed for code page %u.\n", acp
);
3237 memset(&enum_font
, 0, sizeof(enum_font
));
3238 enum_font
.lfCharSet
= csi
.ciCharset
;
3239 target
.lfFaceName
[0] = '\0';
3240 target
.lfCharSet
= csi
.ciCharset
;
3241 EnumFontFamiliesExA(hdc
, &enum_font
, enum_multi_charset_font_proc
, (LPARAM
)&target
, 0);
3242 if (target
.lfFaceName
[0] == '\0') {
3243 skip("suitable font isn't found for charset %d.\n", enum_font
.lfCharSet
);
3246 if (acp
== 874 || acp
== 1255 || acp
== 1256) {
3247 /* these codepage use complex script, expecting ANSI_CHARSET here. */
3248 target
.lfCharSet
= ANSI_CHARSET
;
3251 memset(&efd
, 0, sizeof(efd
));
3252 memset(&enum_font
, 0, sizeof(enum_font
));
3253 strcpy(enum_font
.lfFaceName
, target
.lfFaceName
);
3254 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
3255 EnumFontFamiliesExA(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
3259 ok(0, "EnumFontFamilies is broken. Expected >= 2, got %d.\n", efd
.total
);
3261 ok(efd
.lf
[0].lfCharSet
== target
.lfCharSet
,
3262 "(%s) got charset %d expected %d\n",
3263 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, target
.lfCharSet
);
3269 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
3271 HFONT hfont
, hfont_prev
;
3273 GLYPHMETRICS gm1
, gm2
;
3277 /* negative widths are handled just as positive ones */
3278 lf2
.lfWidth
= -lf
->lfWidth
;
3280 SetLastError(0xdeadbeef);
3281 hfont
= CreateFontIndirectA(lf
);
3282 ok(hfont
!= 0, "CreateFontIndirect error %lu\n", GetLastError());
3283 check_font("original", lf
, hfont
);
3285 hfont_prev
= SelectObject(hdc
, hfont
);
3287 ret
= GetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
3288 if (ret
== GDI_ERROR
|| idx
== 0xffff)
3290 SelectObject(hdc
, hfont_prev
);
3291 DeleteObject(hfont
);
3292 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
3296 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
3297 memset(&gm1
, 0xab, sizeof(gm1
));
3298 SetLastError(0xdeadbeef);
3299 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
3300 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%lx\n", GetLastError());
3302 SelectObject(hdc
, hfont_prev
);
3303 DeleteObject(hfont
);
3305 SetLastError(0xdeadbeef);
3306 hfont
= CreateFontIndirectA(&lf2
);
3307 ok(hfont
!= 0, "CreateFontIndirect error %lu\n", GetLastError());
3308 check_font("negative width", &lf2
, hfont
);
3310 hfont_prev
= SelectObject(hdc
, hfont
);
3312 memset(&gm2
, 0xbb, sizeof(gm2
));
3313 SetLastError(0xdeadbeef);
3314 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3315 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%lx\n", GetLastError());
3317 SelectObject(hdc
, hfont_prev
);
3318 DeleteObject(hfont
);
3320 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
3321 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
3322 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
3323 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
3324 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
3325 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
3326 "gm1=%d,%d,%ld,%ld,%d,%d gm2=%d,%d,%ld,%ld,%d,%d\n",
3327 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
3328 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
3329 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
3330 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
3333 /* PANOSE is 10 bytes in size, need to pack the structure properly */
3334 #include "pshpack2.h"
3338 SHORT xAvgCharWidth
;
3339 USHORT usWeightClass
;
3340 USHORT usWidthClass
;
3342 SHORT ySubscriptXSize
;
3343 SHORT ySubscriptYSize
;
3344 SHORT ySubscriptXOffset
;
3345 SHORT ySubscriptYOffset
;
3346 SHORT ySuperscriptXSize
;
3347 SHORT ySuperscriptYSize
;
3348 SHORT ySuperscriptXOffset
;
3349 SHORT ySuperscriptYOffset
;
3350 SHORT yStrikeoutSize
;
3351 SHORT yStrikeoutPosition
;
3354 ULONG ulUnicodeRange1
;
3355 ULONG ulUnicodeRange2
;
3356 ULONG ulUnicodeRange3
;
3357 ULONG ulUnicodeRange4
;
3360 USHORT usFirstCharIndex
;
3361 USHORT usLastCharIndex
;
3362 /* According to the Apple spec, original version didn't have the below fields,
3363 * version numbers were taken from the OpenType spec.
3365 /* version 0 (TrueType 1.5) */
3366 USHORT sTypoAscender
;
3367 USHORT sTypoDescender
;
3368 USHORT sTypoLineGap
;
3370 USHORT usWinDescent
;
3371 /* version 1 (TrueType 1.66) */
3372 ULONG ulCodePageRange1
;
3373 ULONG ulCodePageRange2
;
3374 /* version 2 (OpenType 1.2) */
3377 USHORT usDefaultChar
;
3379 USHORT usMaxContext
;
3380 /* version 4 (OpenType 1.6) */
3381 USHORT usLowerOpticalPointSize
;
3382 USHORT usUpperOpticalPointSize
;
3384 #include "poppack.h"
3386 #define TT_OS2_V0_SIZE (FIELD_OFFSET(TT_OS2_V4, ulCodePageRange1))
3399 } cmap_encoding_record
;
3407 BYTE glyph_ids
[256];
3417 USHORT search_range
;
3418 USHORT entry_selector
;
3421 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
3424 USHORT start_count[seg_countx2 / 2];
3425 USHORT id_delta[seg_countx2 / 2];
3426 USHORT id_range_offset[seg_countx2 / 2];
3436 USHORT id_range_offset
;
3437 } cmap_format_4_seg
;
3439 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V4
*os2
, WORD family
, const char *name
)
3441 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
3442 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
3443 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
3444 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
3445 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
3448 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
3451 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
3455 for(i
= 0; i
< 256; i
++)
3457 if(cmap
->glyph_ids
[i
] == 0) continue;
3459 if(*first
== 256) *first
= i
;
3461 if(*first
== 256) return FALSE
;
3465 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
3467 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3468 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
3469 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
3470 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
3471 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
3474 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
3477 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
3478 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
3482 for(i
= 0; i
< seg_count
; i
++)
3484 cmap_format_4_seg seg
;
3486 get_seg4(cmap
, i
, &seg
);
3488 if(seg
.start_count
> 0xfffe) break;
3490 if(*first
== 0x10000) *first
= seg
.start_count
;
3492 *last
= min(seg
.end_count
, 0xfffe);
3495 if(*first
== 0x10000) return FALSE
;
3499 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
3502 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
3504 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
3506 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
3507 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
3520 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
3523 cmap_header
*header
;
3528 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
3529 ok(size
!= GDI_ERROR
, "no cmap table found\n");
3530 if(size
== GDI_ERROR
) return FALSE
;
3532 header
= HeapAlloc(GetProcessHeap(), 0, size
);
3533 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
3534 ok(ret
== size
, "GetFontData should return %lu not %lu\n", size
, ret
);
3535 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
3537 cmap
= get_cmap(header
, 3, 1);
3539 *cmap_type
= cmap_ms_unicode
;
3542 cmap
= get_cmap(header
, 3, 0);
3543 if(cmap
) *cmap_type
= cmap_ms_symbol
;
3547 *cmap_type
= cmap_none
;
3551 format
= GET_BE_WORD(*(WORD
*)cmap
);
3555 r
= get_first_last_from_cmap0(cmap
, first
, last
);
3558 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
3561 skip("unhandled cmap format %d\n", format
);
3566 HeapFree(GetProcessHeap(), 0, header
);
3570 #define TT_PLATFORM_APPLE_UNICODE 0
3571 #define TT_PLATFORM_MACINTOSH 1
3572 #define TT_PLATFORM_MICROSOFT 3
3573 #define TT_APPLE_ID_DEFAULT 0
3574 #define TT_APPLE_ID_ISO_10646 2
3575 #define TT_APPLE_ID_UNICODE_2_0 3
3576 #define TT_MS_ID_SYMBOL_CS 0
3577 #define TT_MS_ID_UNICODE_CS 1
3578 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
3579 #define TT_NAME_ID_FONT_FAMILY 1
3580 #define TT_NAME_ID_FONT_SUBFAMILY 2
3581 #define TT_NAME_ID_UNIQUE_ID 3
3582 #define TT_NAME_ID_FULL_NAME 4
3583 #define TT_MAC_ID_SIMPLIFIED_CHINESE 25
3585 typedef struct sfnt_name
3595 static const LANGID mac_langid_table
[] =
3597 MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ENGLISH */
3598 MAKELANGID(LANG_FRENCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FRENCH */
3599 MAKELANGID(LANG_GERMAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GERMAN */
3600 MAKELANGID(LANG_ITALIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ITALIAN */
3601 MAKELANGID(LANG_DUTCH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DUTCH */
3602 MAKELANGID(LANG_SWEDISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWEDISH */
3603 MAKELANGID(LANG_SPANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SPANISH */
3604 MAKELANGID(LANG_DANISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_DANISH */
3605 MAKELANGID(LANG_PORTUGUESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PORTUGUESE */
3606 MAKELANGID(LANG_NORWEGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NORWEGIAN */
3607 MAKELANGID(LANG_HEBREW
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HEBREW */
3608 MAKELANGID(LANG_JAPANESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_JAPANESE */
3609 MAKELANGID(LANG_ARABIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARABIC */
3610 MAKELANGID(LANG_FINNISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FINNISH */
3611 MAKELANGID(LANG_GREEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREEK */
3612 MAKELANGID(LANG_ICELANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ICELANDIC */
3613 MAKELANGID(LANG_MALTESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALTESE */
3614 MAKELANGID(LANG_TURKISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKISH */
3615 MAKELANGID(LANG_CROATIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CROATIAN */
3616 MAKELANGID(LANG_CHINESE_TRADITIONAL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_TRADITIONAL */
3617 MAKELANGID(LANG_URDU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_URDU */
3618 MAKELANGID(LANG_HINDI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HINDI */
3619 MAKELANGID(LANG_THAI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_THAI */
3620 MAKELANGID(LANG_KOREAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KOREAN */
3621 MAKELANGID(LANG_LITHUANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LITHUANIAN */
3622 MAKELANGID(LANG_POLISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_POLISH */
3623 MAKELANGID(LANG_HUNGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_HUNGARIAN */
3624 MAKELANGID(LANG_ESTONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESTONIAN */
3625 MAKELANGID(LANG_LATVIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LETTISH */
3626 MAKELANGID(LANG_SAMI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SAAMISK */
3627 MAKELANGID(LANG_FAEROESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FAEROESE */
3628 MAKELANGID(LANG_FARSI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_FARSI */
3629 MAKELANGID(LANG_RUSSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_RUSSIAN */
3630 MAKELANGID(LANG_CHINESE_SIMPLIFIED
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CHINESE_SIMPLIFIED */
3631 MAKELANGID(LANG_DUTCH
,SUBLANG_DUTCH_BELGIAN
), /* TT_MAC_LANGID_FLEMISH */
3632 MAKELANGID(LANG_IRISH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_IRISH */
3633 MAKELANGID(LANG_ALBANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ALBANIAN */
3634 MAKELANGID(LANG_ROMANIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ROMANIAN */
3635 MAKELANGID(LANG_CZECH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CZECH */
3636 MAKELANGID(LANG_SLOVAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVAK */
3637 MAKELANGID(LANG_SLOVENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SLOVENIAN */
3638 0, /* TT_MAC_LANGID_YIDDISH */
3639 MAKELANGID(LANG_SERBIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SERBIAN */
3640 MAKELANGID(LANG_MACEDONIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MACEDONIAN */
3641 MAKELANGID(LANG_BULGARIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BULGARIAN */
3642 MAKELANGID(LANG_UKRAINIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UKRAINIAN */
3643 MAKELANGID(LANG_BELARUSIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BYELORUSSIAN */
3644 MAKELANGID(LANG_UZBEK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UZBEK */
3645 MAKELANGID(LANG_KAZAK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KAZAKH */
3646 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_CYRILLIC
), /* TT_MAC_LANGID_AZERBAIJANI */
3647 0, /* TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT */
3648 MAKELANGID(LANG_ARMENIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ARMENIAN */
3649 MAKELANGID(LANG_GEORGIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GEORGIAN */
3650 0, /* TT_MAC_LANGID_MOLDAVIAN */
3651 MAKELANGID(LANG_KYRGYZ
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KIRGHIZ */
3652 MAKELANGID(LANG_TAJIK
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAJIKI */
3653 MAKELANGID(LANG_TURKMEN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TURKMEN */
3654 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MONGOLIAN */
3655 MAKELANGID(LANG_MONGOLIAN
,SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA
), /* TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT */
3656 MAKELANGID(LANG_PASHTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PASHTO */
3657 0, /* TT_MAC_LANGID_KURDISH */
3658 MAKELANGID(LANG_KASHMIRI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KASHMIRI */
3659 MAKELANGID(LANG_SINDHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINDHI */
3660 MAKELANGID(LANG_TIBETAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIBETAN */
3661 MAKELANGID(LANG_NEPALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_NEPALI */
3662 MAKELANGID(LANG_SANSKRIT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SANSKRIT */
3663 MAKELANGID(LANG_MARATHI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MARATHI */
3664 MAKELANGID(LANG_BENGALI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BENGALI */
3665 MAKELANGID(LANG_ASSAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ASSAMESE */
3666 MAKELANGID(LANG_GUJARATI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GUJARATI */
3667 MAKELANGID(LANG_PUNJABI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_PUNJABI */
3668 MAKELANGID(LANG_ORIYA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ORIYA */
3669 MAKELANGID(LANG_MALAYALAM
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAYALAM */
3670 MAKELANGID(LANG_KANNADA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KANNADA */
3671 MAKELANGID(LANG_TAMIL
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TAMIL */
3672 MAKELANGID(LANG_TELUGU
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TELUGU */
3673 MAKELANGID(LANG_SINHALESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SINHALESE */
3674 0, /* TT_MAC_LANGID_BURMESE */
3675 MAKELANGID(LANG_KHMER
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_KHMER */
3676 MAKELANGID(LANG_LAO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_LAO */
3677 MAKELANGID(LANG_VIETNAMESE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_VIETNAMESE */
3678 MAKELANGID(LANG_INDONESIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INDONESIAN */
3679 0, /* TT_MAC_LANGID_TAGALOG */
3680 MAKELANGID(LANG_MALAY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAY_ROMAN_SCRIPT */
3681 0, /* TT_MAC_LANGID_MALAY_ARABIC_SCRIPT */
3682 MAKELANGID(LANG_AMHARIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AMHARIC */
3683 MAKELANGID(LANG_TIGRIGNA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TIGRINYA */
3684 0, /* TT_MAC_LANGID_GALLA */
3685 0, /* TT_MAC_LANGID_SOMALI */
3686 MAKELANGID(LANG_SWAHILI
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SWAHILI */
3687 0, /* TT_MAC_LANGID_RUANDA */
3688 0, /* TT_MAC_LANGID_RUNDI */
3689 0, /* TT_MAC_LANGID_CHEWA */
3690 MAKELANGID(LANG_MALAGASY
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MALAGASY */
3691 MAKELANGID(LANG_ESPERANTO
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_ESPERANTO */
3692 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 95-111 */
3693 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 112-127 */
3694 MAKELANGID(LANG_WELSH
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_WELSH */
3695 MAKELANGID(LANG_BASQUE
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BASQUE */
3696 MAKELANGID(LANG_CATALAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_CATALAN */
3697 0, /* TT_MAC_LANGID_LATIN */
3698 MAKELANGID(LANG_QUECHUA
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_QUECHUA */
3699 0, /* TT_MAC_LANGID_GUARANI */
3700 0, /* TT_MAC_LANGID_AYMARA */
3701 MAKELANGID(LANG_TATAR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_TATAR */
3702 MAKELANGID(LANG_UIGHUR
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_UIGHUR */
3703 0, /* TT_MAC_LANGID_DZONGKHA */
3704 0, /* TT_MAC_LANGID_JAVANESE */
3705 0, /* TT_MAC_LANGID_SUNDANESE */
3706 MAKELANGID(LANG_GALICIAN
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GALICIAN */
3707 MAKELANGID(LANG_AFRIKAANS
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_AFRIKAANS */
3708 MAKELANGID(LANG_BRETON
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_BRETON */
3709 MAKELANGID(LANG_INUKTITUT
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_INUKTITUT */
3710 MAKELANGID(LANG_SCOTTISH_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_SCOTTISH_GAELIC */
3711 MAKELANGID(LANG_MANX_GAELIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_MANX_GAELIC */
3712 MAKELANGID(LANG_IRISH
,SUBLANG_IRISH_IRELAND
), /* TT_MAC_LANGID_IRISH_GAELIC */
3713 0, /* TT_MAC_LANGID_TONGAN */
3714 0, /* TT_MAC_LANGID_GREEK_POLYTONIC */
3715 MAKELANGID(LANG_GREENLANDIC
,SUBLANG_DEFAULT
), /* TT_MAC_LANGID_GREELANDIC */
3716 MAKELANGID(LANG_AZERI
,SUBLANG_AZERI_LATIN
), /* TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT */
3719 static inline WORD
get_mac_code_page( const sfnt_name
*name
)
3721 if (GET_BE_WORD(name
->encoding_id
) == TT_MAC_ID_SIMPLIFIED_CHINESE
) return 10008; /* special case */
3722 return 10000 + GET_BE_WORD(name
->encoding_id
);
3725 static int match_name_table_language( const sfnt_name
*name
, LANGID lang
)
3730 switch (GET_BE_WORD(name
->platform_id
))
3732 case TT_PLATFORM_MICROSOFT
:
3733 res
+= 5; /* prefer the Microsoft name */
3734 switch (GET_BE_WORD(name
->encoding_id
))
3736 case TT_MS_ID_UNICODE_CS
:
3737 case TT_MS_ID_SYMBOL_CS
:
3738 name_lang
= GET_BE_WORD(name
->language_id
);
3744 case TT_PLATFORM_MACINTOSH
:
3745 if (!IsValidCodePage( get_mac_code_page( name
))) return 0;
3746 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3747 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3749 case TT_PLATFORM_APPLE_UNICODE
:
3750 res
+= 2; /* prefer Unicode encodings */
3751 switch (GET_BE_WORD(name
->encoding_id
))
3753 case TT_APPLE_ID_DEFAULT
:
3754 case TT_APPLE_ID_ISO_10646
:
3755 case TT_APPLE_ID_UNICODE_2_0
:
3756 if (GET_BE_WORD(name
->language_id
) >= ARRAY_SIZE(mac_langid_table
)) return 0;
3757 name_lang
= mac_langid_table
[GET_BE_WORD(name
->language_id
)];
3766 if (name_lang
== lang
) res
+= 30;
3767 else if (PRIMARYLANGID( name_lang
) == PRIMARYLANGID( lang
)) res
+= 20;
3768 else if (name_lang
== MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
)) res
+= 10;
3772 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
3774 struct sfnt_name_header
3777 USHORT number_of_record
;
3778 USHORT storage_offset
;
3782 LONG size
, offset
, length
;
3787 int res
, best_lang
= 0, best_index
= -1;
3789 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
3790 ok(size
!= GDI_ERROR
, "no name table found\n");
3791 if(size
== GDI_ERROR
) return FALSE
;
3793 data
= HeapAlloc(GetProcessHeap(), 0, size
);
3794 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
3795 ok(ret
== size
, "GetFontData should return %lu not %lu\n", size
, ret
);
3797 header
= (void *)data
;
3798 header
->format
= GET_BE_WORD(header
->format
);
3799 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
3800 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3801 if (header
->format
!= 0)
3803 skip("got format %u\n", header
->format
);
3806 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3808 skip("number records out of range: %d\n", header
->number_of_record
);
3811 if (header
->storage_offset
>= size
)
3813 skip("storage_offset %u > size %lu\n", header
->storage_offset
, size
);
3817 entry
= (void *)&header
[1];
3818 for (i
= 0; i
< header
->number_of_record
; i
++)
3820 if (GET_BE_WORD(entry
[i
].name_id
) != name_id
) continue;
3821 res
= match_name_table_language( &entry
[i
], language_id
);
3822 if (res
> best_lang
)
3829 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[best_index
].offset
);
3830 length
= GET_BE_WORD(entry
[best_index
].length
);
3831 if (offset
+ length
> size
)
3833 skip("entry %d is out of range\n", best_index
);
3836 if (length
>= out_size
)
3838 skip("buffer too small for entry %d\n", best_index
);
3842 name
= (WCHAR
*)(data
+ offset
);
3843 for (c
= 0; c
< length
/ 2; c
++)
3844 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3850 HeapFree(GetProcessHeap(), 0, data
);
3854 static void test_text_metrics(const LOGFONTA
*lf
, const NEWTEXTMETRICA
*ntm
)
3857 HFONT hfont
, hfont_old
;
3861 const char *font_name
= lf
->lfFaceName
;
3862 DWORD cmap_first
= 0, cmap_last
= 0;
3863 UINT ascent
, descent
, cell_height
;
3864 cmap_type cmap_type
;
3865 BOOL sys_lang_non_english
;
3867 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3870 SetLastError(0xdeadbeef);
3871 hfont
= CreateFontIndirectA(lf
);
3872 ok(hfont
!= 0, "CreateFontIndirect error %lu\n", GetLastError());
3874 hfont_old
= SelectObject(hdc
, hfont
);
3876 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3877 if (size
== GDI_ERROR
)
3879 trace("OS/2 chunk was not found\n");
3882 if (size
> sizeof(tt_os2
))
3884 trace("got too large OS/2 chunk of size %lu\n", size
);
3885 size
= sizeof(tt_os2
);
3888 memset(&tt_os2
, 0, sizeof(tt_os2
));
3889 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3890 ok(ret
>= TT_OS2_V0_SIZE
&& ret
<= size
, "GetFontData should return size from [%lu,%lu] not %lu\n", TT_OS2_V0_SIZE
,
3893 SetLastError(0xdeadbeef);
3894 ret
= GetTextMetricsA(hdc
, &tmA
);
3895 ok(ret
, "GetTextMetricsA error %lu\n", GetLastError());
3897 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3899 skip("%s is not a Windows font, OS/2 metrics may be invalid.\n",font_name
);
3903 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3904 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3905 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3909 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3910 descent
= abs((SHORT
)GET_BE_WORD(tt_os2
.usWinDescent
));
3911 cell_height
= ascent
+ descent
;
3912 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3913 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3915 /* NEWTEXTMETRIC's scaling method is different from TEXTMETRIC's */
3916 #define SCALE_NTM(value) (MulDiv(ntm->tmHeight, (value), cell_height))
3917 size
= MulDiv(32, ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
3918 ok(ntm
->tmHeight
== size
, "%s: ntm->tmHeight %ld != %ld (%u/%u)\n",
3919 font_name
, ntm
->tmHeight
, size
, ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
3920 size
= SCALE_NTM(ntm
->ntmAvgWidth
);
3921 ok(ntm
->tmAveCharWidth
== size
, "%s: ntm->tmAveCharWidth %ld != %ld (%u/%u,%ld)\n",
3922 font_name
, ntm
->tmAveCharWidth
, size
, ntm
->ntmAvgWidth
, cell_height
, ntm
->tmHeight
);
3923 size
= SCALE_NTM(ascent
);
3924 ok(ntm
->tmAscent
== size
, "%s: ntm->tmAscent %ld != %ld (%u/%u,%ld)\n",
3925 font_name
, ntm
->tmAscent
, size
, ascent
, cell_height
, ntm
->tmHeight
);
3926 size
= ntm
->tmHeight
- ntm
->tmAscent
;
3927 ok(ntm
->tmDescent
== size
, "%s: ntm->tmDescent %ld != %ld (%u/%u,%ld)\n",
3928 font_name
, ntm
->tmDescent
, size
, descent
, cell_height
, ntm
->tmHeight
);
3929 size
= SCALE_NTM(cell_height
- ntm
->ntmSizeEM
);
3930 ok(ntm
->tmInternalLeading
== size
, "%s: ntm->tmInternalLeading %ld != %ld (%u/%u,%ld)\n",
3931 font_name
, ntm
->tmInternalLeading
, size
, cell_height
- ntm
->ntmSizeEM
, cell_height
, ntm
->tmHeight
);
3934 version
= GET_BE_WORD(tt_os2
.version
);
3936 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3937 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3938 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3939 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3941 if (winetest_debug
> 1)
3942 trace("font %s charset %u: %x-%x (%lx-%lx) default %x break %x OS/2 version %u vendor %4.4s\n",
3943 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3944 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3946 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3951 case 1255: /* Hebrew */
3952 expect_last_W
= 0xf896;
3954 case 1257: /* Baltic */
3955 expect_last_W
= 0xf8fd;
3958 expect_last_W
= 0xf0ff;
3960 expect_break_W
= 0x20;
3961 expect_default_W
= expect_break_W
- 1;
3962 expect_first_A
= 0x1e;
3963 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3967 expect_first_W
= cmap_first
;
3968 expect_last_W
= cmap_last
;
3969 if(os2_first_char
<= 1)
3970 expect_break_W
= os2_first_char
+ 2;
3971 else if(os2_first_char
> 0xff)
3972 expect_break_W
= 0x20;
3974 expect_break_W
= os2_first_char
;
3975 expect_default_W
= expect_break_W
- 1;
3976 expect_first_A
= expect_default_W
- 1;
3977 expect_last_A
= min(os2_last_char
, 0xff);
3979 expect_break_A
= expect_break_W
;
3980 expect_default_A
= expect_default_W
;
3982 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3983 todo_wine_if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3984 ok(tmA
.tmFirstChar
== expect_first_A
,
3985 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3986 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3987 todo_wine_if(expect_last_A
!= 0 && expect_last_A
!= 0xff) ok(tmA
.tmLastChar
== expect_last_A
,
3988 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3990 skip("tmLastChar is DBCS lead byte\n");
3991 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3992 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3993 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3994 "A: tmDefaultChar for %s got %02x expected %02x\n",
3995 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3998 SetLastError(0xdeadbeef);
3999 ret
= GetTextMetricsW(hdc
, &tmW
);
4000 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
4001 "GetTextMetricsW error %lu\n", GetLastError());
4004 /* Wine uses the os2 first char */
4005 todo_wine_if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
4006 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
4007 font_name
, tmW
.tmFirstChar
, expect_first_W
);
4009 /* Wine uses the os2 last char */
4010 todo_wine_if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
4011 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
4012 font_name
, tmW
.tmLastChar
, expect_last_W
);
4013 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
4014 font_name
, tmW
.tmBreakChar
, expect_break_W
);
4015 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
4016 "W: tmDefaultChar for %s got %02x expected %02x\n",
4017 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
4019 /* Test the aspect ratio while we have tmW */
4020 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
4021 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %lu != %lu\n",
4022 tmW
.tmDigitizedAspectX
, ret
);
4023 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
4024 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %lu != %lu\n",
4025 tmW
.tmDigitizedAspectX
, ret
);
4029 /* test FF_ values */
4030 switch(tt_os2
.panose
.bFamilyType
)
4034 case PAN_FAMILY_TEXT_DISPLAY
:
4035 case PAN_FAMILY_PICTORIAL
:
4037 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
4038 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
4040 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
4043 switch(tt_os2
.panose
.bSerifStyle
)
4048 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
4051 case PAN_SERIF_COVE
:
4052 case PAN_SERIF_OBTUSE_COVE
:
4053 case PAN_SERIF_SQUARE_COVE
:
4054 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
4055 case PAN_SERIF_SQUARE
:
4056 case PAN_SERIF_THIN
:
4057 case PAN_SERIF_BONE
:
4058 case PAN_SERIF_EXAGGERATED
:
4059 case PAN_SERIF_TRIANGLE
:
4060 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
4063 case PAN_SERIF_NORMAL_SANS
:
4064 case PAN_SERIF_OBTUSE_SANS
:
4065 case PAN_SERIF_PERP_SANS
:
4066 case PAN_SERIF_FLARED
:
4067 case PAN_SERIF_ROUNDED
:
4068 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
4073 case PAN_FAMILY_SCRIPT
:
4074 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
4077 case PAN_FAMILY_DECORATIVE
:
4078 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
4082 test_negative_width(hdc
, lf
);
4085 SelectObject(hdc
, hfont_old
);
4086 DeleteObject(hfont
);
4091 static INT CALLBACK
enum_truetype_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
4093 INT
*enumed
= (INT
*)lParam
;
4095 if (type
== TRUETYPE_FONTTYPE
)
4098 test_text_metrics(lf
, (const NEWTEXTMETRICA
*)ntm
);
4103 static void test_GetTextMetrics(void)
4114 memset(&lf
, 0, sizeof(lf
));
4115 lf
.lfCharSet
= DEFAULT_CHARSET
;
4117 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
4119 /* Test a bug triggered by rounding up FreeType ppem */
4120 hf
= CreateFontA(20, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
, DEFAULT_CHARSET
,
4121 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, DEFAULT_PITCH
,
4123 ok(hf
!= NULL
, "CreateFontA failed, error %lu\n", GetLastError());
4124 old_hf
= SelectObject(hdc
, hf
);
4125 ret
= GetTextMetricsA(hdc
, &tm
);
4126 ok(ret
, "GetTextMetricsA failed, error %lu\n", GetLastError());
4127 ok(tm
.tmHeight
<= 20, "Got unexpected tmHeight %ld\n", tm
.tmHeight
);
4128 SelectObject(hdc
, old_hf
);
4134 static void test_nonexistent_font(void)
4142 { "Times New Roman Baltic", 186 },
4143 { "Times New Roman CE", 238 },
4144 { "Times New Roman CYR", 204 },
4145 { "Times New Roman Greek", 161 },
4146 { "Times New Roman TUR", 162 }
4154 { "MS Shell Dlg", 186 },
4155 { "MS Shell Dlg", 238 },
4156 { "MS Shell Dlg", 204 },
4157 { "MS Shell Dlg", 161 },
4158 { "MS Shell Dlg", 162 }
4164 INT cs
, expected_cs
, i
, ret
;
4165 char buf
[LF_FACESIZE
];
4167 expected_cs
= GetACP();
4168 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
4170 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
4173 expected_cs
= csi
.ciCharset
;
4174 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
4176 hdc
= CreateCompatibleDC(0);
4178 for (i
= 0; i
< ARRAY_SIZE(shell_subst
); i
++)
4180 ret
= is_font_installed(shell_subst
[i
].name
);
4181 ok(ret
, "%s should be enumerated\n", shell_subst
[i
].name
);
4182 ret
= is_truetype_font_installed(shell_subst
[i
].name
);
4183 ok(ret
, "%s should be enumerated\n", shell_subst
[i
].name
);
4185 memset(&lf
, 0, sizeof(lf
));
4187 lf
.lfWeight
= FW_REGULAR
;
4188 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4189 hfont
= CreateFontIndirectA(&lf
);
4190 hfont
= SelectObject(hdc
, hfont
);
4191 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4192 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4193 cs
= GetTextCharset(hdc
);
4194 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, shell_subst
[i
].name
);
4196 DeleteObject(SelectObject(hdc
, hfont
));
4198 memset(&lf
, 0, sizeof(lf
));
4200 lf
.lfWeight
= FW_DONTCARE
;
4201 strcpy(lf
.lfFaceName
, shell_subst
[i
].name
);
4202 hfont
= CreateFontIndirectA(&lf
);
4203 hfont
= SelectObject(hdc
, hfont
);
4204 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4205 ok(!lstrcmpiA(buf
, shell_subst
[i
].name
), "expected %s, got %s\n", shell_subst
[i
].name
, buf
);
4206 cs
= GetTextCharset(hdc
);
4207 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, shell_subst
[i
].name
);
4208 DeleteObject(SelectObject(hdc
, hfont
));
4211 if (!is_truetype_font_installed("Arial") ||
4212 !is_truetype_font_installed("Times New Roman"))
4215 skip("Arial or Times New Roman not installed\n");
4219 memset(&lf
, 0, sizeof(lf
));
4221 lf
.lfWeight
= FW_REGULAR
;
4222 lf
.lfCharSet
= ANSI_CHARSET
;
4223 lf
.lfPitchAndFamily
= FF_SWISS
;
4224 strcpy(lf
.lfFaceName
, "Nonexistent font");
4225 hfont
= CreateFontIndirectA(&lf
);
4226 hfont
= SelectObject(hdc
, hfont
);
4227 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4228 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
4229 cs
= GetTextCharset(hdc
);
4230 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4231 DeleteObject(SelectObject(hdc
, hfont
));
4233 memset(&lf
, 0, sizeof(lf
));
4235 lf
.lfWeight
= FW_DONTCARE
;
4236 strcpy(lf
.lfFaceName
, "Nonexistent font");
4237 hfont
= CreateFontIndirectA(&lf
);
4238 hfont
= SelectObject(hdc
, hfont
);
4239 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4240 todo_wine
/* Wine uses Arial for all substitutions */
4241 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
4242 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4244 cs
= GetTextCharset(hdc
);
4245 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
4246 DeleteObject(SelectObject(hdc
, hfont
));
4248 memset(&lf
, 0, sizeof(lf
));
4250 lf
.lfWeight
= FW_REGULAR
;
4251 strcpy(lf
.lfFaceName
, "Nonexistent font");
4252 hfont
= CreateFontIndirectA(&lf
);
4253 hfont
= SelectObject(hdc
, hfont
);
4254 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4255 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
4256 cs
= GetTextCharset(hdc
);
4257 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4258 DeleteObject(SelectObject(hdc
, hfont
));
4260 memset(&lf
, 0, sizeof(lf
));
4262 lf
.lfWeight
= FW_DONTCARE
;
4263 strcpy(lf
.lfFaceName
, "Times New Roman");
4264 hfont
= CreateFontIndirectA(&lf
);
4265 hfont
= SelectObject(hdc
, hfont
);
4266 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4267 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
4268 cs
= GetTextCharset(hdc
);
4269 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
4270 DeleteObject(SelectObject(hdc
, hfont
));
4272 for (i
= 0; i
< ARRAY_SIZE(font_subst
); i
++)
4274 ret
= is_font_installed(font_subst
[i
].name
);
4276 ok(ret
, "%s should be enumerated\n", font_subst
[i
].name
);
4277 ret
= is_truetype_font_installed(font_subst
[i
].name
);
4279 ok(ret
, "%s should be enumerated\n", font_subst
[i
].name
);
4281 memset(&lf
, 0, sizeof(lf
));
4283 lf
.lfWeight
= FW_REGULAR
;
4284 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4285 hfont
= CreateFontIndirectA(&lf
);
4286 hfont
= SelectObject(hdc
, hfont
);
4287 cs
= GetTextCharset(hdc
);
4288 if (font_subst
[i
].charset
== expected_cs
)
4290 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4291 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4292 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
4296 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
4297 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4298 ok(!lstrcmpiA(buf
, "Arial"), "got %s for font %s\n", buf
, font_subst
[i
].name
);
4300 DeleteObject(SelectObject(hdc
, hfont
));
4302 memset(&lf
, 0, sizeof(lf
));
4304 lf
.lfWeight
= FW_DONTCARE
;
4305 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
4306 hfont
= CreateFontIndirectA(&lf
);
4307 hfont
= SelectObject(hdc
, hfont
);
4308 GetTextFaceA(hdc
, sizeof(buf
), buf
);
4309 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
4310 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
4311 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
4312 "got %s for font %s\n", buf
, font_subst
[i
].name
);
4313 cs
= GetTextCharset(hdc
);
4314 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
4315 DeleteObject(SelectObject(hdc
, hfont
));
4321 struct font_realization_info
4336 WCHAR path
[MAX_PATH
];
4339 static void test_RealizationInfo(void)
4341 struct realization_info_t
4348 struct file_info file_info
;
4350 DWORD info
[4], info2
[32], read
;
4351 HFONT hfont
, hfont_old
;
4355 BYTE file
[16], data
[14];
4360 if(!pGdiRealizationInfo
)
4362 win_skip("GdiRealizationInfo not available\n");
4368 memset(info
, 0xcc, sizeof(info
));
4369 r
= pGdiRealizationInfo(hdc
, info
);
4370 ok(r
!= 0, "ret 0\n");
4371 ok((info
[0] & 0xf) == 1, "info[0] = %lx for the system font\n", info
[0]);
4372 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4374 if (!is_truetype_font_installed("Tahoma"))
4376 skip("skipping GdiRealizationInfo with truetype font\n");
4380 memset(&lf
, 0, sizeof(lf
));
4381 strcpy(lf
.lfFaceName
, "Tahoma");
4383 lf
.lfWeight
= FW_BOLD
;
4385 hfont
= CreateFontIndirectA(&lf
);
4386 hfont_old
= SelectObject(hdc
, hfont
);
4388 memset(info
, 0xcc, sizeof(info
));
4389 r
= pGdiRealizationInfo(hdc
, info
);
4390 ok(r
!= 0, "ret 0\n");
4391 ok((info
[0] & 0xf) == 3, "info[0] = %lx for arial\n", info
[0]);
4392 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
4394 if (pGetFontRealizationInfo
)
4396 struct font_realization_info
*fri
= (struct font_realization_info
*)info2
;
4397 struct realization_info_t
*ri
= (struct realization_info_t
*)info
;
4399 /* The first DWORD represents a struct size. On a
4400 newly rebooted system setting this to < 16 results
4401 in GetFontRealizationInfo failing. However there
4402 appears to be some caching going on which results
4403 in calls after a successful call also succeeding even
4404 if the size < 16. This means we can't reliably test
4407 memset(info2
, 0xcc, sizeof(info2
));
4409 r
= pGetFontRealizationInfo(hdc
, info2
);
4410 ok(r
!= 0, "ret 0\n");
4411 /* We may get the '24' version here if that has been previously
4413 ok(fri
->size
== 16 || fri
->size
== 24, "got %ld\n", info2
[0]);
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(info2
[6] == 0xcccccccc, "got wrong dword 6, 0x%08lx\n", info2
[6]);
4419 memset(info2
, 0xcc, sizeof(info2
));
4421 r
= pGetFontRealizationInfo(hdc
, info2
);
4422 ok(r
== FALSE
, "got %d\n", r
);
4424 memset(info2
, 0xcc, sizeof(info2
));
4426 r
= pGetFontRealizationInfo(hdc
, info2
);
4427 ok(r
!= 0, "ret 0\n");
4428 ok(fri
->size
== 24, "got %ld\n", fri
->size
);
4429 ok(fri
->flags
== ri
->flags
, "flags mismatch\n");
4430 ok(fri
->cache_num
== ri
->cache_num
, "cache_num mismatch\n");
4431 ok(fri
->instance_id
== ri
->instance_id
, "instance id mismatch\n");
4432 ok(fri
->simulations
== 0x2, "got simulations flags 0x%04x\n", fri
->simulations
);
4433 ok(fri
->face_index
== 0, "got wrong face index %u\n", fri
->face_index
);
4434 ok(info2
[6] == 0xcccccccc, "structure longer than 6 dwords\n");
4436 /* Test GetFontFileInfo() */
4437 /* invalid font id */
4438 SetLastError(0xdeadbeef);
4439 r
= pGetFontFileInfo(0xabababab, 0, &file_info
, sizeof(file_info
), &needed
);
4440 ok(r
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "ret %d gle %ld\n", r
, GetLastError());
4443 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, sizeof(file_info
), &needed
);
4444 ok(r
!= 0, "Failed to get font file info, error %ld.\n", GetLastError());
4448 ok(needed
> 0 && needed
< sizeof(file_info
), "Unexpected required size.\n");
4450 h
= CreateFileW(file_info
.path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
4451 ok(h
!= INVALID_HANDLE_VALUE
, "Unable to open file %ld\n", GetLastError());
4453 GetFileTime(h
, NULL
, NULL
, &time
);
4454 ok(!CompareFileTime(&file_info
.time
, &time
), "time mismatch\n");
4455 GetFileSizeEx(h
, &size
);
4456 ok(file_info
.size
.QuadPart
== size
.QuadPart
, "size mismatch\n");
4458 /* Read first 16 bytes from the file */
4459 ReadFile(h
, file
, sizeof(file
), &read
, NULL
);
4462 /* shorter buffer */
4463 SetLastError(0xdeadbeef);
4464 r
= pGetFontFileInfo(fri
->instance_id
, 0, &file_info
, needed
- 1, &needed
);
4465 ok(r
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "ret %d gle %ld\n", r
, GetLastError());
4468 /* Get bytes 2 - 16 using GetFontFileData */
4469 r
= pGetFontFileData(fri
->instance_id
, 0, 2, data
, sizeof(data
));
4470 ok(r
!= 0, "ret 0 gle %ld\n", GetLastError());
4472 ok(!memcmp(data
, file
+ 2, sizeof(data
)), "mismatch\n");
4475 DeleteObject(SelectObject(hdc
, hfont_old
));
4481 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
4482 the nul in the count of characters copied when the face name buffer is not
4483 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
4484 always includes it. */
4485 static void test_GetTextFace(void)
4487 static const char faceA
[] = "Tahoma";
4488 static const WCHAR faceW
[] = L
"Tahoma";
4491 char bufA
[LF_FACESIZE
];
4492 WCHAR bufW
[LF_FACESIZE
];
4497 if(!is_font_installed("Tahoma"))
4499 skip("Tahoma is not installed so skipping this test\n");
4504 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
4505 f
= CreateFontIndirectA(&fA
);
4506 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
4509 g
= SelectObject(dc
, f
);
4510 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
4511 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
4512 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
4514 /* Play with the count arg. */
4516 n
= GetTextFaceA(dc
, 0, bufA
);
4517 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4518 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4521 n
= GetTextFaceA(dc
, 1, bufA
);
4522 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
4523 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
4525 bufA
[0] = 'x'; bufA
[1] = 'y';
4526 n
= GetTextFaceA(dc
, 2, bufA
);
4527 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
4528 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
4530 n
= GetTextFaceA(dc
, 0, NULL
);
4531 ok(n
== sizeof faceA
, "GetTextFaceA returned %d\n", n
);
4533 DeleteObject(SelectObject(dc
, g
));
4534 ReleaseDC(NULL
, dc
);
4537 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
4538 SetLastError(0xdeadbeef);
4539 f
= CreateFontIndirectW(&fW
);
4540 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
4542 win_skip("CreateFontIndirectW is not implemented\n");
4545 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
4548 g
= SelectObject(dc
, f
);
4549 n
= GetTextFaceW(dc
, ARRAY_SIZE(bufW
), bufW
);
4550 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4551 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
4553 /* Play with the count arg. */
4555 n
= GetTextFaceW(dc
, 0, bufW
);
4556 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
4557 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4560 n
= GetTextFaceW(dc
, 1, bufW
);
4561 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
4562 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
4564 bufW
[0] = 'x'; bufW
[1] = 'y';
4565 n
= GetTextFaceW(dc
, 2, bufW
);
4566 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
4567 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
4569 n
= GetTextFaceW(dc
, 0, NULL
);
4570 ok(n
== ARRAY_SIZE(faceW
), "GetTextFaceW returned %d\n", n
);
4572 DeleteObject(SelectObject(dc
, g
));
4573 ReleaseDC(NULL
, dc
);
4576 static void test_orientation(void)
4578 static const char test_str
[11] = "Test String";
4581 HFONT hfont
, old_hfont
;
4584 if (!is_truetype_font_installed("Arial"))
4586 skip("Arial is not installed\n");
4590 hdc
= CreateCompatibleDC(0);
4591 memset(&lf
, 0, sizeof(lf
));
4592 lstrcpyA(lf
.lfFaceName
, "Arial");
4594 lf
.lfOrientation
= lf
.lfEscapement
= 900;
4595 hfont
= create_font("orientation", &lf
);
4596 old_hfont
= SelectObject(hdc
, hfont
);
4597 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
4598 ok(near_match(311, size
.cx
), "cx should be about 311, got %ld\n", size
.cx
);
4599 ok(near_match(75, size
.cy
), "cy should be about 75, got %ld\n", size
.cy
);
4600 SelectObject(hdc
, old_hfont
);
4601 DeleteObject(hfont
);
4605 static void test_oemcharset(void)
4609 HFONT hfont
, old_hfont
;
4612 hdc
= CreateCompatibleDC(0);
4613 ZeroMemory(&lf
, sizeof(lf
));
4615 lf
.lfCharSet
= OEM_CHARSET
;
4616 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
4617 lstrcpyA(lf
.lfFaceName
, "Terminal");
4618 hfont
= CreateFontIndirectA(&lf
);
4619 old_hfont
= SelectObject(hdc
, hfont
);
4620 charset
= GetTextCharset(hdc
);
4622 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
4623 hfont
= SelectObject(hdc
, old_hfont
);
4624 GetObjectA(hfont
, sizeof(clf
), &clf
);
4625 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
4626 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
4627 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
4628 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %ld height, got %ld\n", lf
.lfHeight
, clf
.lfHeight
);
4629 DeleteObject(hfont
);
4633 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONTA
*lpelfe
,
4634 const TEXTMETRICA
*lpntme
,
4635 DWORD FontType
, LPARAM lParam
)
4637 const NEWTEXTMETRICEXA
*lpntmex
= (const NEWTEXTMETRICEXA
*)lpntme
;
4639 LOGFONTA lf
= *lpelfe
;
4643 /* skip bitmap, proportional or vertical font */
4644 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
4645 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
4646 lf
.lfFaceName
[0] == '@')
4649 /* skip linked font */
4650 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
4651 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
4654 /* skip linked font, like SimSun-ExtB */
4655 switch (lpelfe
->lfCharSet
) {
4656 case SHIFTJIS_CHARSET
:
4657 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 17); /* Hiragana */
4659 case GB2312_CHARSET
:
4660 case CHINESEBIG5_CHARSET
:
4661 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 16); /* CJK Symbols And Punctuation */
4663 case HANGEUL_CHARSET
:
4664 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[1] & (1 << 24); /* Hangul Syllables */
4667 found_subset
= lpntmex
->ntmFontSig
.fsUsb
[0] & (1 << 0); /* Basic Latin */
4673 /* test with an odd height */
4676 hfont
= CreateFontIndirectA(&lf
);
4679 *(HFONT
*)lParam
= hfont
;
4685 static void test_GetGlyphOutline(void)
4688 GLYPHMETRICS gm
, gm2
;
4690 HFONT hfont
, old_hfont
;
4692 const UINT fmt
[] = { GGO_METRICS
, GGO_BITMAP
, GGO_GRAY2_BITMAP
,
4693 GGO_GRAY4_BITMAP
, GGO_GRAY8_BITMAP
};
4701 {ANSI_CHARSET
, 0x30, 0x30},
4702 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
4703 {HANGEUL_CHARSET
, 0x8141, 0xac02},
4704 {GB2312_CHARSET
, 0x8141, 0x4e04},
4705 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
4709 if (!is_truetype_font_installed("Tahoma"))
4711 skip("Tahoma is not installed\n");
4715 hdc
= CreateCompatibleDC(0);
4716 memset(&lf
, 0, sizeof(lf
));
4718 lstrcpyA(lf
.lfFaceName
, "Tahoma");
4719 SetLastError(0xdeadbeef);
4720 hfont
= CreateFontIndirectA(&lf
);
4721 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
4722 old_hfont
= SelectObject(hdc
, hfont
);
4724 memset(&gm
, 0, sizeof(gm
));
4725 SetLastError(0xdeadbeef);
4726 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4727 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %lu\n", GetLastError());
4729 memset(&gm
, 0, sizeof(gm
));
4730 SetLastError(0xdeadbeef);
4731 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4732 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
4733 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", GetLastError());
4735 memset(&gm
, 0, sizeof(gm
));
4736 SetLastError(0xdeadbeef);
4737 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4738 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4739 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %lu\n", GetLastError());
4741 memset(&gm
, 0, sizeof(gm
));
4742 SetLastError(0xdeadbeef);
4743 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
4744 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4746 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
4747 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", GetLastError());
4750 /* test for needed buffer size request on space char */
4751 memset(&gm
, 0, sizeof(gm
));
4752 SetLastError(0xdeadbeef);
4753 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4754 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4756 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
4757 ok(gm
.gmBlackBoxX
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxX
);
4758 ok(gm
.gmBlackBoxY
== 1, "Expected 1, got %u\n", gm
.gmBlackBoxY
);
4761 /* requesting buffer size for space char + error */
4762 memset(&gm
, 0, sizeof(gm
));
4763 SetLastError(0xdeadbeef);
4764 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
4765 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4767 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
4768 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %lu\n", GetLastError());
4769 ok(gm
.gmBlackBoxX
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxX
);
4770 ok(gm
.gmBlackBoxY
== 0, "Expected 0, got %u\n", gm
.gmBlackBoxY
);
4773 /* test GetGlyphOutline with a buffer too small */
4774 SetLastError(0xdeadbeef);
4775 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_NATIVE
, &gm
, sizeof(i
), &i
, &mat
);
4776 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4777 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return an error when the buffer size is too small.\n");
4779 for (i
= 0; i
< ARRAY_SIZE(fmt
); ++i
)
4783 memset(&gm
, 0xab, sizeof(gm
));
4784 SetLastError(0xdeadbeef);
4785 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, NULL
, &mat
);
4786 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4788 if (fmt
[i
] == GGO_METRICS
)
4789 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4791 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4792 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4793 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4796 memset(&gm
, 0xab, sizeof(gm
));
4797 SetLastError(0xdeadbeef);
4798 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, 0, &dummy
, &mat
);
4799 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4801 if (fmt
[i
] == GGO_METRICS
)
4802 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4804 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, got %d\n", fmt
[i
], ret
);
4805 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4806 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4809 memset(&gm
, 0xab, sizeof(gm
));
4810 SetLastError(0xdeadbeef);
4811 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), NULL
, &mat
);
4812 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4814 if (fmt
[i
] == GGO_METRICS
)
4815 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4817 ok(ret
== 0, "%2d:GetGlyphOutlineW should return 0, 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
);
4822 memset(&gm
, 0xab, sizeof(gm
));
4823 SetLastError(0xdeadbeef);
4824 ret
= GetGlyphOutlineW(hdc
, ' ', fmt
[i
], &gm
, sizeof(dummy
), &dummy
, &mat
);
4825 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
4827 if (fmt
[i
] == GGO_METRICS
) {
4828 ok(ret
!= GDI_ERROR
, "%2d:GetGlyphOutlineW should succeed, got %d\n", fmt
[i
], ret
);
4829 ok(gm
.gmBlackBoxX
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxX
);
4830 ok(gm
.gmBlackBoxY
== 1, "%2d:expected 1, got %u\n", fmt
[i
], gm
.gmBlackBoxY
);
4834 ok(ret
== GDI_ERROR
, "%2d:GetGlyphOutlineW should return GDI_ERROR, got %d\n", fmt
[i
], ret
);
4835 memset(&gm2
, 0xab, sizeof(gm2
));
4836 ok(memcmp(&gm
, &gm2
, sizeof(GLYPHMETRICS
)) == 0,
4837 "%2d:GLYPHMETRICS shouldn't be touched on error\n", fmt
[i
]);
4842 SelectObject(hdc
, old_hfont
);
4843 DeleteObject(hfont
);
4845 for (i
= 0; i
< ARRAY_SIZE(c
); ++i
)
4847 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
4850 lf
.lfFaceName
[0] = '\0';
4851 lf
.lfCharSet
= c
[i
].cs
;
4852 lf
.lfPitchAndFamily
= 0;
4853 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
4855 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
4859 old_hfont
= SelectObject(hdc
, hfont
);
4861 /* expected to ignore superfluous bytes (single-byte character) */
4862 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4863 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4864 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4866 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4867 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4868 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4870 /* expected to ignore superfluous bytes (double-byte character) */
4871 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
4872 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4873 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
4874 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
4876 /* expected to match wide-char version results */
4877 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
4878 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
4880 if (EnumFontFamiliesExA(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
4882 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
4885 DeleteObject(SelectObject(hdc
, hfont
));
4888 DeleteObject(SelectObject(hdc
, old_hfont
));
4892 ret
= GetObjectA(hfont
, sizeof lf
, &lf
);
4893 ok(ret
> 0, "GetObject error %lu\n", GetLastError());
4895 ret
= GetTextMetricsA(hdc
, &tm
);
4896 ok(ret
, "GetTextMetrics error %lu\n", GetLastError());
4897 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4898 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %lu\n", GetLastError());
4899 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4900 "expected %ld, got %d (%s:%d)\n",
4901 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4903 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
4904 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %lu\n", GetLastError());
4905 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4906 "expected %ld, got %d (%s:%d)\n",
4907 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4910 hfont
= CreateFontIndirectA(&lf
);
4911 ok(hfont
!= NULL
, "CreateFontIndirect error %lu\n", GetLastError());
4912 DeleteObject(SelectObject(hdc
, hfont
));
4913 ret
= GetTextMetricsA(hdc
, &tm
);
4914 ok(ret
, "GetTextMetrics error %lu\n", GetLastError());
4915 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4916 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %lu\n", GetLastError());
4917 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
4918 "expected %ld, got %d (%s:%d)\n",
4919 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
4921 lf
.lfItalic
= FALSE
;
4922 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
4923 hfont
= CreateFontIndirectA(&lf
);
4924 ok(hfont
!= NULL
, "CreateFontIndirect error %lu\n", GetLastError());
4925 DeleteObject(SelectObject(hdc
, hfont
));
4926 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
4927 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %lu\n", GetLastError());
4928 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
4929 "expected %ld, got %d (%s:%d)\n",
4930 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
4932 hfont
= SelectObject(hdc
, old_hfont
);
4933 DeleteObject(hfont
);
4939 /* bug #9995: there is a limit to the character width that can be specified */
4940 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
4946 int ave_width
, height
, width
, ratio
;
4948 if (!is_truetype_font_installed( fontname
)) {
4949 skip("%s is not installed\n", fontname
);
4952 hdc
= CreateCompatibleDC(0);
4953 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
4954 /* select width = 0 */
4955 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4956 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4957 DEFAULT_QUALITY
, VARIABLE_PITCH
,
4959 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
4960 of
= SelectObject( hdc
, hf
);
4961 ret
= GetTextMetricsA( hdc
, &tm
);
4962 ok(ret
, "GetTextMetricsA error %lu\n", GetLastError());
4963 height
= tm
.tmHeight
;
4964 ave_width
= tm
.tmAveCharWidth
;
4965 SelectObject( hdc
, of
);
4968 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
4970 hf
= CreateFontA(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
4971 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
4972 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
4973 ok(hf
!= 0, "CreateFont failed\n");
4974 of
= SelectObject(hdc
, hf
);
4975 ret
= GetTextMetricsA(hdc
, &tm
);
4976 ok(ret
, "GetTextMetrics error %lu\n", GetLastError());
4977 SelectObject(hdc
, of
);
4980 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
, FALSE
) || width
/ height
> 200)
4986 ratio
= width
/ height
;
4988 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
4991 static void test_GetCharacterPlacement(void)
4993 GCP_RESULTSA result
;
4999 hdc
= CreateCompatibleDC(0);
5000 ok(!!hdc
, "CreateCompatibleDC failed\n");
5002 memset(&result
, 0, sizeof(result
));
5003 result
.lStructSize
= sizeof(result
);
5004 result
.lpCaretPos
= pos
;
5005 result
.lpGlyphs
= glyphs
;
5006 result
.nGlyphs
= 20;
5010 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, &result
, 0);
5011 ok(size
, "GetCharacterPlacementA failed!\n");
5012 ok(result
.nGlyphs
== 9, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5013 ok(glyphs
[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5014 ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
5018 result
.nGlyphs
= 20;
5019 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 0, 0, &result
, 0);
5020 ok(!size2
, "Expected GetCharacterPlacementA to fail\n");
5021 ok(result
.nGlyphs
== 20, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5022 ok(glyphs
[0] == '!', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5023 ok(pos
[0] == -1, "Unexpected caret position %d\n", pos
[0]);
5025 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 0, NULL
, 0);
5026 ok(size2
, "GetCharacterPlacementA failed!\n");
5027 ok(size
== size2
, "GetCharacterPlacementA returned different result: %lu vs %lu\n", size2
, size
);
5029 size2
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, NULL
, GCP_REORDER
);
5030 ok(size2
, "GetCharacterPlacementA failed!\n");
5031 ok(size
== size2
, "GetCharacterPlacementA returned different result: %lu vs %lu\n", size2
, size
);
5035 result
.nGlyphs
= 20;
5036 size
= GetCharacterPlacementA(hdc
, "Wine Test", 9, 1024, &result
, GCP_REORDER
);
5037 ok(size
, "GetCharacterPlacementA failed!\n");
5038 ok(size
== size2
, "GetCharacterPlacementA returned different result: %lu vs %lu\n", size2
, size
);
5039 ok(result
.nGlyphs
== 9, "Unexpected number of glyphs %u\n", result
.nGlyphs
);
5040 ok(glyphs
[0] == 'W', "Unexpected first glyph %s\n", wine_dbgstr_wn(glyphs
, 1));
5041 todo_wine
ok(pos
[0] == 0, "Unexpected caret position %d\n", pos
[0]);
5046 static void test_CreateFontIndirect(void)
5048 LOGFONTA lf
, getobj_lf
;
5051 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
5053 memset(&lf
, 0, sizeof(lf
));
5054 lf
.lfCharSet
= ANSI_CHARSET
;
5055 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5058 lf
.lfQuality
= DEFAULT_QUALITY
;
5059 lf
.lfItalic
= FALSE
;
5060 lf
.lfWeight
= FW_DONTCARE
;
5062 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5064 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5065 hfont
= CreateFontIndirectA(&lf
);
5066 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5067 SetLastError(0xdeadbeef);
5068 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
5069 ok(ret
, "GetObject failed: %ld\n", GetLastError());
5070 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
5071 ok(lf
.lfWeight
== getobj_lf
.lfWeight
, "lfWeight: expect %08lx got %08lx\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
5072 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
), "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
5073 DeleteObject(hfont
);
5077 static void test_CreateFontIndirectEx(void)
5079 ENUMLOGFONTEXDVA lfex
;
5082 if (!is_truetype_font_installed("Arial"))
5084 skip("Arial is not installed\n");
5088 SetLastError(0xdeadbeef);
5089 hfont
= CreateFontIndirectExA(NULL
);
5090 ok(hfont
== NULL
, "got %p\n", hfont
);
5091 ok(GetLastError() == 0xdeadbeef, "got error %ld\n", GetLastError());
5093 memset(&lfex
, 0, sizeof(lfex
));
5094 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
5095 hfont
= CreateFontIndirectExA(&lfex
);
5096 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
5098 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
5099 DeleteObject(hfont
);
5102 static void test_realization_info(const char *name
, DWORD size
, BOOL is_memory_resource
)
5104 struct font_realization_info info
;
5105 struct file_info file_info
;
5106 HFONT hfont
, hfont_prev
;
5113 if (!pGetFontRealizationInfo
)
5116 memset(&lf
, 0, sizeof(lf
));
5118 strcpy(lf
.lfFaceName
, name
);
5120 hfont
= CreateFontIndirectA(&lf
);
5121 ok(hfont
!= 0, "Failed to create a font, %lu.\n", GetLastError());
5125 hfont_prev
= SelectObject(hdc
, hfont
);
5126 ok(hfont_prev
!= NULL
, "Failed to select font.\n");
5128 memset(&info
, 0xcc, sizeof(info
));
5129 info
.size
= sizeof(info
);
5130 ret
= pGetFontRealizationInfo(hdc
, (DWORD
*)&info
);
5131 ok(ret
!= 0, "Unexpected return value %d.\n", ret
);
5133 ok((info
.flags
& 0xf) == 0x3, "Unexpected flags %#lx.\n", info
.flags
);
5134 ok(info
.cache_num
!= 0, "Unexpected cache num %lu.\n", info
.cache_num
);
5135 ok(info
.instance_id
!= 0, "Unexpected instance id %lu.\n", info
.instance_id
);
5136 ok(info
.simulations
== 0, "Unexpected simulations %#x.\n", info
.simulations
);
5137 ok(info
.face_index
== 0, "Unexpected face index %u.\n", info
.face_index
);
5139 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, NULL
);
5140 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %ld.\n",
5141 ret
, GetLastError());
5144 ret
= pGetFontFileInfo(info
.instance_id
, 0, NULL
, 0, &needed
);
5145 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %ld.\n",
5146 ret
, GetLastError());
5148 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, 0, NULL
);
5149 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %ld.\n",
5150 ret
, GetLastError());
5152 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
- 1, NULL
);
5153 ok(ret
== 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
, "Unexpected return value %d, error %ld.\n",
5154 ret
, GetLastError());
5156 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, needed
, NULL
);
5157 ok(ret
!= 0, "Failed to get font file info, ret %d gle %ld.\n", ret
, GetLastError());
5159 memset(&file_info
, 0xcc, sizeof(file_info
));
5160 ret
= pGetFontFileInfo(info
.instance_id
, 0, &file_info
, sizeof(file_info
), NULL
);
5161 ok(ret
!= 0, "Failed to get font file info, ret %d gle %ld.\n", ret
, GetLastError());
5164 ok(is_memory_resource
? file_info
.size
.QuadPart
== size
: file_info
.size
.QuadPart
> 0, "Unexpected file size.\n");
5165 ok(is_memory_resource
? !file_info
.path
[0] : file_info
.path
[0], "Unexpected file path %s.\n",
5166 wine_dbgstr_w(file_info
.path
));
5169 size
= file_info
.size
.LowPart
;
5170 data
= HeapAlloc(GetProcessHeap(), 0, size
+ 16);
5172 memset(data
, 0xcc, size
);
5173 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
);
5174 ok(ret
!= 0, "Failed to get font file data, %ld\n", GetLastError());
5175 ok(*(DWORD
*)data
== 0x00000100, "Unexpected sfnt header version %#lx.\n", *(DWORD
*)data
);
5176 ok(*(WORD
*)(data
+ 4) == 0x0e00, "Unexpected table count %#x.\n", *(WORD
*)(data
+ 4));
5178 /* Larger than font data size. */
5179 memset(data
, 0xcc, size
);
5180 ret
= pGetFontFileData(info
.instance_id
, 0, 0, data
, size
+ 16);
5181 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %ld\n",
5182 ret
, GetLastError());
5183 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#lx.\n", *(DWORD
*)data
);
5186 memset(data
, 0xcc, size
);
5187 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
- 16);
5188 ok(ret
!= 0, "Failed to get font file data, %ld\n", GetLastError());
5189 ok(*(DWORD
*)data
== 0x1000000, "Unexpected buffer contents %#lx.\n", *(DWORD
*)data
);
5191 memset(data
, 0xcc, size
);
5192 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, size
);
5193 ok(ret
== 0 && GetLastError() == ERROR_INVALID_PARAMETER
, "Unexpected return value %d, error %ld\n",
5194 ret
, GetLastError());
5195 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#lx.\n", *(DWORD
*)data
);
5197 /* Zero buffer size. */
5198 memset(data
, 0xcc, size
);
5199 ret
= pGetFontFileData(info
.instance_id
, 0, 16, data
, 0);
5201 ok(ret
== 0 && GetLastError() == ERROR_NOACCESS
, "Unexpected return value %d, error %ld\n", ret
, GetLastError());
5202 ok(*(DWORD
*)data
== 0xcccccccc, "Unexpected buffer contents %#lx.\n", *(DWORD
*)data
);
5204 HeapFree(GetProcessHeap(), 0, data
);
5206 SelectObject(hdc
, hfont_prev
);
5207 DeleteObject(hfont
);
5208 ReleaseDC(NULL
, hdc
);
5211 static void test_AddFontMemResource(void)
5213 char ttf_name
[MAX_PATH
];
5215 DWORD font_size
, num_fonts
;
5219 SetLastError(0xdeadbeef);
5220 ret
= AddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
5221 ok(!ret
, "AddFontMemResourceEx should fail\n");
5222 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5223 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5226 SetLastError(0xdeadbeef);
5227 ret
= AddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
5228 ok(!ret
, "AddFontMemResourceEx should fail\n");
5229 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5230 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5233 SetLastError(0xdeadbeef);
5234 ret
= AddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
5235 ok(!ret
, "AddFontMemResourceEx should fail\n");
5236 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5237 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5240 SetLastError(0xdeadbeef);
5241 ret
= AddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
5242 ok(!ret
, "AddFontMemResourceEx should fail\n");
5243 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5244 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5247 /* Now with scalable font */
5248 bRet
= write_ttf_file("wine_test.ttf", ttf_name
);
5249 ok(bRet
, "Failed to create test font file.\n");
5251 font
= load_font(ttf_name
, &font_size
);
5252 ok(font
!= NULL
, "Failed to map font file.\n");
5254 bRet
= is_truetype_font_installed("wine_test");
5255 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5258 ret
= AddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5259 ok(ret
!= 0, "Failed to add resource, %ld.\n", GetLastError());
5260 ok(num_fonts
== 1, "Unexpected number of fonts %lu.\n", num_fonts
);
5262 bRet
= is_truetype_font_installed("wine_test");
5264 ok(!bRet
, "Font wine_test should not be enumerated.\n");
5266 test_realization_info("wine_test", font_size
, TRUE
);
5268 bRet
= RemoveFontMemResourceEx(ret
);
5269 ok(bRet
, "RemoveFontMemResourceEx error %ld\n", GetLastError());
5273 bRet
= DeleteFileA(ttf_name
);
5274 ok(bRet
, "Failed to delete font file, %ld.\n", GetLastError());
5276 font
= load_font("sserife.fon", &font_size
);
5279 skip("Unable to locate and load font sserife.fon\n");
5283 SetLastError(0xdeadbeef);
5284 ret
= AddFontMemResourceEx(font
, 0, NULL
, NULL
);
5285 ok(!ret
, "AddFontMemResourceEx should fail\n");
5286 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5287 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5290 SetLastError(0xdeadbeef);
5291 ret
= AddFontMemResourceEx(font
, 10, NULL
, NULL
);
5292 ok(!ret
, "AddFontMemResourceEx should fail\n");
5293 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5294 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5297 num_fonts
= 0xdeadbeef;
5298 SetLastError(0xdeadbeef);
5299 ret
= AddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
5300 ok(!ret
, "AddFontMemResourceEx should fail\n");
5301 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5302 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5304 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5306 num_fonts
= 0xdeadbeef;
5307 SetLastError(0xdeadbeef);
5308 ret
= AddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
5309 ok(!ret
, "AddFontMemResourceEx should fail\n");
5310 ok(GetLastError() == 0xdeadbeef,
5311 "Expected GetLastError() to return 0xdeadbeef, got %lu\n",
5313 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
5315 num_fonts
= 0xdeadbeef;
5316 SetLastError(0xdeadbeef);
5317 ret
= AddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
5318 ok(ret
!= 0, "AddFontMemResourceEx error %ld\n", GetLastError());
5319 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
5320 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
5324 SetLastError(0xdeadbeef);
5325 bRet
= RemoveFontMemResourceEx(ret
);
5326 ok(bRet
, "RemoveFontMemResourceEx error %ld\n", GetLastError());
5328 /* test invalid pointer to number of loaded fonts */
5329 font
= load_font("sserife.fon", &font_size
);
5330 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
5332 SetLastError(0xdeadbeef);
5333 ret
= AddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
5334 ok(!ret
, "AddFontMemResourceEx should fail\n");
5335 ok(GetLastError() == 0xdeadbeef,
5336 "Expected GetLastError() to return 0xdeadbeef, got %lu\n",
5339 SetLastError(0xdeadbeef);
5340 ret
= AddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
5341 ok(!ret
, "AddFontMemResourceEx should fail\n");
5342 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
5343 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %lu\n",
5349 static INT CALLBACK
enum_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5353 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5355 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %ld got %ld\n", ntm
->tmWeight
, elf
->lfWeight
);
5357 lf
= (LOGFONTA
*)lparam
;
5362 static INT CALLBACK
enum_all_fonts_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5367 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5369 lf
= (LOGFONTA
*)lparam
;
5370 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
5373 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %ld got %ld\n", ntm
->tmWeight
, elf
->lfWeight
);
5380 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lparam
)
5385 static void test_EnumFonts(void)
5391 if (!is_truetype_font_installed("Arial"))
5393 skip("Arial is not installed\n");
5397 /* Windows uses localized font face names, so Arial Bold won't be found */
5398 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
5400 skip("User locale is not English, skipping the test\n");
5404 hdc
= CreateCompatibleDC(0);
5406 /* check that the enumproc's retval is returned */
5407 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
5408 ok(ret
== 0xcafe, "got %08x\n", ret
);
5410 ret
= EnumFontFamiliesA(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
5411 ok(!ret
, "font Arial is not enumerated\n");
5412 ret
= strcmp(lf
.lfFaceName
, "Arial");
5413 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5414 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %ld\n", lf
.lfWeight
);
5416 strcpy(lf
.lfFaceName
, "Arial");
5417 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5418 ok(!ret
, "font Arial is not enumerated\n");
5419 ret
= strcmp(lf
.lfFaceName
, "Arial");
5420 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5421 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %ld\n", lf
.lfWeight
);
5423 ret
= EnumFontFamiliesA(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5424 ok(!ret
, "font Arial Bold is not enumerated\n");
5425 ret
= strcmp(lf
.lfFaceName
, "Arial");
5426 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5427 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %ld\n", lf
.lfWeight
);
5429 strcpy(lf
.lfFaceName
, "Arial Bold");
5430 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5431 ok(ret
, "font Arial Bold should not be enumerated\n");
5433 ret
= EnumFontFamiliesA(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
5434 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
5435 ret
= strcmp(lf
.lfFaceName
, "Arial");
5436 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
5437 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %ld\n", lf
.lfWeight
);
5439 strcpy(lf
.lfFaceName
, "Arial Bold Italic");
5440 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5441 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
5443 ret
= EnumFontFamiliesA(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
5444 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5446 strcpy(lf
.lfFaceName
, "Arial Italic Bold");
5447 ret
= EnumFontFamiliesA(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
5448 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
5453 static INT CALLBACK
enum_ms_shell_dlg_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5455 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5457 if (winetest_debug
> 2)
5458 trace("enumed font \"%s\", charset %d, height %ld, weight %ld, italic %d\n",
5459 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5461 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5462 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg") != 0) return 1;
5464 if (efnd
->total
>= efnd
->size
)
5466 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5467 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5468 if (!efnd
->elf
) return 0;
5470 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5474 static INT CALLBACK
enum_ms_shell_dlg2_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5476 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
5478 if (winetest_debug
> 2)
5479 trace("enumed font \"%s\", charset %d, height %ld, weight %ld, italic %d\n",
5480 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
5482 if (type
!= TRUETYPE_FONTTYPE
) return 1;
5483 if (strcmp(lf
->lfFaceName
, "MS Shell Dlg 2") != 0) return 1;
5485 if (efnd
->total
>= efnd
->size
)
5487 efnd
->size
= max( (efnd
->total
+ 1) * 2, 256 );
5488 efnd
->elf
= heap_realloc( efnd
->elf
, efnd
->size
* sizeof(*efnd
->elf
) );
5489 if (!efnd
->elf
) return 0;
5491 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONTA
*)lf
;
5495 static void test_EnumFonts_subst(void)
5500 struct enum_fullname_data efnd
;
5502 ret
= is_font_installed("MS Shell Dlg");
5503 ok(ret
, "MS Shell Dlg should be enumerated\n");
5504 ret
= is_truetype_font_installed("MS Shell Dlg");
5505 ok(ret
, "MS Shell Dlg should be enumerated as a TrueType font\n");
5507 ret
= is_font_installed("MS Shell Dlg 2");
5508 ok(ret
, "MS Shell Dlg 2 should be enumerated\n");
5509 ret
= is_truetype_font_installed("MS Shell Dlg 2");
5510 ok(ret
, "MS Shell Dlg 2 should be enumerated as a TrueType font\n");
5512 hdc
= CreateCompatibleDC(0);
5514 memset(&efnd
, 0, sizeof(efnd
));
5515 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5516 ok(ret
, "MS Shell Dlg should not be enumerated\n");
5517 ok(!efnd
.total
, "MS Shell Dlg should not be enumerated\n");
5519 memset(&lf
, 0, sizeof(lf
));
5520 lf
.lfCharSet
= DEFAULT_CHARSET
;
5523 strcpy(lf
.lfFaceName
, "MS Shell Dlg");
5524 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg_proc
, (LPARAM
)&efnd
, 0);
5525 ok(!ret
, "MS Shell Dlg should be enumerated\n");
5526 ok(efnd
.total
> 0, "MS Shell Dlg should be enumerated\n");
5529 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg");
5530 ok(!ret
, "expected MS Shell Dlg, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5531 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg");
5532 ok(ret
, "did not expect MS Shell Dlg\n");
5536 ret
= EnumFontFamiliesExA(hdc
, NULL
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5537 ok(ret
, "MS Shell Dlg 2 should not be enumerated\n");
5538 ok(!efnd
.total
, "MS Shell Dlg 2 should not be enumerated\n");
5541 strcpy(lf
.lfFaceName
, "MS Shell Dlg 2");
5542 ret
= EnumFontFamiliesExA(hdc
, &lf
, enum_ms_shell_dlg2_proc
, (LPARAM
)&efnd
, 0);
5543 ok(!ret
, "MS Shell Dlg 2 should be enumerated\n");
5544 ok(efnd
.total
> 0, "MS Shell Dlg 2 should be enumerated\n");
5547 ret
= strcmp((const char *)efnd
.elf
[0].elfLogFont
.lfFaceName
, "MS Shell Dlg 2");
5548 ok(!ret
, "expected MS Shell Dlg 2, got %s\n", efnd
.elf
[0].elfLogFont
.lfFaceName
);
5549 ret
= strcmp((const char *)efnd
.elf
[0].elfFullName
, "MS Shell Dlg 2");
5550 ok(ret
, "did not expect MS Shell Dlg 2\n");
5553 heap_free(efnd
.elf
);
5557 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
5559 const ENUMLOGFONTA
*elf
= (const ENUMLOGFONTA
*)lf
;
5560 const char *fullname
= (const char *)lParam
;
5562 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
5567 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
5572 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
5579 static void test_fullname(void)
5581 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
5582 WCHAR bufW
[LF_FULLFACESIZE
];
5583 char bufA
[LF_FULLFACESIZE
];
5590 hdc
= CreateCompatibleDC(0);
5591 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5593 memset(&lf
, 0, sizeof(lf
));
5594 lf
.lfCharSet
= ANSI_CHARSET
;
5595 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5598 lf
.lfQuality
= DEFAULT_QUALITY
;
5599 lf
.lfItalic
= FALSE
;
5600 lf
.lfWeight
= FW_DONTCARE
;
5602 for (i
= 0; i
< ARRAY_SIZE(TestName
); i
++)
5604 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
5606 skip("%s is not installed\n", TestName
[i
]);
5610 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
5611 hfont
= CreateFontIndirectA(&lf
);
5612 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5614 of
= SelectObject(hdc
, hfont
);
5617 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5618 ok(ret
, "face full name could not be read\n");
5619 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
5620 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
5621 SelectObject(hdc
, of
);
5622 DeleteObject(hfont
);
5627 static WCHAR
*prepend_at(WCHAR
*family
)
5632 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
5637 static void test_fullname2_helper(const char *Family
)
5639 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
5640 struct enum_fullname_data efnd
;
5647 DWORD otm_size
, ret
, buf_size
;
5648 OUTLINETEXTMETRICA
*otm
;
5649 BOOL want_vertical
, get_vertical
;
5650 want_vertical
= ( Family
[0] == '@' );
5652 hdc
= CreateCompatibleDC(0);
5653 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
5655 memset(&lf
, 0, sizeof(lf
));
5656 lf
.lfCharSet
= DEFAULT_CHARSET
;
5657 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
5660 lf
.lfQuality
= DEFAULT_QUALITY
;
5661 lf
.lfItalic
= FALSE
;
5662 lf
.lfWeight
= FW_DONTCARE
;
5663 strcpy(lf
.lfFaceName
, Family
);
5664 memset(&efnd
, 0, sizeof(efnd
));
5665 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
5666 if (efnd
.total
== 0)
5667 skip("%s is not installed\n", lf
.lfFaceName
);
5669 for (i
= 0; i
< efnd
.total
; i
++)
5671 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
5672 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
5673 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
5675 get_vertical
= ( FamilyName
[0] == '@' );
5676 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
5678 lstrcpyA(lf
.lfFaceName
, FaceName
);
5679 hfont
= CreateFontIndirectA(&lf
);
5680 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
5682 of
= SelectObject(hdc
, hfont
);
5683 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
5684 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
5685 if (buf_size
== GDI_ERROR
) continue;
5687 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5688 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
5690 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5691 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5692 memset(otm
, 0, otm_size
);
5693 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, otm
);
5694 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
5695 if (ret
== 0) continue;
5699 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5700 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5701 ok(ret
, "%s: FAMILY (family name) could not be read\n", FamilyName
);
5702 if (want_vertical
) bufW
= prepend_at(bufW
);
5703 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5704 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
5705 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
5706 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
5710 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
5711 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5712 ok(ret
, "FULL_NAME (face name) could not be read\n");
5713 if (want_vertical
) bufW
= prepend_at(bufW
);
5714 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5715 ok(!lstrcmpA(FaceName
, bufA
), "%s: font face names don't match: returned %s, expect %s\n", FamilyName
, FaceName
, bufA
);
5716 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
5717 ok(!lstrcmpA(FaceName
, otmStr
), "%s: FaceName %s doesn't match otmpFaceName %s\n", FamilyName
, FaceName
, otmStr
);
5721 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
5722 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5723 ok(ret
, "%s: SUBFAMILY (style name) could not be read\n", FamilyName
);
5724 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5725 ok(!lstrcmpA(StyleName
, bufA
), "%s: style names don't match: returned %s, expect %s\n", FamilyName
, StyleName
, bufA
);
5726 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
5727 ok(!lstrcmpA(StyleName
, otmStr
), "%s: StyleName %s doesn't match otmpStyleName %s\n", FamilyName
, StyleName
, otmStr
);
5731 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
5732 if (!ret
) ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
5733 ok(ret
, "%s: UNIQUE_ID (full name) could not be read\n", FamilyName
);
5734 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
5735 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
5736 ok(!lstrcmpA(otmStr
, bufA
), "%s: UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", FamilyName
, otmStr
, bufA
);
5738 SelectObject(hdc
, of
);
5739 DeleteObject(hfont
);
5741 HeapFree(GetProcessHeap(), 0, otm
);
5742 HeapFree(GetProcessHeap(), 0, bufW
);
5743 HeapFree(GetProcessHeap(), 0, bufA
);
5745 heap_free(efnd
.elf
);
5749 static void test_fullname2(void)
5751 test_fullname2_helper("Arial");
5752 test_fullname2_helper("DejaVu Sans");
5753 test_fullname2_helper("Lucida Sans");
5754 test_fullname2_helper("Tahoma");
5755 test_fullname2_helper("Webdings");
5756 test_fullname2_helper("Wingdings");
5757 test_fullname2_helper("SimSun");
5758 test_fullname2_helper("NSimSun");
5759 test_fullname2_helper("MingLiu");
5760 test_fullname2_helper("PMingLiu");
5761 test_fullname2_helper("WenQuanYi Micro Hei");
5762 test_fullname2_helper("MS UI Gothic");
5763 test_fullname2_helper("Ume UI Gothic");
5764 test_fullname2_helper("MS Gothic");
5765 test_fullname2_helper("Ume Gothic");
5766 test_fullname2_helper("MS PGothic");
5767 test_fullname2_helper("Ume P Gothic");
5768 test_fullname2_helper("Gulim");
5769 test_fullname2_helper("Batang");
5770 test_fullname2_helper("UnBatang");
5771 test_fullname2_helper("UnDotum");
5772 test_fullname2_helper("@SimSun");
5773 test_fullname2_helper("@NSimSun");
5774 test_fullname2_helper("@MingLiu");
5775 test_fullname2_helper("@PMingLiu");
5776 test_fullname2_helper("@WenQuanYi Micro Hei");
5777 test_fullname2_helper("@MS UI Gothic");
5778 test_fullname2_helper("@Ume UI Gothic");
5779 test_fullname2_helper("@MS Gothic");
5780 test_fullname2_helper("@Ume Gothic");
5781 test_fullname2_helper("@MS PGothic");
5782 test_fullname2_helper("@Ume P Gothic");
5783 test_fullname2_helper("@Gulim");
5784 test_fullname2_helper("@Batang");
5785 test_fullname2_helper("@UnBatang");
5786 test_fullname2_helper("@UnDotum");
5790 static void test_GetGlyphOutline_empty_contour(void)
5794 HFONT hfont
, hfont_prev
;
5795 TTPOLYGONHEADER
*header
;
5800 memset(&lf
, 0, sizeof(lf
));
5802 lstrcpyA(lf
.lfFaceName
, "wine_test");
5804 hfont
= CreateFontIndirectA(&lf
);
5805 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
5809 hfont_prev
= SelectObject(hdc
, hfont
);
5810 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5812 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
5813 ok(ret
== 228, "GetGlyphOutline returned %ld, expected 228\n", ret
);
5815 header
= (TTPOLYGONHEADER
*)buf
;
5816 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
5817 ok(ret
== 228, "GetGlyphOutline returned %ld, expected 228\n", ret
);
5818 ok(header
->cb
== 36, "header->cb = %ld, expected 36\n", header
->cb
);
5819 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %ld, expected TT_POLYGON_TYPE\n", header
->dwType
);
5820 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5821 ok(header
->cb
== 96, "header->cb = %ld, expected 96\n", header
->cb
);
5822 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
5823 ok(header
->cb
== 96, "header->cb = %ld, expected 96\n", header
->cb
);
5825 SelectObject(hdc
, hfont_prev
);
5826 DeleteObject(hfont
);
5827 ReleaseDC(NULL
, hdc
);
5830 static void test_GetGlyphOutline_metric_clipping(void)
5834 HFONT hfont
, hfont_prev
;
5840 memset(&lf
, 0, sizeof(lf
));
5842 lstrcpyA(lf
.lfFaceName
, "wine_test");
5844 SetLastError(0xdeadbeef);
5845 hfont
= CreateFontIndirectA(&lf
);
5846 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
5850 hfont_prev
= SelectObject(hdc
, hfont
);
5851 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5853 SetLastError(0xdeadbeef);
5854 ret
= GetTextMetricsA(hdc
, &tm
);
5855 ok(ret
, "GetTextMetrics error %lu\n", GetLastError());
5857 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5858 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
5859 "Glyph top(%ld) exceeds ascent(%ld)\n",
5860 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
5861 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
5862 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
5863 "Glyph bottom(%ld) exceeds descent(%ld)\n",
5864 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
5866 /* Test tmLastChar - wine_test has code points fffb-fffe mapped to glyph 0 */
5867 GetTextMetricsW(hdc
, &tmW
);
5869 ok( tmW
.tmLastChar
== 0xfffe, "got %04x\n", tmW
.tmLastChar
);
5871 SelectObject(hdc
, hfont_prev
);
5872 DeleteObject(hfont
);
5873 ReleaseDC(NULL
, hdc
);
5876 static void test_GetGlyphOutline_character(void)
5878 HFONT hfont
, hfont_old
;
5882 GLYPHMETRICS gm1
, gm2
, gmn
;
5883 char test_chars
[] = { 'A', 'D', '!', '\0' };
5886 memset(&lf
, 0, sizeof(lf
));
5888 lstrcpyA(lf
.lfFaceName
, "wine_test");
5890 hfont
= CreateFontIndirectA(&lf
);
5891 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
5895 hfont_old
= SelectObject(hdc
, hfont
);
5896 ok(hfont_old
!= NULL
, "SelectObject failed\n");
5898 ret
= GetGlyphOutlineW(hdc
, 'Z', GGO_METRICS
, &gmn
, 0, NULL
, &mat
);
5899 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed to default to .notdef for character 'Z'\n");
5901 for (current_char
= test_chars
; *current_char
!= '\0'; current_char
++)
5903 ret
= GetGlyphOutlineW(hdc
, *current_char
, GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
5904 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for '%c'\n", *current_char
);
5905 ok(memcmp(&gm1
, &gmn
, sizeof(gmn
)) != 0, "the test character '%c' matches .notdef\n", *current_char
);
5907 ret
= GetGlyphOutlineW(hdc
, 0x10000 + *current_char
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
5908 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for 0x10000 + '%c'\n", *current_char
);
5909 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for character 0x10000 + '%c'\n", *current_char
);
5912 ret
= GetGlyphOutlineW(hdc
, 0x3, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm1
, 0, NULL
, &mat
);
5913 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed for glyph index 0x3\n");
5915 ret
= GetGlyphOutlineW(hdc
, 0xFFFF, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5916 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW for nonexistent glyph index 0xFFFF has succeeded\n");
5918 ret
= GetGlyphOutlineW(hdc
, 0x10003, GGO_METRICS
|GGO_GLYPH_INDEX
, &gm2
, 0, NULL
, &mat
);
5919 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW for index 0x10003 has failed\n");
5920 ok(memcmp(&gm1
, &gm2
, sizeof(gmn
)) == 0, "GetGlyphOutlineW returned wrong metrics for glyph 0x10003\n");
5922 SelectObject(hdc
, hfont_old
);
5923 DeleteObject(hfont
);
5924 ReleaseDC(NULL
, hdc
);
5927 static void test_fstype_fixup(void)
5931 HFONT hfont
, hfont_prev
;
5933 OUTLINETEXTMETRICA
*otm
;
5936 memset(&lf
, 0, sizeof(lf
));
5938 lstrcpyA(lf
.lfFaceName
, "wine_test");
5940 SetLastError(0xdeadbeef);
5941 hfont
= CreateFontIndirectA(&lf
);
5942 ok(hfont
!= 0, "CreateFontIndirectA error %lu\n", GetLastError());
5946 hfont_prev
= SelectObject(hdc
, hfont
);
5947 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
5949 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
5950 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
5951 otm
->otmSize
= sizeof(*otm
);
5952 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
5953 ok(ret
== otm
->otmSize
, "expected %u, got %lu, error %ld\n", otm
->otmSize
, ret
, GetLastError());
5955 /* Test font has fsType set to 0x7fff, test that reserved bits are filtered out,
5956 valid bits are 1, 2, 3, 8, 9. */
5957 ok((otm
->otmfsType
& ~0x30e) == 0, "fsType %#x\n", otm
->otmfsType
);
5959 HeapFree(GetProcessHeap(), 0, otm
);
5961 SelectObject(hdc
, hfont_prev
);
5962 DeleteObject(hfont
);
5963 ReleaseDC(NULL
, hdc
);
5966 static void test_CreateScalableFontResource(void)
5968 char ttf_name
[MAX_PATH
];
5969 char tmp_path
[MAX_PATH
];
5970 char fot_name
[MAX_PATH
];
5975 if (!write_ttf_file("wine_test.ttf", ttf_name
))
5977 skip("Failed to create ttf file for testing\n");
5981 trace("created %s\n", ttf_name
);
5983 ret
= is_truetype_font_installed("wine_test");
5984 ok(!ret
, "font wine_test should not be enumerated\n");
5986 ret
= GetTempPathA(MAX_PATH
, tmp_path
);
5987 ok(ret
, "GetTempPath() error %ld\n", GetLastError());
5988 ret
= GetTempFileNameA(tmp_path
, "fot", 0, fot_name
);
5989 ok(ret
, "GetTempFileName() error %ld\n", GetLastError());
5991 ret
= GetFileAttributesA(fot_name
);
5992 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
5994 SetLastError(0xdeadbeef);
5995 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
5996 ok(!ret
, "CreateScalableFontResource() should fail\n");
5997 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %ld\n", GetLastError());
5999 SetLastError(0xdeadbeef);
6000 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, "");
6001 ok(!ret
, "CreateScalableFontResource() should fail\n");
6002 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %ld\n", GetLastError());
6004 file_part
= strrchr(ttf_name
, '\\');
6005 SetLastError(0xdeadbeef);
6006 ret
= CreateScalableFontResourceA(0, fot_name
, file_part
, tmp_path
);
6007 ok(!ret
, "CreateScalableFontResource() should fail\n");
6008 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %ld\n", GetLastError());
6010 SetLastError(0xdeadbeef);
6011 ret
= CreateScalableFontResourceA(0, fot_name
, "random file name", tmp_path
);
6012 ok(!ret
, "CreateScalableFontResource() should fail\n");
6013 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %ld\n", GetLastError());
6015 SetLastError(0xdeadbeef);
6016 ret
= CreateScalableFontResourceA(0, fot_name
, NULL
, ttf_name
);
6017 ok(!ret
, "CreateScalableFontResource() should fail\n");
6018 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %ld\n", GetLastError());
6020 ret
= DeleteFileA(fot_name
);
6021 ok(ret
, "DeleteFile() error %ld\n", GetLastError());
6023 ret
= RemoveFontResourceExA(fot_name
, 0, 0);
6024 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6026 /* test public font resource */
6027 SetLastError(0xdeadbeef);
6028 ret
= CreateScalableFontResourceA(0, fot_name
, ttf_name
, NULL
);
6029 ok(ret
, "CreateScalableFontResource() error %ld\n", GetLastError());
6031 ret
= is_truetype_font_installed("wine_test");
6032 ok(!ret
, "font wine_test should not be enumerated\n");
6034 SetLastError(0xdeadbeef);
6035 ret
= AddFontResourceExA(fot_name
, 0, 0);
6036 ok(ret
, "AddFontResourceEx() error %ld\n", GetLastError());
6038 ret
= is_truetype_font_installed("wine_test");
6039 ok(ret
, "font wine_test should be enumerated\n");
6041 test_GetGlyphOutline_empty_contour();
6042 test_GetGlyphOutline_metric_clipping();
6043 test_GetGlyphOutline_character();
6044 test_fstype_fixup();
6046 ret
= RemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6047 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
6049 SetLastError(0xdeadbeef);
6050 ret
= RemoveFontResourceExA(fot_name
, 0, 0);
6051 ok(ret
, "RemoveFontResourceEx() error %ld\n", GetLastError());
6053 ret
= is_truetype_font_installed("wine_test");
6054 ok(!ret
, "font wine_test should not be enumerated\n");
6056 ret
= RemoveFontResourceExA(fot_name
, 0, 0);
6057 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6059 /* test refcounting */
6060 for (i
= 0; i
< 5; i
++)
6062 SetLastError(0xdeadbeef);
6063 ret
= AddFontResourceExA(fot_name
, 0, 0);
6064 ok(ret
, "AddFontResourceEx() error %ld\n", GetLastError());
6066 for (i
= 0; i
< 5; i
++)
6068 SetLastError(0xdeadbeef);
6069 ret
= RemoveFontResourceExA(fot_name
, 0, 0);
6070 ok(ret
, "RemoveFontResourceEx() error %ld\n", GetLastError());
6072 ret
= RemoveFontResourceExA(fot_name
, 0, 0);
6073 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6075 DeleteFileA(fot_name
);
6077 /* test hidden font resource */
6078 SetLastError(0xdeadbeef);
6079 ret
= CreateScalableFontResourceA(1, fot_name
, ttf_name
, NULL
);
6080 ok(ret
, "CreateScalableFontResource() error %ld\n", GetLastError());
6082 ret
= is_truetype_font_installed("wine_test");
6083 ok(!ret
, "font wine_test should not be enumerated\n");
6085 SetLastError(0xdeadbeef);
6086 ret
= AddFontResourceExA(fot_name
, 0, 0);
6087 ok(ret
, "AddFontResourceEx() error %ld\n", GetLastError());
6089 ret
= is_truetype_font_installed("wine_test");
6091 ok(!ret
, "font wine_test should not be enumerated\n");
6093 /* XP allows removing a private font added with 0 flags */
6094 SetLastError(0xdeadbeef);
6095 ret
= RemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
6096 ok(ret
, "RemoveFontResourceEx() error %ld\n", GetLastError());
6098 ret
= is_truetype_font_installed("wine_test");
6099 ok(!ret
, "font wine_test should not be enumerated\n");
6101 ret
= RemoveFontResourceExA(fot_name
, 0, 0);
6102 ok(!ret
, "RemoveFontResourceEx() should fail\n");
6104 DeleteFileA(fot_name
);
6105 DeleteFileA(ttf_name
);
6108 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
6111 HFONT hfont
, hfont_prev
;
6115 static const WCHAR str
[] = { 0x2025 };
6117 *installed
= is_truetype_font_installed(name
);
6121 lf
.lfEscapement
= 0;
6122 lf
.lfOrientation
= 0;
6123 lf
.lfWeight
= FW_DONTCARE
;
6127 lf
.lfCharSet
= DEFAULT_CHARSET
;
6128 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
6129 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6130 lf
.lfQuality
= DEFAULT_QUALITY
;
6131 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
6132 strcpy(lf
.lfFaceName
, name
);
6134 hfont
= CreateFontIndirectA(&lf
);
6135 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
6139 hfont_prev
= SelectObject(hdc
, hfont
);
6140 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
6142 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
6143 ok(ret
, "GetTextFaceA failed\n");
6144 *selected
= !strcmp(facename
, name
);
6146 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
6147 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6149 memset(gm
, 0, sizeof *gm
);
6151 ret
= GetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
6152 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
6154 SelectObject(hdc
, hfont_prev
);
6155 DeleteObject(hfont
);
6156 ReleaseDC(NULL
, hdc
);
6159 static void check_vertical_metrics(const char *face
)
6162 HFONT hfont
, hfont_prev
;
6165 GLYPHMETRICS rgm
, vgm
;
6166 const UINT code
= 0x5EAD, height
= 1000;
6169 OUTLINETEXTMETRICA otm
;
6170 USHORT numOfLongVerMetrics
;
6174 memset(&lf
, 0, sizeof(lf
));
6175 strcpy(lf
.lfFaceName
, face
);
6176 lf
.lfHeight
= -height
;
6177 lf
.lfCharSet
= DEFAULT_CHARSET
;
6178 lf
.lfEscapement
= lf
.lfOrientation
= 900;
6179 hfont
= CreateFontIndirectA(&lf
);
6180 hfont_prev
= SelectObject(hdc
, hfont
);
6181 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &rgm
, 0, NULL
, &mat
);
6182 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6183 ret
= GetCharABCWidthsW(hdc
, code
, code
, &abc
);
6184 ok(ret
, "GetCharABCWidthsW failed\n");
6185 DeleteObject(SelectObject(hdc
, hfont_prev
));
6187 memset(&lf
, 0, sizeof(lf
));
6188 strcpy(lf
.lfFaceName
, "@");
6189 strcat(lf
.lfFaceName
, face
);
6190 lf
.lfHeight
= -height
;
6191 lf
.lfCharSet
= DEFAULT_CHARSET
;
6192 hfont
= CreateFontIndirectA(&lf
);
6193 hfont_prev
= SelectObject(hdc
, hfont
);
6194 ret
= GetGlyphOutlineW(hdc
, code
, GGO_METRICS
, &vgm
, 0, NULL
, &mat
);
6195 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
6196 ret
= GetCharABCWidthsW(hdc
, code
, code
, &vabc
);
6197 ok(ret
, "GetCharABCWidthsW failed\n");
6198 ok(vabc
.abcA
== vgm
.gmptGlyphOrigin
.x
, "expected %d, got %ld\n",
6199 vabc
.abcA
, vgm
.gmptGlyphOrigin
.x
);
6200 ok(vabc
.abcB
== vgm
.gmBlackBoxX
, "expected %d, got %d\n",
6201 vabc
.abcB
, vgm
.gmBlackBoxX
);
6202 ok(vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
== vgm
.gmCellIncX
,
6203 "expected %d, got %d\n",
6204 vabc
.abcA
+ vabc
.abcB
+ vabc
.abcC
, vgm
.gmCellIncX
);
6206 memset(&otm
, 0, sizeof(otm
));
6207 otm
.otmSize
= sizeof(otm
);
6208 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
6209 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
6211 if (GetFontData(hdc
, MS_MAKE_TAG('v','h','e','a'), sizeof(SHORT
) * 17,
6212 &numOfLongVerMetrics
, sizeof(numOfLongVerMetrics
)) != GDI_ERROR
) {
6214 SHORT topSideBearing
;
6216 ret
= GetGlyphIndicesW(hdc
, (LPCWSTR
)&code
, 1, &idx
, 0);
6217 ok(ret
!= 0, "GetGlyphIndicesW failed\n");
6218 numOfLongVerMetrics
= GET_BE_WORD(numOfLongVerMetrics
);
6219 if (numOfLongVerMetrics
> idx
)
6220 offset
= idx
* 2 + 1;
6222 offset
= numOfLongVerMetrics
* 2 + (idx
- numOfLongVerMetrics
);
6223 ret
= GetFontData(hdc
, MS_MAKE_TAG('v','m','t','x'), offset
* sizeof(SHORT
),
6224 &topSideBearing
, sizeof(SHORT
));
6225 ok(ret
!= GDI_ERROR
, "GetFontData(vmtx) failed\n");
6226 topSideBearing
= GET_BE_WORD(topSideBearing
);
6227 ok(match_off_by_1(vgm
.gmptGlyphOrigin
.x
,
6228 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), FALSE
),
6229 "expected %d, got %ld\n",
6230 MulDiv(topSideBearing
, height
, otm
.otmEMSquare
), vgm
.gmptGlyphOrigin
.x
);
6234 ok(vgm
.gmptGlyphOrigin
.x
== rgm
.gmptGlyphOrigin
.x
+ vgm
.gmCellIncX
+ otm
.otmDescent
,
6235 "got %ld, expected rgm.origin.x(%ld) + vgm.cellIncX(%d) + descent(%d)\n",
6236 vgm
.gmptGlyphOrigin
.x
, rgm
.gmptGlyphOrigin
.x
, vgm
.gmCellIncX
, otm
.otmDescent
);
6239 ok(vgm
.gmptGlyphOrigin
.y
== abc
.abcA
+ abc
.abcB
+ otm
.otmDescent
,
6240 "got %d, expected abcA(%d) + abcB(%u) + descent(%d)\n",
6241 (INT
)vgm
.gmptGlyphOrigin
.y
, abc
.abcA
, abc
.abcB
, otm
.otmDescent
);
6243 DeleteObject(SelectObject(hdc
, hfont_prev
));
6244 ReleaseDC(NULL
, hdc
);
6247 static void test_vertical_font(void)
6249 char ttf_name
[MAX_PATH
];
6251 BOOL ret
, installed
, selected
;
6254 const char* face_list
[] = {
6255 "@WineTestVertical", /* has vmtx table */
6256 "@Ume Gothic", /* doesn't have vmtx table */
6257 "@MS UI Gothic", /* has vmtx table, available on native */
6260 if (!write_ttf_file("vertical.ttf", ttf_name
))
6262 skip("Failed to create ttf file for testing\n");
6266 num
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6267 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
6269 check_vertical_font("WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
6270 ok(installed
, "WineTestVertical is not installed\n");
6271 ok(selected
, "WineTestVertical is not selected\n");
6272 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6273 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
6274 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6276 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
6277 ok(installed
, "@WineTestVertical is not installed\n");
6278 ok(selected
, "@WineTestVertical is not selected\n");
6279 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
6280 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
6281 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
6283 ok(hgi
!= vgi
, "same glyph h:%u v:%u\n", hgi
, vgi
);
6285 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++) {
6286 const char* face
= face_list
[i
];
6287 if (!is_truetype_font_installed(face
)) {
6288 skip("%s is not installed\n", face
);
6291 check_vertical_metrics(&face
[1]);
6294 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
6295 ok(ret
, "RemoveFontResourceEx() error %ld\n", GetLastError());
6297 DeleteFileA(ttf_name
);
6300 static INT CALLBACK
has_vertical_font_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*ntm
,
6301 DWORD type
, LPARAM lParam
)
6303 if (lf
->lfFaceName
[0] == '@') {
6309 static void test_east_asian_font_selection(void)
6312 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
6313 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
6318 for (i
= 0; i
< ARRAY_SIZE(charset
); i
++)
6322 char face_name
[LF_FACESIZE
];
6325 memset(&lf
, 0, sizeof lf
);
6326 lf
.lfFaceName
[0] = '\0';
6327 lf
.lfCharSet
= charset
[i
];
6329 if (EnumFontFamiliesExA(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
6331 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
6335 hfont
= CreateFontIndirectA(&lf
);
6336 hfont
= SelectObject(hdc
, hfont
);
6337 memset(face_name
, 0, sizeof face_name
);
6338 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6339 ok(ret
&& face_name
[0] != '@',
6340 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6341 DeleteObject(SelectObject(hdc
, hfont
));
6343 memset(&lf
, 0, sizeof lf
);
6344 strcpy(lf
.lfFaceName
, "@");
6345 lf
.lfCharSet
= charset
[i
];
6346 hfont
= CreateFontIndirectA(&lf
);
6347 hfont
= SelectObject(hdc
, hfont
);
6348 memset(face_name
, 0, sizeof face_name
);
6349 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
6350 ok(ret
&& face_name
[0] == '@',
6351 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
6352 DeleteObject(SelectObject(hdc
, hfont
));
6354 ReleaseDC(NULL
, hdc
);
6357 static int get_font_dpi(const LOGFONTA
*lf
, int *height
)
6359 HDC hdc
= CreateCompatibleDC(0);
6364 hfont
= CreateFontIndirectA(lf
);
6365 ok(hfont
!= 0, "CreateFontIndirect failed\n");
6367 SelectObject(hdc
, hfont
);
6368 ret
= GetTextMetricsA(hdc
, &tm
);
6369 ok(ret
, "GetTextMetrics failed\n");
6370 ret
= tm
.tmDigitizedAspectX
;
6371 if (height
) *height
= tm
.tmHeight
;
6374 DeleteObject(hfont
);
6379 static void test_stock_fonts(void)
6381 static const int font
[] =
6383 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
6384 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
6386 static const struct test_data
6388 int charset
, weight
, height
, height_pixels
, dpi
;
6389 const char face_name
[LF_FACESIZE
];
6393 { /* ANSI_FIXED_FONT */
6394 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_ARABIC
},
6395 { ANSI_CHARSET
, FW_NORMAL
, 12, 12, 96, "Courier", LANG_HEBREW
},
6396 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "Courier" },
6397 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "Courier" },
6400 { /* ANSI_VAR_FONT */
6401 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 96, "MS Sans Serif" },
6402 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 13, 120, "MS Sans Serif" },
6406 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6407 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6408 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6409 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6410 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6411 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6414 { /* DEVICE_DEFAULT_FONT */
6415 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 18, 96, "System" },
6416 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 22, 120, "System" },
6417 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 16, 96, "System" },
6418 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 20, 120, "System" },
6419 { DEFAULT_CHARSET
, FW_BOLD
, 16, 16, 96, "System" },
6420 { DEFAULT_CHARSET
, FW_BOLD
, 20, 20, 120, "System" },
6423 { /* DEFAULT_GUI_FONT */
6424 { SHIFTJIS_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6425 { SHIFTJIS_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6426 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MS UI Gothic" },
6427 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MS UI Gothic" },
6428 { HANGEUL_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6429 { HANGEUL_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6430 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 15, 96, "?Gulim" },
6431 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 18, 120, "?Gulim" },
6432 { GB2312_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6433 { GB2312_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6434 { GB2312_CHARSET
, FW_NORMAL
, -12, 15, 96, "?SimHei" },
6435 { GB2312_CHARSET
, FW_NORMAL
, -15, 18, 120, "?SimHei" },
6436 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 15, 96, "?MingLiU" },
6437 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 18, 120, "?MingLiU" },
6438 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 13, 96, "MS Shell Dlg" },
6439 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 16, 120, "MS Shell Dlg" },
6445 for (i
= 0; i
< ARRAY_SIZE(font
); i
++)
6451 hfont
= GetStockObject(font
[i
]);
6452 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
6454 ret
= GetObjectA(hfont
, sizeof(lf
), &lf
);
6455 ok(ret
== sizeof(lf
), "%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
6457 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
6459 if ((lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
) ||
6460 (system_lang_id
!= td
[i
][j
].lang_id
&& td
[i
][j
].lang_id
!= LANG_NEUTRAL
) ||
6461 (td
[i
][j
].face_name
[0] != '?' && strcmp(lf
.lfFaceName
, td
[i
][j
].face_name
)))
6466 ret
= get_font_dpi(&lf
, &height
);
6467 if (ret
!= td
[i
][j
].dpi
)
6469 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
6470 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
6474 /* FIXME: Remove once Wine is fixed */
6475 todo_wine_if (td
[i
][j
].dpi
!= 96 &&
6476 /* MS Sans Serif for 120 dpi and higher should include 12 pixel bitmap set */
6477 ((!strcmp(td
[i
][j
].face_name
, "MS Sans Serif") && td
[i
][j
].height
== 12) ||
6478 /* System for 120 dpi and higher should include 20 pixel bitmap set */
6479 (!strcmp(td
[i
][j
].face_name
, "System") && td
[i
][j
].height
> 16)))
6480 ok(height
== td
[i
][j
].height_pixels
, "%d(%d): expected height %d, got %d\n", i
, j
, td
[i
][j
].height_pixels
, height
);
6482 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %ld\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
6483 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %ld\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
6484 if (td
[i
][j
].face_name
[0] == '?')
6486 /* Wine doesn't have this font, skip this case for now.
6487 Actually, the face name is localized on Windows and varies
6488 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
6489 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
6493 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
);
6500 static void test_max_height(void)
6504 HFONT hfont
, hfont_old
;
6505 TEXTMETRICA tm1
, tm
;
6507 LONG invalid_height
[] = { -65536, -123456, 123456 };
6510 memset(&tm1
, 0, sizeof(tm1
));
6511 memset(&lf
, 0, sizeof(lf
));
6512 strcpy(lf
.lfFaceName
, "Tahoma");
6517 /* get 1 ppem value */
6518 hfont
= CreateFontIndirectA(&lf
);
6519 hfont_old
= SelectObject(hdc
, hfont
);
6520 r
= GetTextMetricsA(hdc
, &tm1
);
6521 ok(r
, "GetTextMetrics failed\n");
6522 ok(tm1
.tmHeight
> 0, "expected a positive value, got %ld\n", tm1
.tmHeight
);
6523 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %ld\n", tm1
.tmHeight
);
6524 DeleteObject(SelectObject(hdc
, hfont_old
));
6526 /* test the largest value */
6527 lf
.lfHeight
= -((1 << 16) - 1);
6528 hfont
= CreateFontIndirectA(&lf
);
6529 hfont_old
= SelectObject(hdc
, hfont
);
6530 memset(&tm
, 0, sizeof(tm
));
6531 r
= GetTextMetricsA(hdc
, &tm
);
6532 ok(r
, "GetTextMetrics failed\n");
6533 ok(tm
.tmHeight
> tm1
.tmHeight
,
6534 "expected greater than 1 ppem value (%ld), got %ld\n", tm1
.tmHeight
, tm
.tmHeight
);
6535 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
6536 "expected greater than 1 ppem value (%ld), got %ld\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6537 DeleteObject(SelectObject(hdc
, hfont_old
));
6539 /* test an invalid value */
6540 for (i
= 0; i
< ARRAY_SIZE(invalid_height
); i
++) {
6541 winetest_push_context("height=%ld", invalid_height
[i
]);
6542 lf
.lfHeight
= invalid_height
[i
];
6543 hfont
= CreateFontIndirectA(&lf
);
6544 hfont_old
= SelectObject(hdc
, hfont
);
6545 memset(&tm
, 0, sizeof(tm
));
6546 r
= GetTextMetricsA(hdc
, &tm
);
6547 ok(r
, "GetTextMetrics failed\n");
6548 ok(tm
.tmHeight
== tm1
.tmHeight
,
6549 "expected 1 ppem value (%ld), got %ld\n", tm1
.tmHeight
, tm
.tmHeight
);
6550 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
6551 "expected 1 ppem value (%ld), got %ld\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
6552 DeleteObject(SelectObject(hdc
, hfont_old
));
6553 winetest_pop_context();
6556 ReleaseDC(NULL
, hdc
);
6560 static void test_vertical_order(void)
6562 struct enum_font_data efd
;
6567 hdc
= CreateCompatibleDC(0);
6568 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6570 memset(&lf
, 0, sizeof(lf
));
6571 lf
.lfCharSet
= DEFAULT_CHARSET
;
6572 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
6575 lf
.lfQuality
= DEFAULT_QUALITY
;
6576 lf
.lfItalic
= FALSE
;
6577 lf
.lfWeight
= FW_DONTCARE
;
6578 memset( &efd
, 0, sizeof(efd
) );
6579 EnumFontFamiliesExA(hdc
, &lf
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
6580 for (i
= 0; i
< efd
.total
; i
++)
6582 if (efd
.lf
[i
].lfFaceName
[0] != '@') continue;
6583 for (j
= 0; j
< efd
.total
; j
++)
6585 if (!strcmp(efd
.lf
[i
].lfFaceName
+ 1, efd
.lf
[j
].lfFaceName
))
6587 ok(i
> j
,"Found vertical font %s before its horizontal version\n", efd
.lf
[i
].lfFaceName
);
6592 heap_free( efd
.lf
);
6596 static void test_GetCharWidth32(void)
6606 memset(&lf
, 0, sizeof(lf
));
6607 strcpy(lf
.lfFaceName
, "System");
6610 hfont
= CreateFontIndirectA(&lf
);
6612 hfont
= SelectObject(hdc
, hfont
);
6614 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6615 ok(ret
, "GetCharWidth32W should have succeeded\n");
6616 ret
= GetCharWidth32A(hdc
, 'a', 'a', &bufferA
);
6617 ok(ret
, "GetCharWidth32A should have succeeded\n");
6618 ok (bufferA
== bufferW
, "Widths should be the same\n");
6619 ok (bufferA
> 0," Width should be greater than zero\n");
6621 hfont
= SelectObject(hdc
, hfont
);
6622 DeleteObject(hfont
);
6623 ReleaseDC(NULL
, hdc
);
6625 memset(&lf
, 0, sizeof(lf
));
6626 strcpy(lf
.lfFaceName
, "Tahoma");
6629 hfont
= CreateFontIndirectA(&lf
);
6630 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
6633 SetMapMode( hdc
, MM_ANISOTROPIC
);
6634 SelectObject(hdc
, hfont
);
6636 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6637 ok(ret
, "GetCharWidth32W should have succeeded\n");
6638 ok (bufferW
> 0," Width should be greater than zero\n");
6639 SetWindowExtEx(hdc
, -1,-1,NULL
);
6640 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6641 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6642 ok(ret
, "GetCharWidth32W should have succeeded\n");
6643 ok (bufferW
> 0," Width should be greater than zero\n");
6644 SetGraphicsMode(hdc
, GM_ADVANCED
);
6645 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6646 ok(ret
, "GetCharWidth32W should have succeeded\n");
6647 ok (bufferW
> 0," Width should be greater than zero\n");
6648 SetWindowExtEx(hdc
, 1,1,NULL
);
6649 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6650 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6651 ok(ret
, "GetCharWidth32W should have succeeded\n");
6652 ok (bufferW
> 0," Width should be greater than zero\n");
6653 SetGraphicsMode(hdc
, GM_ADVANCED
);
6654 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6655 ok(ret
, "GetCharWidth32W should have succeeded\n");
6656 ok (bufferW
> 0," Width should be greater than zero\n");
6658 ReleaseDC(hwnd
, hdc
);
6659 DestroyWindow(hwnd
);
6661 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
6664 SetMapMode( hdc
, MM_ANISOTROPIC
);
6665 SelectObject(hdc
, hfont
);
6667 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6668 ok(ret
, "GetCharWidth32W should have succeeded\n");
6669 ok (bufferW
> 0," Width should be greater than zero\n");
6670 SetWindowExtEx(hdc
, -1,-1,NULL
);
6671 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6672 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6673 ok(ret
, "GetCharWidth32W should have succeeded\n");
6674 ok (bufferW
> 0," Width should be greater than zero\n");
6675 SetGraphicsMode(hdc
, GM_ADVANCED
);
6676 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6677 ok(ret
, "GetCharWidth32W should have succeeded\n");
6678 ok (bufferW
> 0," Width should be greater than zero\n");
6679 SetWindowExtEx(hdc
, 1,1,NULL
);
6680 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
6681 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6682 ok(ret
, "GetCharWidth32W should have succeeded\n");
6683 ok (bufferW
> 0," Width should be greater than zero\n");
6684 SetGraphicsMode(hdc
, GM_ADVANCED
);
6685 ret
= GetCharWidth32W(hdc
, 'a', 'a', &bufferW
);
6686 ok(ret
, "GetCharWidth32W should have succeeded\n");
6687 ok (bufferW
> 0," Width should be greater than zero\n");
6689 ReleaseDC(hwnd
, hdc
);
6690 DestroyWindow(hwnd
);
6691 DeleteObject(hfont
);
6694 static void test_fake_bold_font(void)
6696 static const MAT2 x2_mat
= { {0,2}, {0,0}, {0,0}, {0,2} };
6709 /* Test outline font */
6710 memset(&lf
, 0, sizeof(lf
));
6711 strcpy(lf
.lfFaceName
, "Wingdings");
6712 lf
.lfCharSet
= SYMBOL_CHARSET
;
6716 for (i
= 0; i
<= 1; i
++)
6718 HFONT hfont
, hfont_old
;
6720 lf
.lfWeight
= i
? FW_BOLD
: FW_NORMAL
;
6721 hfont
= CreateFontIndirectA(&lf
);
6722 hfont_old
= SelectObject(hdc
, hfont
);
6724 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6725 ok(ret
, "got %d\n", ret
);
6726 ret
= GetCharABCWidthsA(hdc
, 0x76, 0x76, &data
[i
].abc
);
6727 ok(ret
, "got %d\n", ret
);
6728 data
[i
].w
= data
[i
].abc
.abcA
+ data
[i
].abc
.abcB
+ data
[i
].abc
.abcC
;
6729 r
= GetGlyphOutlineA(hdc
, 0x76, GGO_METRICS
, &data
[i
].gm
, 0, NULL
, &x2_mat
);
6730 ok(r
!= GDI_ERROR
, "got %d\n", ret
);
6732 SelectObject(hdc
, hfont_old
);
6733 DeleteObject(hfont
);
6735 ReleaseDC(NULL
, hdc
);
6737 /* compare results (outline) */
6738 ok(data
[0].tm
.tmHeight
== data
[1].tm
.tmHeight
,
6739 "expected %ld, got %ld\n", data
[0].tm
.tmHeight
, data
[1].tm
.tmHeight
);
6740 ok(data
[0].tm
.tmAscent
== data
[1].tm
.tmAscent
,
6741 "expected %ld, got %ld\n", data
[0].tm
.tmAscent
, data
[1].tm
.tmAscent
);
6742 ok(data
[0].tm
.tmDescent
== data
[1].tm
.tmDescent
,
6743 "expected %ld, got %ld\n", data
[0].tm
.tmDescent
, data
[1].tm
.tmDescent
);
6744 ok(data
[0].tm
.tmAveCharWidth
+ 1 == data
[1].tm
.tmAveCharWidth
,
6745 "expected %ld, got %ld\n", data
[0].tm
.tmAveCharWidth
+ 1, data
[1].tm
.tmAveCharWidth
);
6746 ok(data
[0].tm
.tmMaxCharWidth
+ 1 == data
[1].tm
.tmMaxCharWidth
,
6747 "expected %ld, got %ld\n", data
[0].tm
.tmMaxCharWidth
+ 1, data
[1].tm
.tmMaxCharWidth
);
6748 ok(data
[0].tm
.tmOverhang
== data
[1].tm
.tmOverhang
,
6749 "expected %ld, got %ld\n", data
[0].tm
.tmOverhang
, data
[1].tm
.tmOverhang
);
6750 ok(data
[0].w
+ 1 == data
[1].w
,
6751 "expected %d, got %d\n", data
[0].w
+ 1, data
[1].w
);
6753 ok(data
[0].gm
.gmCellIncX
+ 1 == data
[1].gm
.gmCellIncX
,
6754 "expected %d, got %d\n", data
[0].gm
.gmCellIncX
+ 1, data
[1].gm
.gmCellIncX
);
6755 ok(data
[0].gm
.gmCellIncY
== data
[1].gm
.gmCellIncY
,
6756 "expected %d, got %d\n", data
[0].gm
.gmCellIncY
, data
[1].gm
.gmCellIncY
);
6758 /* Test bitmap font */
6759 memset(&data
, 0xaa, sizeof(data
));
6760 memset(&lf
, 0, sizeof(lf
));
6761 strcpy(lf
.lfFaceName
, "Courier");
6762 lf
.lfCharSet
= ANSI_CHARSET
;
6766 for (i
= 0; i
< 4; i
++)
6768 HFONT hfont
, hfont_old
;
6770 lf
.lfWeight
= (i
% 2) ? FW_BOLD
: FW_NORMAL
;
6771 lf
.lfHeight
= (i
> 1) ? data
[0].tm
.tmHeight
* x2_mat
.eM11
.value
: 0;
6772 hfont
= CreateFontIndirectA(&lf
);
6773 hfont_old
= SelectObject(hdc
, hfont
);
6775 ret
= GetTextMetricsA(hdc
, &data
[i
].tm
);
6776 ok(ret
, "got %d\n", ret
);
6777 ret
= GetCharWidth32A(hdc
, 0x76, 0x76, &data
[i
].w
);
6778 ok(ret
, "got %d\n", ret
);
6780 SelectObject(hdc
, hfont_old
);
6781 DeleteObject(hfont
);
6783 ReleaseDC(NULL
, hdc
);
6785 /* compare results (bitmap) */
6786 for (i
= 0; i
< 4; i
+=2)
6788 int diff
= (i
> 1) ? x2_mat
.eM11
.value
: 1;
6789 if (data
[i
].tm
.tmPitchAndFamily
& TMPF_TRUETYPE
)
6791 skip("TrueType font is selected (expected a bitmap one)\n");
6794 ok(data
[i
].tm
.tmHeight
== data
[i
+1].tm
.tmHeight
,
6795 "expected %ld, got %ld\n", data
[i
].tm
.tmHeight
, data
[i
+1].tm
.tmHeight
);
6796 ok(data
[i
].tm
.tmAscent
== data
[i
+1].tm
.tmAscent
,
6797 "expected %ld, got %ld\n", data
[i
].tm
.tmAscent
, data
[i
+1].tm
.tmAscent
);
6798 ok(data
[i
].tm
.tmDescent
== data
[i
+1].tm
.tmDescent
,
6799 "expected %ld, got %ld\n", data
[i
].tm
.tmDescent
, data
[i
+1].tm
.tmDescent
);
6800 ok(data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
== diff
,
6801 "expected %d, got %ld\n", diff
, data
[i
+1].tm
.tmAveCharWidth
- data
[i
].tm
.tmAveCharWidth
);
6802 ok(data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
== diff
,
6803 "expected %d, got %ld\n", diff
, data
[i
+1].tm
.tmMaxCharWidth
- data
[i
].tm
.tmMaxCharWidth
);
6804 ok(data
[i
].tm
.tmOverhang
== 0,
6805 "expected 0, got %ld\n", data
[i
].tm
.tmOverhang
);
6806 ok(data
[i
+1].tm
.tmOverhang
== 1,
6807 "expected 1, got %ld\n", data
[i
+1].tm
.tmOverhang
);
6808 ok(data
[i
].w
+ 1 == data
[i
+1].w
,
6809 "expected %d, got %d\n", data
[i
].w
+ 1, data
[i
+1].w
);
6813 static void test_bitmap_font_glyph_index(void)
6815 const WCHAR text
[] = L
"#!/bin/sh";
6819 } bitmap_font_list
[] = {
6820 { "Courier", ANSI_CHARSET
},
6821 { "Small Fonts", ANSI_CHARSET
},
6822 { "Fixedsys", DEFAULT_CHARSET
},
6823 { "System", DEFAULT_CHARSET
}
6828 CHAR facename
[LF_FACESIZE
];
6839 hdc
= CreateCompatibleDC(0);
6840 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
6842 memset(&bmi
, 0, sizeof(bmi
));
6843 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
6844 bmi
.bmiHeader
.biBitCount
= 32;
6845 bmi
.bmiHeader
.biPlanes
= 1;
6846 bmi
.bmiHeader
.biWidth
= 128;
6847 bmi
.bmiHeader
.biHeight
= 32;
6848 bmi
.bmiHeader
.biCompression
= BI_RGB
;
6850 for (i
= 0; i
< ARRAY_SIZE(bitmap_font_list
); i
++) {
6851 memset(&lf
, 0, sizeof(lf
));
6852 lf
.lfCharSet
= bitmap_font_list
[i
].charset
;
6853 strcpy(lf
.lfFaceName
, bitmap_font_list
[i
].face
);
6854 hFont
= CreateFontIndirectA(&lf
);
6855 ok(hFont
!= NULL
, "Can't create font (%s:%d)\n", lf
.lfFaceName
, lf
.lfCharSet
);
6856 hFont
= SelectObject(hdc
, hFont
);
6857 ret
= GetTextMetricsA(hdc
, &tm
);
6858 ok(ret
, "GetTextMetric failed\n");
6859 ret
= GetTextFaceA(hdc
, sizeof(facename
), facename
);
6860 ok(ret
, "GetTextFace failed\n");
6861 if (tm
.tmPitchAndFamily
& TMPF_TRUETYPE
) {
6862 skip("TrueType font (%s) was selected for \"%s\"\n", facename
, bitmap_font_list
[i
].face
);
6865 if (lstrcmpiA(facename
, lf
.lfFaceName
) != 0) {
6866 skip("expected %s, got %s\n", lf
.lfFaceName
, facename
);
6870 for (j
= 0; j
< 2; j
++) {
6872 hBmp
[j
] = CreateDIBSection(hdc
, &bmi
, DIB_RGB_COLORS
, &pixels
[j
], NULL
, 0);
6873 ok(hBmp
[j
] != NULL
, "Can't create DIB\n");
6874 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6877 ret
= ExtTextOutW(hdc
, 0, 0, 0, NULL
, text
, lstrlenW(text
), NULL
);
6881 int len
= lstrlenW(text
);
6882 LPWORD indices
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WORD
));
6883 ret
= GetGlyphIndicesW(hdc
, text
, len
, indices
, 0);
6884 ok(ret
, "GetGlyphIndices failed\n");
6885 ok(memcmp(indices
, text
, sizeof(WORD
) * len
) == 0,
6886 "Glyph indices and text are different for %s:%d\n", lf
.lfFaceName
, tm
.tmCharSet
);
6887 ret
= ExtTextOutW(hdc
, 0, 0, ETO_GLYPH_INDEX
, NULL
, indices
, len
, NULL
);
6888 HeapFree(GetProcessHeap(), 0, indices
);
6892 ok(ret
, "ExtTextOutW failed\n");
6893 SelectObject(hdc
, hBmpPrev
);
6896 GetObjectA(hBmp
[0], sizeof(bmp
), &bmp
);
6897 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6898 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6900 ret
= TranslateCharsetInfo((LPDWORD
)(DWORD_PTR
)tm
.tmCharSet
, &ci
, TCI_SRCCHARSET
);
6902 skip("Can't get charset info for (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6905 if (IsDBCSLeadByteEx(ci
.ciACP
, chr
)) {
6906 skip("High-ascii character is not defined in codepage %d\n", ci
.ciACP
);
6910 for (j
= 0; j
< 2; j
++) {
6913 hBmpPrev
= SelectObject(hdc
, hBmp
[j
]);
6916 ret
= ExtTextOutA(hdc
, 100, 0, 0, NULL
, (LPCSTR
)&chr
, 1, NULL
);
6919 ret
= GetGlyphIndicesA(hdc
, (LPCSTR
)&chr
, 1, &code
, 0);
6920 ok(ret
, "GetGlyphIndices failed\n");
6921 ok(code
== chr
, "expected %02x, got %02x (%s:%d)\n", chr
, code
, lf
.lfFaceName
, tm
.tmCharSet
);
6922 ret
= ExtTextOutA(hdc
, 100, 0, ETO_GLYPH_INDEX
, NULL
, (LPCSTR
)&code
, 1, NULL
);
6925 ok(ret
, "ExtTextOutA failed\n");
6926 SelectObject(hdc
, hBmpPrev
);
6929 ok(memcmp(pixels
[0], pixels
[1], bmp
.bmHeight
* bmp
.bmWidthBytes
) == 0,
6930 "Images are different (%s:%d)\n", lf
.lfFaceName
, tm
.tmCharSet
);
6932 for (j
= 0; j
< 2; j
++)
6933 DeleteObject(hBmp
[j
]);
6934 hFont
= SelectObject(hdc
, hFont
);
6935 DeleteObject(hFont
);
6941 static void test_GetCharWidthI(void)
6943 static const char *teststr
= "wine ";
6944 HFONT hfont
, prev_hfont
;
6955 memset(&lf
, 0, sizeof(lf
));
6956 strcpy(lf
.lfFaceName
, "Tahoma");
6961 hfont
= CreateFontIndirectA(&lf
);
6962 prev_hfont
= SelectObject(hdc
, hfont
);
6964 len
= strlen(teststr
);
6965 nb
= GetGlyphIndicesA(hdc
, teststr
, len
, glyphs
, 0);
6966 ok(nb
== len
, "\n");
6968 memset(abc
, 0xcc, sizeof(abc
));
6969 ret
= GetCharABCWidthsI(hdc
, 0, len
, glyphs
, abc
);
6970 ok(ret
, "GetCharABCWidthsI failed\n");
6972 memset(&abc1
, 0xcc, sizeof(abc1
));
6973 ret
= GetCharABCWidthsI(hdc
, glyphs
[0], 1, NULL
, &abc1
);
6974 ok(ret
, "GetCharABCWidthsI failed\n");
6975 ok(!memcmp(&abc1
, abc
, sizeof(abc1
)), "unexpected abc1\n");
6977 memset(widths
, 0xcc, sizeof(widths
));
6978 ret
= GetCharWidthI(hdc
, 0, len
, glyphs
, widths
);
6979 ok(ret
, "GetCharWidthI failed\n");
6982 ret
= GetCharWidthI(hdc
, glyphs
[0], 1, NULL
, &width
);
6983 ok(ret
, "GetCharWidthI failed\n");
6984 ok(width
== widths
[0], "unexpected width %u\n", width
);
6986 for (i
= 0; i
< len
; i
++)
6987 ok(widths
[i
] == abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
, "%u, glyph %u, got width %d\n",
6988 i
, glyphs
[i
], widths
[i
]);
6990 DeleteObject(SelectObject(hdc
, prev_hfont
));
6994 static INT CALLBACK
long_enum_proc(const LOGFONTA
*lf
, const TEXTMETRICA
*tm
, DWORD type
, LPARAM lparam
)
6996 BOOL
*found_font
= (BOOL
*)lparam
;
7001 static void test_long_names(void)
7003 char ttf_name
[MAX_PATH
];
7004 LOGFONTA font
= {0};
7010 if (!write_ttf_file("wine_longname.ttf", ttf_name
))
7012 skip("Failed to create ttf file for testing\n");
7018 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7019 ok(ret
, "AddFontResourceEx() failed\n");
7021 strcpy(font
.lfFaceName
, "wine_3_this_is_a_very_long_name");
7023 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7024 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7026 strcpy(font
.lfFaceName
, "wine_2_this_is_a_very_long_name");
7028 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7029 ok(found_font
== TRUE
, "EnumFontFamiliesExA didn't find font.\n");
7031 strcpy(font
.lfFaceName
, "wine_1_this_is_a_very_long_name");
7033 EnumFontFamiliesExA(dc
, &font
, long_enum_proc
, (LPARAM
)&found_font
, 0);
7034 ok(found_font
== FALSE
, "EnumFontFamiliesExA must not find font.\n");
7036 handle_font
= CreateFontIndirectA(&font
);
7037 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7038 DeleteObject(handle_font
);
7040 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7041 ok(ret
, "RemoveFontResourceEx() failed\n");
7043 DeleteFileA(ttf_name
);
7044 ReleaseDC(NULL
, dc
);
7047 static void test_ttf_names(void)
7049 struct enum_fullname_data efnd
;
7050 char ttf_name
[MAX_PATH
], ttf_name_bold
[MAX_PATH
];
7051 LOGFONTA font
= {0};
7056 if (!write_ttf_file("wine_ttfnames.ttf", ttf_name
))
7058 skip("Failed to create ttf file for testing\n");
7062 if (!write_ttf_file("wine_ttfnames_bold.ttf", ttf_name_bold
))
7064 skip("Failed to create ttf file for testing\n");
7065 DeleteFileA(ttf_name
);
7069 ret
= AddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7070 ok(ret
, "AddFontResourceEx() failed\n");
7072 ret
= AddFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7073 ok(ret
, "AddFontResourceEx() failed\n");
7077 strcpy(font
.lfFaceName
, "Wine_TTF_Names_Long_Family1_Con");
7078 memset(&efnd
, 0, sizeof(efnd
));
7079 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7080 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7082 /* Windows doesn't match with Typographic/Preferred Family tags */
7083 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1");
7084 memset(&efnd
, 0, sizeof(efnd
));
7085 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7086 ok(efnd
.total
== 0, "EnumFontFamiliesExA must not find font.\n");
7088 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Ext");
7089 memset(&efnd
, 0, sizeof(efnd
));
7090 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7091 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7093 strcpy(font
.lfFaceName
, "Wine TTF Names Long Family1 Con");
7094 memset(&efnd
, 0, sizeof(efnd
));
7095 EnumFontFamiliesExA(dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
7096 ok(efnd
.total
== 2, "EnumFontFamiliesExA found %d fonts, expected 2.\n", efnd
.total
);
7098 handle_font
= CreateFontIndirectA(&font
);
7099 ok(handle_font
!= NULL
, "CreateFontIndirectA failed\n");
7100 DeleteObject(handle_font
);
7102 ret
= RemoveFontResourceExA(ttf_name_bold
, FR_PRIVATE
, 0);
7103 ok(ret
, "RemoveFontResourceEx() failed\n");
7105 DeleteFileA(ttf_name_bold
);
7107 ret
= RemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
7108 ok(ret
, "RemoveFontResourceEx() failed\n");
7110 DeleteFileA(ttf_name
);
7111 ReleaseDC(NULL
, dc
);
7114 static void test_lang_names(void)
7116 static const WCHAR name_cond_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja)";
7117 static const WCHAR name_cond_ja_reg_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg";
7118 static const WCHAR name_cond_ja_reg_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d Cond (ja) Reg (ja)";
7119 static const WCHAR name_wws_ja_w
[] = L
"\x30d5\x30a9\x30f3\x30c8\x540d WWS (ja)";
7121 struct enum_fullname_data efnd
;
7122 struct enum_fullname_data_w efnd_w
;
7123 char ttf_name
[MAX_PATH
], ttf_name2
[MAX_PATH
], ttf_name3
[MAX_PATH
];
7124 LOGFONTA font
= {0};
7125 LOGFONTW font_w
= {0};
7128 const WCHAR
*primary_family
, *primary_fullname
;
7130 if (PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
&& PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_JAPANESE
)
7132 skip( "Primary language is neither English nor Japanese, skipping test\n" );
7136 if (!write_ttf_file( "wine_langnames.ttf", ttf_name
))
7138 skip( "Failed to create ttf file for testing\n" );
7142 if (!write_ttf_file( "wine_langnames2.ttf", ttf_name2
))
7144 skip( "Failed to create ttf file for testing\n" );
7145 DeleteFileA( ttf_name
);
7149 if (!write_ttf_file( "wine_langnames3.ttf", ttf_name3
))
7151 skip( "Failed to create ttf file for testing\n" );
7152 DeleteFileA( ttf_name2
);
7153 DeleteFileA( ttf_name
);
7157 ret
= AddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7158 ok( ret
, "AddFontResourceEx() failed\n" );
7162 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7164 primary_family
= L
"Wine Lang Cond (en)";
7165 primary_fullname
= L
"Wine Lang Cond Reg (en)";
7169 primary_family
= name_cond_ja_w
;
7170 primary_fullname
= name_cond_ja_reg_w
;
7173 for (i
= 0; i
< 3; ++i
)
7175 /* check that lookup by preferred or WWS family / full names or postscript FontName doesn't work */
7177 strcpy( font
.lfFaceName
, "Wine Lang (en)" );
7178 memset( &efnd
, 0, sizeof(efnd
) );
7179 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7180 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7182 strcpy( font
.lfFaceName
, "Wine Lang Condensed Bold (ko)" );
7183 memset( &efnd
, 0, sizeof(efnd
) );
7184 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7185 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7187 wcscpy( font_w
.lfFaceName
, name_wws_ja_w
);
7188 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7189 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7190 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7192 strcpy( font
.lfFaceName
, "Reg WWS (zh-tw)" );
7193 memset( &efnd
, 0, sizeof(efnd
) );
7194 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7195 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7197 strcpy( font
.lfFaceName
, "Wine Lang (en) Reg WWS (en)" );
7198 memset( &efnd
, 0, sizeof(efnd
) );
7199 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7200 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7202 strcpy( font
.lfFaceName
, "WineLangNamesRegular" );
7203 memset( &efnd
, 0, sizeof(efnd
) );
7204 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7205 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7207 /* then, the primary ttf family name always works */
7209 wcscpy( font_w
.lfFaceName
, primary_family
);
7210 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7211 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7212 ok( efnd_w
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7214 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7216 wcscpy( font_w
.lfFaceName
, name_cond_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
);
7222 /* if there is no primary ttf family name, the english ttf name, or postscript FamilyName are used instead */
7224 strcpy( font
.lfFaceName
, "Wine_Lang_Names" );
7225 memset( &efnd
, 0, sizeof(efnd
) );
7226 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7228 ok( efnd
.total
== 1, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7230 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7232 /* same goes for ttf full names */
7234 wcscpy( font_w
.lfFaceName
, primary_fullname
);
7235 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7236 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7237 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7239 if (efnd_w
.total
>= 1)
7241 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
, primary_family
),
7242 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfLogFont
.lfFaceName
) );
7243 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfFullName
, primary_fullname
),
7244 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfFullName
) );
7245 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
? L
"Reg (en)" : L
"Reg (ja)" ),
7246 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfStyle
) );
7249 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7251 wcscpy( font_w
.lfFaceName
, name_cond_ja_reg_w
);
7252 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7253 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7254 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7257 wcscpy( font_w
.lfFaceName
, L
"Wine_Lang_Names_Regular" );
7258 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7259 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7260 ok( efnd_w
.total
== i
, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7262 while (efnd_w
.total
--)
7264 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
, efnd_w
.total
== 1 ? L
"Wine_Lang_Names" : primary_family
),
7265 "%d: (%d) unexpected lfFaceName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfLogFont
.lfFaceName
) );
7266 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
, L
"Wine_Lang_Names_Regular" ),
7267 "%d: (%d) unexpected elfFullName %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfFullName
) );
7268 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7269 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
, efnd_w
.total
== 1 ? L
"Regular" : L
"Reg (en)" ),
7270 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[efnd_w
.total
].elfStyle
) );
7272 ok( !wcscmp( (WCHAR
*)efnd_w
.elf
[0].elfStyle
, L
"Reg (ja)" ),
7273 "%d: (%d) unexpected elfStyle %s\n", i
, efnd_w
.total
, debugstr_w((WCHAR
*)efnd_w
.elf
[0].elfStyle
) );
7276 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7278 wcscpy( font_w
.lfFaceName
, name_cond_ja_reg_ja_w
);
7279 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7280 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7281 ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd_w
.total
);
7284 /* another language can also be used for lookup, if the primary langid isn't english, then
7285 english seems to have priority, otherwise or if english is already the primary langid,
7286 the family name with the smallest langid is used as secondary lookup language. */
7288 strcpy( font
.lfFaceName
, "Wine Lang Cond (zh-tw)" );
7289 memset( &efnd
, 0, sizeof(efnd
) );
7290 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7291 if (PRIMARYLANGID(GetSystemDefaultLangID()) == LANG_ENGLISH
)
7292 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7293 else /* (zh-tw) doesn't match here probably because there's an (en) name too */
7294 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7296 strcpy( font
.lfFaceName
, "Wine Lang Cond (en)" );
7297 memset( &efnd
, 0, sizeof(efnd
) );
7298 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7299 /* either because it's the primary language, or because it's a secondary */
7300 ok( efnd
.total
== min( 2, i
+ 1 ), "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7302 wcscpy( font_w
.lfFaceName
, L
"Wine Police d'\xe9" "criture (fr)" );
7303 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7304 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7305 /* as wine_langnames3.sfd does not specify (en) name, (fr) is preferred */
7306 if (i
== 2) ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7307 else ok( efnd_w
.total
== 0, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7309 /* case matching should not depend on the current locale */
7312 wcscpy( font_w
.lfFaceName
, L
"Wine POLICE D'\xc9" "CRITURE (fr)" );
7313 memset( &efnd_w
, 0, sizeof(efnd_w
) );
7314 EnumFontFamiliesExW( dc
, &font_w
, enum_fullname_data_proc_w
, (LPARAM
)&efnd_w
, 0 );
7315 ok( efnd_w
.total
== 1, "%d: EnumFontFamiliesExW unexpected count %u.\n", i
, efnd_w
.total
);
7318 strcpy( font
.lfFaceName
, "Wine Lang Cond (ko)" );
7319 memset( &efnd
, 0, sizeof(efnd
) );
7320 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7321 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7323 /* that doesn't apply to full names */
7325 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (zh-tw)" );
7326 memset( &efnd
, 0, sizeof(efnd
) );
7327 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7328 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7330 strcpy( font
.lfFaceName
, "Wine Lang Cond Reg (fr)" );
7331 memset( &efnd
, 0, sizeof(efnd
) );
7332 EnumFontFamiliesExA( dc
, &font
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0 );
7333 ok( efnd
.total
== 0, "%d: EnumFontFamiliesExA unexpected count %u.\n", i
, efnd
.total
);
7337 ret
= AddFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7338 ok( ret
, "AddFontResourceEx() failed\n" );
7342 ret
= AddFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7343 ok( ret
, "AddFontResourceEx() failed\n" );
7347 ret
= RemoveFontResourceExA( ttf_name3
, FR_PRIVATE
, 0 );
7348 ok( ret
, "RemoveFontResourceEx() failed\n" );
7350 DeleteFileA( ttf_name3
);
7352 ret
= RemoveFontResourceExA( ttf_name2
, FR_PRIVATE
, 0 );
7353 ok( ret
, "RemoveFontResourceEx() failed\n" );
7355 DeleteFileA( ttf_name2
);
7357 ret
= RemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
7358 ok( ret
, "RemoveFontResourceEx() failed\n" );
7360 DeleteFileA( ttf_name
);
7361 ReleaseDC( NULL
, dc
);
7366 USHORT majorVersion
;
7367 USHORT minorVersion
;
7371 USHORT advanceWidthMax
;
7372 SHORT minLeftSideBearing
;
7373 SHORT minRightSideBearing
;
7375 SHORT caretSlopeRise
;
7376 SHORT caretSlopeRun
;
7379 SHORT metricDataFormat
;
7380 SHORT numberOfHMetrics
;
7383 static void test_GetCharWidthInfo(void)
7386 HFONT hfont
, hfont_prev
;
7390 OUTLINETEXTMETRICA otm
;
7391 TT_Hori_Header hhea
;
7392 struct char_width_info
7396 SHORT minLeftSideBearing
, minRightSideBearing
;
7398 const char* face_list
[] = { "Symbol", "Ume Gothic", "MS Gothic" };
7400 if (!pGetCharWidthInfo
)
7402 win_skip("GetCharWidthInfo is unavailable\n");
7408 /* test default (System) font */
7409 memset(&info
, 0xaa, sizeof(info
));
7410 r
= pGetCharWidthInfo(hdc
, &info
);
7411 if (r
) /* win10 1803 succeeds */
7413 ok(info
.lsb
== 0, "expected 0, got %d\n", info
.lsb
);
7414 ok(info
.rsb
== 0, "expected 0, got %d\n", info
.rsb
);
7415 ok(info
.unk
== 0, "expected 0, got %d\n", info
.unk
);
7418 memset(&lf
, 0, sizeof(lf
));
7419 lf
.lfWeight
= FW_NORMAL
;
7420 lf
.lfCharSet
= ANSI_CHARSET
;
7421 strcpy(lf
.lfFaceName
, "Tahoma");
7422 hfont
= CreateFontIndirectA(&lf
);
7423 hfont_prev
= SelectObject(hdc
, hfont
);
7424 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7426 ret
= GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
);
7427 ok(ret
!= 0, "GetOutlineTextMetricsA failed\n");
7428 DeleteObject(SelectObject(hdc
, hfont_prev
));
7430 /* test Tahoma at the em square size */
7431 lf
.lfHeight
= -(int)otm
.otmEMSquare
;
7432 hfont
= CreateFontIndirectA(&lf
);
7433 hfont_prev
= SelectObject(hdc
, hfont
);
7434 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7436 ret
= GetFontData(hdc
, MS_MAKE_TAG('h','h','e','a'), 0, &hhea
, sizeof(hhea
));
7437 ok(ret
== sizeof(hhea
), "got %lu\n", ret
);
7438 minLeftSideBearing
= GET_BE_WORD(hhea
.minLeftSideBearing
);
7439 minRightSideBearing
= GET_BE_WORD(hhea
.minRightSideBearing
);
7441 memset(&info
, 0xaa, sizeof(info
));
7442 r
= pGetCharWidthInfo(hdc
, &info
);
7443 ok(r
, "GetCharWidthInfo failed\n");
7444 ok(info
.lsb
== minLeftSideBearing
, "expected %d, got %d\n", minLeftSideBearing
, info
.lsb
);
7445 ok(info
.rsb
== minRightSideBearing
, "expected %d, got %d\n", minRightSideBearing
, info
.rsb
);
7447 DeleteObject(SelectObject(hdc
, hfont_prev
));
7449 /* these values are scaled, try with smaller size */
7451 hfont
= CreateFontIndirectA(&lf
);
7452 hfont_prev
= SelectObject(hdc
, hfont
);
7453 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7455 memset(&info2
, 0xaa, sizeof(info2
));
7456 r
= pGetCharWidthInfo(hdc
, &info2
);
7457 ok(r
, "pGetCharWidthInfo failed\n");
7458 ok(info2
.lsb
== info
.lsb
/3, "expected %d, got %d\n", info
.lsb
/3, info2
.lsb
);
7459 ok(info2
.rsb
== info
.rsb
/3, "expected %d, got %d\n", info
.rsb
/3, info2
.rsb
);
7461 DeleteObject(SelectObject(hdc
, hfont_prev
));
7462 ReleaseDC(NULL
, hdc
);
7464 /* test with another mapping mode */
7466 SetMapMode(hdc
, MM_ISOTROPIC
);
7467 SetWindowExtEx(hdc
, 2, 2, NULL
);
7468 SetViewportExtEx(hdc
, 1, 1, NULL
);
7470 memset(pt
, 0, sizeof(pt
));
7471 pt
[0].y
= otm
.otmEMSquare
;
7474 memset(&lf
, 0, sizeof(lf
));
7475 lf
.lfWeight
= FW_NORMAL
;
7476 lf
.lfCharSet
= ANSI_CHARSET
;
7477 lf
.lfHeight
= -abs(pt
[0].y
);
7478 strcpy(lf
.lfFaceName
, "Tahoma");
7479 hfont
= CreateFontIndirectA(&lf
);
7480 hfont_prev
= SelectObject(hdc
, hfont
);
7481 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
7483 memset(&info2
, 0xaa, sizeof(info2
));
7484 r
= pGetCharWidthInfo(hdc
, &info2
);
7485 ok(r
, "GetCharWidthInfo failed\n");
7486 pt
[0].x
= info
.lsb
; pt
[0].y
= 0;
7487 pt
[1].x
= info
.rsb
; pt
[1].y
= 0;
7489 ok(pt
[0].x
== info2
.lsb
, "expected %ld, got %d\n", pt
[0].x
, info2
.lsb
);
7490 ok(pt
[1].x
== info2
.rsb
, "expected %ld, got %d\n", pt
[1].x
, info2
.rsb
);
7492 DeleteObject(SelectObject(hdc
, hfont_prev
));
7493 ReleaseDC(NULL
, hdc
);
7495 /* test with synthetic fonts */
7497 for (i
= 0; i
< ARRAY_SIZE(face_list
); i
++)
7499 const char* face
= face_list
[i
];
7500 if (!is_truetype_font_installed(face
))
7502 skip("%s is not installed\n", face
);
7505 memset(&lf
, 0, sizeof(lf
));
7506 lf
.lfWeight
= FW_NORMAL
;
7507 lf
.lfItalic
= FALSE
;
7508 lf
.lfCharSet
= DEFAULT_CHARSET
;
7510 strcpy(lf
.lfFaceName
, face
);
7511 hfont
= CreateFontIndirectA(&lf
);
7512 hfont_prev
= SelectObject(hdc
, hfont
);
7514 memset(&info
, 0xaa, sizeof(info
));
7515 r
= pGetCharWidthInfo(hdc
, &info
);
7516 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7518 /* test with synthetic bold */
7519 lf
.lfWeight
= FW_BOLD
;
7520 lf
.lfItalic
= FALSE
;
7521 hfont
= CreateFontIndirectA(&lf
);
7522 DeleteObject(SelectObject(hdc
, hfont
));
7524 memset(&info2
, 0xaa, sizeof(info2
));
7525 r
= pGetCharWidthInfo(hdc
, &info2
);
7526 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7527 ok(info
.lsb
== info2
.lsb
, "%s: expected %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7528 ok(info
.rsb
== info2
.rsb
, "%s: expected %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7530 /* test with synthetic italic */
7531 lf
.lfWeight
= FW_NORMAL
;
7533 hfont
= CreateFontIndirectA(&lf
);
7534 DeleteObject(SelectObject(hdc
, hfont
));
7536 memset(&info2
, 0xaa, sizeof(info2
));
7537 r
= pGetCharWidthInfo(hdc
, &info2
);
7538 ok(r
, "%s: GetCharWidthInfo failed\n", face
);
7539 todo_wine
ok(info
.lsb
> info2
.lsb
, "%s: expected less than %d, got %d\n", face
, info
.lsb
, info2
.lsb
);
7540 todo_wine
ok(info
.rsb
> info2
.rsb
, "%s: expected less than %d, got %d\n", face
, info
.rsb
, info2
.rsb
);
7541 DeleteObject(SelectObject(hdc
, hfont_prev
));
7544 ReleaseDC(NULL
, hdc
);
7547 static int CALLBACK
get_char_width_proc(const LOGFONTA
*lf
,
7548 const TEXTMETRICA
*tm
, DWORD type
, LPARAM ctx
)
7550 HFONT font
= CreateFontIndirectA(lf
);
7551 HDC dc
= GetDC(NULL
);
7559 SelectObject(dc
, font
);
7561 ret
= GetCharWidthFloatA(dc
, c
, c
, &f
);
7562 ok(ret
, "%s: GetCharWidthFloat() failed\n", lf
->lfFaceName
);
7563 ret
= GetCharWidth32A(dc
, c
, c
, &i32
);
7564 ok(ret
, "%s: GetCharWidth32A() failed\n", lf
->lfFaceName
);
7565 ret
= GetCharWidthA(dc
, c
, c
, &i
);
7566 ok(ret
, "%s: GetCharWidthA() failed\n", lf
->lfFaceName
);
7567 ok(i
== i32
, "%s: mismatched widths %d/%d\n", lf
->lfFaceName
, i
, i32
);
7568 ok((float)i
/ 16.0f
== f
, "%s: mismatched widths %d/%.8e\n", lf
->lfFaceName
, i
, f
);
7570 ret
= GetCharABCWidthsFloatA(dc
, c
, c
, &abcf
);
7571 ok(ret
, "%s: GetCharABCWidths() failed\n", lf
->lfFaceName
);
7572 if (GetCharABCWidthsA(dc
, c
, c
, &abc
))
7573 ok((float)abc
.abcB
== abcf
.abcfB
, "%s: mismatched widths %d/%.8e\n",
7574 lf
->lfFaceName
, abc
.abcB
, abcf
.abcfB
);
7576 ReleaseDC(NULL
, dc
);
7581 static void test_char_width(void)
7583 HDC dc
= GetDC(NULL
);
7586 lf
.lfCharSet
= DEFAULT_CHARSET
;
7587 EnumFontFamiliesExA(dc
, &lf
, get_char_width_proc
, 0, 0);
7589 ReleaseDC(NULL
, dc
);
7592 static void test_GetCharacterPlacement_kerning(void)
7595 HFONT hfont
, hfont_old
;
7598 DWORD count
, ret
, i
, size
, width
, width_kern
, idx
;
7600 GCP_RESULTSW result
;
7601 int kern
[30], pos
[30], pos_kern
[30], dx
[30], dx_kern
[30], kern_amount
;
7603 if (!is_font_installed("Arial"))
7605 skip("Arial is not installed, skipping the test\n");
7611 memset(&lf
, 0, sizeof(lf
));
7612 strcpy(lf
.lfFaceName
, "Arial");
7614 hfont
= CreateFontIndirectA(&lf
);
7615 ok(hfont
!= NULL
, "CreateFontIndirect failed\n");
7617 hfont_old
= SelectObject(hdc
, hfont
);
7619 count
= GetKerningPairsW(hdc
, 0, NULL
);
7620 kp
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*kp
));
7622 ret
= GetKerningPairsW(hdc
, count
, kp
);
7623 ok(ret
== count
, "got %lu, expected %lu\n", ret
, count
);
7625 size
= kern_amount
= idx
= 0;
7626 for (i
= 0; i
< count
; i
++)
7628 if (kp
[i
].wFirst
>= 'A' && kp
[i
].wFirst
<= 'z' &&
7629 kp
[i
].wSecond
>= 'A' && kp
[i
].wSecond
<= 'z')
7631 str
[size
++] = kp
[i
].wFirst
;
7632 str
[size
++] = kp
[i
].wSecond
;
7634 kern
[idx
] = kp
[i
].iKernAmount
;
7636 kern_amount
+= kp
[i
].iKernAmount
;
7637 if (size
>= ARRAY_SIZE(str
)) break;
7641 HeapFree(GetProcessHeap(), 0, kp
);
7645 memset(&result
, 0, sizeof(result
));
7646 result
.lStructSize
= sizeof(result
);
7647 result
.lpCaretPos
= pos
;
7649 result
.nGlyphs
= count
;
7650 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, 0);
7651 ok(ret
, "GetCharacterPlacement failed\n");
7652 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7653 width
= LOWORD(ret
);
7655 memset(&result
, 0, sizeof(result
));
7656 result
.lStructSize
= sizeof(result
);
7657 result
.lpCaretPos
= pos_kern
;
7658 result
.lpDx
= dx_kern
;
7659 result
.nGlyphs
= count
;
7660 ret
= GetCharacterPlacementW(hdc
, str
, count
, 0, &result
, GCP_USEKERNING
);
7661 ok(ret
, "GetCharacterPlacement failed\n");
7662 ok(result
.nGlyphs
== count
, "got %u\n", result
.nGlyphs
);
7663 width_kern
= LOWORD(ret
);
7665 if (width
== width_kern
)
7667 win_skip("GCP_USEKERNING is broken on this platform\n");
7671 ok(width
+ kern_amount
== width_kern
, "%ld + %d != %ld\n", width
, kern_amount
, width_kern
);
7673 kern_amount
= idx
= 0;
7674 for (i
= 0; i
< count
; i
+= 3, idx
++)
7676 ok(pos
[i
] + kern_amount
== pos_kern
[i
], "%ld: %d + %d != %d\n", i
, pos
[i
], kern_amount
, pos_kern
[i
]);
7677 kern_amount
+= kern
[idx
];
7678 ok(pos
[i
+1] + kern_amount
== pos_kern
[i
+1], "%ld: %d + %d != %d\n", i
, pos
[i
+1], kern_amount
, pos_kern
[i
+1]);
7679 ok(pos
[i
+2] + kern_amount
== pos_kern
[i
+2], "%ld: %d + %d != %d\n", i
, pos
[i
+2], kern_amount
, pos_kern
[i
+2]);
7681 ok(dx
[i
] + kern
[idx
] == dx_kern
[i
], "%ld: %d + %d != %d\n", i
, dx
[i
], kern
[idx
], dx_kern
[i
]);
7682 ok(dx
[i
+1] == dx_kern
[i
+1], "%ld: %d != %d\n", i
, dx
[i
+1], dx_kern
[i
+1]);
7683 ok(dx
[i
+2] == dx_kern
[i
+2], "%ld: %d != %d\n", i
, dx
[i
+2], dx_kern
[i
+2]);
7687 SelectObject(hdc
, hfont_old
);
7688 DeleteObject(hfont
);
7692 static void test_select_object(void)
7694 HFONT hfont
, old_font
;
7697 memset(&lf
, 0, sizeof lf
);
7699 lf
.lfCharSet
= ANSI_CHARSET
;
7700 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
7701 lf
.lfWeight
= FW_DONTCARE
;
7704 lf
.lfQuality
= DEFAULT_QUALITY
;
7706 lstrcpyA(lf
.lfFaceName
, "Arial");
7707 hfont
= create_font("Arial", &lf
);
7709 SetLastError(0xdeadbeef);
7710 old_font
= SelectObject(NULL
, hfont
);
7711 ok(!old_font
, "SelectObject returned %p\n", old_font
);
7712 ok(GetLastError() == ERROR_INVALID_HANDLE
, "GetLastError() = %lu\n",
7715 DeleteObject(hfont
);
7718 static void test_GetOutlineTextMetrics_subst(void)
7720 OUTLINETEXTMETRICA
*otm
;
7722 HFONT hfont
, hfont_old
;
7725 char face_name
[LF_FACESIZE
];
7726 const char* family_name
;
7728 if (!is_font_installed("MS SHELL DLG"))
7730 skip("MS Shell Dlg is not installed\n");
7735 memset(&lf
, 0, sizeof(lf
));
7736 strcpy(lf
.lfFaceName
, "MS SHELL DLG");
7737 lf
.lfCharSet
= DEFAULT_CHARSET
;
7738 hfont
= CreateFontIndirectA(&lf
);
7739 ok(hfont
!= NULL
, "failed to create a font\n");
7740 hfont_old
= SelectObject(hdc
, hfont
);
7743 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
7744 ok(ret
, "GetTextFace failed\n");
7745 ok(!lstrcmpiA(lf
.lfFaceName
, face_name
), "expected %s, got %s\n", lf
.lfFaceName
, face_name
);
7747 ret
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
7748 otm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ret
);
7749 ret
= GetOutlineTextMetricsA(hdc
, ret
, otm
);
7750 ok(ret
!= 0, "GetOutlineTextMetrics failed\n");
7753 family_name
= (const char*)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
7754 ok(lstrcmpiA(lf
.lfFaceName
, family_name
), "expected a real family name (e.g. Tahoma), got %s\n", family_name
);
7756 HeapFree(GetProcessHeap(), 0, otm
);
7757 SelectObject(hdc
, hfont_old
);
7758 DeleteObject(hfont
);
7765 static const char *test_names
[] =
7767 "AddFontMemResource",
7769 char path_name
[MAX_PATH
];
7770 STARTUPINFOA startup
;
7776 argc
= winetest_get_mainargs(&argv
);
7779 if (!strcmp(argv
[2], "AddFontMemResource"))
7780 test_AddFontMemResource();
7787 test_outline_font();
7788 test_bitmap_font_metrics();
7789 test_GdiGetCharDimensions();
7790 test_GetCharABCWidths();
7791 test_text_extents();
7792 test_GetGlyphIndices();
7793 test_GetKerningPairs();
7794 test_GetOutlineTextMetrics();
7795 test_GetOutlineTextMetrics_subst();
7796 test_SetTextJustification();
7797 test_TranslateCharsetInfo();
7798 test_font_charset();
7799 test_GdiGetCodePage();
7800 test_GetFontUnicodeRanges();
7801 test_nonexistent_font();
7803 test_height_selection();
7805 test_EnumFonts_subst();
7807 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
7808 * I'd like to avoid them in this test.
7810 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
7811 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
7812 if (is_truetype_font_installed("Arial Black") &&
7813 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
7815 test_EnumFontFamilies("", ANSI_CHARSET
);
7816 test_EnumFontFamilies("", SYMBOL_CHARSET
);
7817 test_EnumFontFamilies("", DEFAULT_CHARSET
);
7820 skip("Arial Black or Symbol/Wingdings is not installed\n");
7821 test_EnumFontFamiliesEx_default_charset();
7822 test_GetTextMetrics();
7823 test_RealizationInfo();
7825 test_GetGlyphOutline();
7826 test_GetTextMetrics2("Tahoma", -11);
7827 test_GetTextMetrics2("Tahoma", -55);
7828 test_GetTextMetrics2("Tahoma", -110);
7829 test_GetTextMetrics2("Arial", -11);
7830 test_GetTextMetrics2("Arial", -55);
7831 test_GetTextMetrics2("Arial", -110);
7832 test_GetCharacterPlacement();
7833 test_GetCharacterPlacement_kerning();
7834 test_GetCharWidthInfo();
7835 test_CreateFontIndirect();
7836 test_CreateFontIndirectEx();
7840 test_east_asian_font_selection();
7842 test_vertical_order();
7843 test_GetCharWidth32();
7844 test_fake_bold_font();
7845 test_bitmap_font_glyph_index();
7846 test_GetCharWidthI();
7851 test_select_object();
7853 /* These tests should be last test until RemoveFontResource
7854 * is properly implemented.
7856 test_vertical_font();
7857 test_CreateScalableFontResource();
7859 winetest_get_mainargs( &argv
);
7860 for (i
= 0; i
< ARRAY_SIZE(test_names
); ++i
)
7862 PROCESS_INFORMATION info
;
7864 memset(&startup
, 0, sizeof(startup
));
7865 startup
.cb
= sizeof(startup
);
7866 sprintf(path_name
, "%s font %s", argv
[0], test_names
[i
]);
7867 ok(CreateProcessA(NULL
, path_name
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &startup
, &info
),
7868 "CreateProcess failed.\n");
7869 wait_child_process(info
.hProcess
);
7870 CloseHandle(info
.hProcess
);
7871 CloseHandle(info
.hThread
);