2 * Unit test suite for fonts
4 * Copyright 2002 Mike McCormack
5 * Copyright 2004 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/heap.h"
32 #include "wine/test.h"
34 static inline BOOL
match_off_by_n(int a
, int b
, unsigned int n
)
36 return abs(a
- b
) <= n
;
38 #define match_off_by_1(a, b, exact) match_off_by_n((a), (b), (exact) ? 0 : 1)
39 #define near_match(a, b) match_off_by_n((a), (b), 6)
40 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
42 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
43 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
44 static BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
45 static BOOL (WINAPI
*pGetCharABCWidthsA
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
46 static BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
47 static BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
48 static BOOL (WINAPI
*pGetCharWidth32A
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
49 static BOOL (WINAPI
*pGetCharWidth32W
)(HDC hdc
, UINT first
, UINT last
, LPINT buffer
);
50 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
51 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
52 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
53 static BOOL (WINAPI
*pGetTextExtentExPointI
)(HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
54 LPINT nfit
, LPINT dxs
, LPSIZE size
);
55 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
56 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDVA
*);
57 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
58 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
59 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
60 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
61 static BOOL (WINAPI
*pGetFontRealizationInfo
)(HDC hdc
, DWORD
*);
62 static BOOL (WINAPI
*pGetFontFileInfo
)(DWORD
, DWORD
, void *, DWORD
, DWORD
*);
63 static BOOL (WINAPI
*pGetFontFileData
)(DWORD
, DWORD
, ULONGLONG
, void *, DWORD
);
65 static HMODULE hgdi32
= 0;
66 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
67 static WORD system_lang_id
;
69 #ifdef WORDS_BIGENDIAN
70 #define GET_BE_WORD(x) (x)
71 #define GET_BE_DWORD(x) (x)
73 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
74 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
77 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
78 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
79 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
80 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
81 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
82 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
84 static void init(void)
86 hgdi32
= GetModuleHandleA("gdi32.dll");
88 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
89 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
90 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
91 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
92 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
93 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
94 pGetCharWidth32A
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32A");
95 pGetCharWidth32W
= (void *)GetProcAddress(hgdi32
, "GetCharWidth32W");
96 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
97 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
98 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
99 pGetTextExtentExPointI
= (void *)GetProcAddress(hgdi32
, "GetTextExtentExPointI");
100 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
101 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
102 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
103 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
104 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
105 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
106 pGetFontRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GetFontRealizationInfo");
107 pGetFontFileInfo
= (void *)GetProcAddress(hgdi32
, "GetFontFileInfo");
108 pGetFontFileData
= (void *)GetProcAddress(hgdi32
, "GetFontFileData");
110 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
113 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
115 if (type
!= TRUETYPE_FONTTYPE
) return 1;
120 static BOOL
is_truetype_font_installed(const char *name
)
125 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
132 static INT CALLBACK
is_font_installed_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
137 static BOOL
is_font_installed(const char *name
)
142 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
149 static void *get_res_data(const char *fontname
, DWORD
*rsrc_size
)
154 rsrc
= FindResourceA(GetModuleHandleA(NULL
), fontname
, (LPCSTR
)RT_RCDATA
);
155 if (!rsrc
) return NULL
;
157 rsrc_data
= LockResource(LoadResource(GetModuleHandleA(NULL
), rsrc
));
158 if (!rsrc_data
) return NULL
;
160 *rsrc_size
= SizeofResource(GetModuleHandleA(NULL
), rsrc
);
161 if (!*rsrc_size
) return NULL
;
166 static BOOL
write_tmp_file( const void *data
, DWORD
*size
, char *tmp_name
)
168 char tmp_path
[MAX_PATH
];
172 GetTempPathA(MAX_PATH
, tmp_path
);
173 GetTempFileNameA(tmp_path
, "ttf", 0, tmp_name
);
175 hfile
= CreateFileA(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
176 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
178 ret
= WriteFile(hfile
, data
, *size
, size
, NULL
);
184 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
189 rsrc_data
= get_res_data( fontname
, &rsrc_size
);
190 if (!rsrc_data
) return FALSE
;
192 return write_tmp_file( rsrc_data
, &rsrc_size
, tmp_name
);
195 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
203 ret
= GetObjectA(hfont
, sizeof(getobj_lf
), &getobj_lf
);
204 /* NT4 tries to be clever and only returns the minimum length */
205 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
207 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
208 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
209 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
210 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
211 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
212 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
213 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
214 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
215 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
216 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
217 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
218 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
219 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
220 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
221 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
222 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
223 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
224 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
225 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
226 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
227 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
228 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
229 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
230 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
231 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
232 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
233 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
234 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
237 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
239 HFONT hfont
= CreateFontIndirectA(lf
);
240 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
242 check_font(test
, lf
, hfont
);
246 static void test_logfont(void)
251 memset(&lf
, 0, sizeof lf
);
253 lf
.lfCharSet
= ANSI_CHARSET
;
254 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
255 lf
.lfWeight
= FW_DONTCARE
;
258 lf
.lfQuality
= DEFAULT_QUALITY
;
260 lstrcpyA(lf
.lfFaceName
, "Arial");
261 hfont
= create_font("Arial", &lf
);
264 memset(&lf
, 'A', sizeof(lf
));
265 hfont
= CreateFontIndirectA(&lf
);
266 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
268 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
269 check_font("AAA...", &lf
, hfont
);
273 static INT CALLBACK
font_enum_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
275 if (type
& RASTER_FONTTYPE
)
277 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
279 return 0; /* stop enumeration */
282 return 1; /* continue enumeration */
285 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
287 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
288 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
289 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
290 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
291 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
292 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
293 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
294 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
295 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
296 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
297 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
298 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
299 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
300 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
301 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
302 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
303 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
304 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
305 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
306 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
309 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
310 LONG lfWidth
, const char *test_str
,
311 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
312 const SIZE
*size_orig
, INT width_of_A_orig
,
313 INT scale_x
, INT scale_y
)
316 OUTLINETEXTMETRICA otm
;
319 INT width_of_A
, cx
, cy
;
325 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
327 GetObjectA(hfont
, sizeof(lf
), &lf
);
329 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
331 otm
.otmSize
= sizeof(otm
) / 2;
332 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
333 ok(ret
== sizeof(otm
)/2 /* XP */ ||
334 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
336 memset(&otm
, 0x1, sizeof(otm
));
337 otm
.otmSize
= sizeof(otm
);
338 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
339 ok(ret
== sizeof(otm
) /* XP */ ||
340 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
342 memset(&tm
, 0x2, sizeof(tm
));
343 ret
= GetTextMetricsA(hdc
, &tm
);
344 ok(ret
, "GetTextMetricsA failed\n");
345 /* the structure size is aligned */
346 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
348 ok(0, "tm != otm\n");
349 compare_tm(&tm
, &otm
.otmTextMetrics
);
352 tm
= otm
.otmTextMetrics
;
353 if (0) /* these metrics are scaled too, but with rounding errors */
355 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
356 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
358 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
359 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
360 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
361 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
362 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
363 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
367 ret
= GetTextMetricsA(hdc
, &tm
);
368 ok(ret
, "GetTextMetricsA failed\n");
371 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
372 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
373 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
374 lfHeight
, scale_x
, scale_y
, cx
, cy
);
375 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
376 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
377 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
378 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
379 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
381 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
385 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
388 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
390 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
392 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
393 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
395 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
397 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
);
400 /* Test how GDI scales bitmap font metrics */
401 static void test_bitmap_font(void)
403 static const char test_str
[11] = "Test String";
406 HFONT hfont
, old_hfont
;
409 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
411 hdc
= CreateCompatibleDC(0);
413 /* "System" has only 1 pixel size defined, otherwise the test breaks */
414 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
418 trace("no bitmap fonts were found, skipping the test\n");
422 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
424 height_orig
= bitmap_lf
.lfHeight
;
425 lfWidth
= bitmap_lf
.lfWidth
;
427 hfont
= create_font("bitmap", &bitmap_lf
);
428 old_hfont
= SelectObject(hdc
, hfont
);
429 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
430 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
431 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
432 SelectObject(hdc
, old_hfont
);
435 bitmap_lf
.lfHeight
= 0;
436 bitmap_lf
.lfWidth
= 4;
437 hfont
= create_font("bitmap", &bitmap_lf
);
438 old_hfont
= SelectObject(hdc
, hfont
);
439 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
440 SelectObject(hdc
, old_hfont
);
443 bitmap_lf
.lfHeight
= height_orig
;
444 bitmap_lf
.lfWidth
= lfWidth
;
446 /* test fractional scaling */
447 for (i
= 1; i
<= height_orig
* 6; i
++)
451 bitmap_lf
.lfHeight
= i
;
452 hfont
= create_font("fractional", &bitmap_lf
);
453 scale
= (i
+ height_orig
- 1) / height_orig
;
454 nearest_height
= scale
* height_orig
;
455 /* Only jump to the next height if the difference <= 25% original height */
456 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
457 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
458 so we'll not test this particular height. */
459 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
460 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
461 old_hfont
= SelectObject(hdc
, hfont
);
462 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
463 SelectObject(hdc
, old_hfont
);
467 /* test integer scaling 3x2 */
468 bitmap_lf
.lfHeight
= height_orig
* 2;
469 bitmap_lf
.lfWidth
*= 3;
470 hfont
= create_font("3x2", &bitmap_lf
);
471 old_hfont
= SelectObject(hdc
, hfont
);
472 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
473 SelectObject(hdc
, old_hfont
);
476 /* test integer scaling 3x3 */
477 bitmap_lf
.lfHeight
= height_orig
* 3;
478 bitmap_lf
.lfWidth
= 0;
479 hfont
= create_font("3x3", &bitmap_lf
);
480 old_hfont
= SelectObject(hdc
, hfont
);
481 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
482 SelectObject(hdc
, old_hfont
);
488 /* Test how GDI scales outline font metrics */
489 static void test_outline_font(void)
491 static const char test_str
[11] = "Test String";
494 HFONT hfont
, old_hfont
, old_hfont_2
;
495 OUTLINETEXTMETRICA otm
;
497 INT width_orig
, height_orig
, lfWidth
;
500 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
504 if (!is_truetype_font_installed("Arial"))
506 skip("Arial is not installed\n");
510 hdc
= CreateCompatibleDC(0);
512 memset(&lf
, 0, sizeof(lf
));
513 strcpy(lf
.lfFaceName
, "Arial");
515 hfont
= create_font("outline", &lf
);
516 old_hfont
= SelectObject(hdc
, hfont
);
517 otm
.otmSize
= sizeof(otm
);
518 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
519 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
520 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
522 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
523 SelectObject(hdc
, old_hfont
);
526 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
527 lf
.lfHeight
= otm
.otmEMSquare
;
528 lf
.lfHeight
= -lf
.lfHeight
;
529 hfont
= create_font("outline", &lf
);
530 old_hfont
= SelectObject(hdc
, hfont
);
531 otm
.otmSize
= sizeof(otm
);
532 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
533 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
534 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
535 SelectObject(hdc
, old_hfont
);
538 height_orig
= otm
.otmTextMetrics
.tmHeight
;
539 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
541 /* test integer scaling 3x2 */
542 lf
.lfHeight
= height_orig
* 2;
543 lf
.lfWidth
= lfWidth
* 3;
544 hfont
= create_font("3x2", &lf
);
545 old_hfont
= SelectObject(hdc
, hfont
);
546 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
547 SelectObject(hdc
, old_hfont
);
550 /* test integer scaling 3x3 */
551 lf
.lfHeight
= height_orig
* 3;
552 lf
.lfWidth
= lfWidth
* 3;
553 hfont
= create_font("3x3", &lf
);
554 old_hfont
= SelectObject(hdc
, hfont
);
555 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
556 SelectObject(hdc
, old_hfont
);
559 /* test integer scaling 1x1 */
560 lf
.lfHeight
= height_orig
* 1;
561 lf
.lfWidth
= lfWidth
* 1;
562 hfont
= create_font("1x1", &lf
);
563 old_hfont
= SelectObject(hdc
, hfont
);
564 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
565 SelectObject(hdc
, old_hfont
);
568 /* test integer scaling 1x1 */
569 lf
.lfHeight
= height_orig
;
571 hfont
= create_font("1x1", &lf
);
572 old_hfont
= SelectObject(hdc
, hfont
);
573 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
575 /* with an identity matrix */
576 memset(&gm
, 0, sizeof(gm
));
577 SetLastError(0xdeadbeef);
578 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
579 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
581 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
582 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
583 /* with a custom matrix */
584 memset(&gm
, 0, sizeof(gm
));
585 SetLastError(0xdeadbeef);
586 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
587 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
588 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
589 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
590 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
592 /* Test that changing the DC transformation affects only the font
593 * selected on this DC and doesn't affect the same font selected on
596 hdc_2
= CreateCompatibleDC(0);
597 old_hfont_2
= SelectObject(hdc_2
, hfont
);
598 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
600 SetMapMode(hdc
, MM_ANISOTROPIC
);
602 /* font metrics on another DC should be unchanged */
603 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
605 /* test restrictions of compatibility mode GM_COMPATIBLE */
606 /* part 1: rescaling only X should not change font scaling on screen.
607 So compressing the X axis by 2 is not done, and this
608 appears as X scaling of 2 that no one requested. */
609 SetWindowExtEx(hdc
, 100, 100, NULL
);
610 SetViewportExtEx(hdc
, 50, 100, NULL
);
611 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
612 /* font metrics on another DC should be unchanged */
613 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
615 /* part 2: rescaling only Y should change font scaling.
616 As also X is scaled by a factor of 2, but this is not
617 requested by the DC transformation, we get a scaling factor
618 of 2 in the X coordinate. */
619 SetViewportExtEx(hdc
, 100, 200, NULL
);
620 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
621 /* font metrics on another DC should be unchanged */
622 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
624 /* restore scaling */
625 SetMapMode(hdc
, MM_TEXT
);
627 /* font metrics on another DC should be unchanged */
628 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
630 SelectObject(hdc_2
, old_hfont_2
);
633 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
635 SelectObject(hdc
, old_hfont
);
638 skip("GM_ADVANCED is not supported on this platform\n");
649 SetLastError(0xdeadbeef);
650 ret
= SetWorldTransform(hdc
, &xform
);
651 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
653 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
655 /* with an identity matrix */
656 memset(&gm
, 0, sizeof(gm
));
657 SetLastError(0xdeadbeef);
658 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
659 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
660 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
661 pt
.x
= width_orig
; pt
.y
= 0;
663 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
664 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
665 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
666 /* with a custom matrix */
667 memset(&gm
, 0, sizeof(gm
));
668 SetLastError(0xdeadbeef);
669 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
670 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
671 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
672 pt
.x
= width_orig
; pt
.y
= 0;
674 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
675 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
676 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
678 SetLastError(0xdeadbeef);
679 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
680 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
682 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
684 /* with an identity matrix */
685 memset(&gm
, 0, sizeof(gm
));
686 SetLastError(0xdeadbeef);
687 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
688 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
689 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
690 pt
.x
= width_orig
; pt
.y
= 0;
692 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
693 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
694 /* with a custom matrix */
695 memset(&gm
, 0, sizeof(gm
));
696 SetLastError(0xdeadbeef);
697 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
698 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
699 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
700 pt
.x
= width_orig
; pt
.y
= 0;
702 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
703 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
705 SetLastError(0xdeadbeef);
706 ret
= SetMapMode(hdc
, MM_TEXT
);
707 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
709 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
711 /* with an identity matrix */
712 memset(&gm
, 0, sizeof(gm
));
713 SetLastError(0xdeadbeef);
714 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
715 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
716 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
717 pt
.x
= width_orig
; pt
.y
= 0;
719 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
720 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
721 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
722 /* with a custom matrix */
723 memset(&gm
, 0, sizeof(gm
));
724 SetLastError(0xdeadbeef);
725 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
726 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
727 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
728 pt
.x
= width_orig
; pt
.y
= 0;
730 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
731 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
732 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
734 SelectObject(hdc
, old_hfont
);
739 static INT CALLBACK
find_font_proc(const LOGFONTA
*elf
, const TEXTMETRICA
*ntm
, DWORD type
, LPARAM lParam
)
741 LOGFONTA
*lf
= (LOGFONTA
*)lParam
;
743 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
746 return 0; /* stop enumeration */
748 return 1; /* continue enumeration */
751 static BOOL
is_CJK(void)
753 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
756 #define FH_SCALE 0x80000000
757 static void test_bitmap_font_metrics(void)
759 static const WORD skip_rtl
[] = {LANG_ARABIC
, LANG_HEBREW
, 0};
760 static const struct font_data
762 const char face_name
[LF_FACESIZE
];
763 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
764 int ave_char_width
, max_char_width
, dpi
;
765 BYTE first_char
, last_char
, def_char
, break_char
;
767 const WORD
*skip_lang_id
;
771 { "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 },
772 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
773 { "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 },
774 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
775 { "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 },
776 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
777 { "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 },
778 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
779 { "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 },
780 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
782 { "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 },
783 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
784 { "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 },
785 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
786 { "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 },
787 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
788 { "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 },
789 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
790 { "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 },
791 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
793 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
794 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
795 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
796 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
797 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
798 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
799 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
800 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
801 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
802 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
803 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
804 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
805 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
806 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
807 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
808 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
810 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
811 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
812 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
813 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
814 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
815 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
816 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
817 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
818 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
819 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
820 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
821 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
823 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
824 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
825 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
826 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
827 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
828 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
829 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
830 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
831 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
832 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
833 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
834 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
835 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
836 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
837 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
838 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
839 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
841 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
842 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
843 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
844 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
845 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
846 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
847 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
848 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
849 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
850 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
851 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
853 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
854 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
855 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
857 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
858 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
859 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
861 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
862 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
863 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
865 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
866 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
868 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
869 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
870 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
871 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
872 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
873 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
874 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
875 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
876 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
877 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
878 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, skip_rtl
},
879 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
880 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
881 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
882 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, skip_rtl
},
883 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
884 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
885 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
886 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, skip_rtl
},
887 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
888 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
890 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
891 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
892 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
893 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
894 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
895 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
896 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
897 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
898 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
899 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
900 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
901 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
903 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
904 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
905 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
907 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
909 /* FIXME: add "Terminal" */
911 static const int font_log_pixels
[] = { 96, 120 };
914 HFONT hfont
, old_hfont
;
916 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
917 char face_name
[LF_FACESIZE
];
920 trace("system language id %04x\n", system_lang_id
);
922 expected_cs
= GetACP();
923 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
925 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
928 expected_cs
= csi
.ciCharset
;
929 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
931 hdc
= CreateCompatibleDC(0);
932 ok(hdc
!= NULL
, "failed to create hdc\n");
934 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
935 GetDeviceCaps(hdc
, LOGPIXELSY
));
937 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
940 for (i
= 0; i
< sizeof(font_log_pixels
)/sizeof(font_log_pixels
[0]); i
++)
942 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
946 font_res
= font_log_pixels
[i
];
949 trace("best font resolution is %d\n", font_res
);
951 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
955 memset(&lf
, 0, sizeof(lf
));
957 height
= fd
[i
].height
& ~FH_SCALE
;
958 lf
.lfHeight
= height
;
959 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
961 for(bit
= 0; bit
< 32; bit
++)
969 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
970 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
972 lf
.lfCharSet
= csi
.ciCharset
;
973 ret
= EnumFontFamiliesExA(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
974 if (fd
[i
].height
& FH_SCALE
)
975 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
978 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
980 todo_wine_if (ret
) /* FIXME: Remove once Wine is fixed */
981 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
984 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
987 hfont
= create_font(lf
.lfFaceName
, &lf
);
988 old_hfont
= SelectObject(hdc
, hfont
);
990 SetLastError(0xdeadbeef);
991 ret
= GetTextFaceA(hdc
, sizeof(face_name
), face_name
);
992 ok(ret
, "GetTextFace error %u\n", GetLastError());
994 if (strcmp(face_name
, fd
[i
].face_name
) != 0)
996 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
997 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
998 SelectObject(hdc
, old_hfont
);
1003 memset(&gm
, 0, sizeof(gm
));
1004 SetLastError(0xdeadbeef);
1005 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1007 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
1008 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
1011 bRet
= GetTextMetricsA(hdc
, &tm
);
1012 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
1014 SetLastError(0xdeadbeef);
1015 ret
= GetTextCharset(hdc
);
1016 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
1017 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
1019 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
1021 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
1022 trace("expected %s, height %d scaled_height %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
1024 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1027 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1028 if (fd
[i
].skip_lang_id
)
1032 while(!skipme
&& fd
[i
].skip_lang_id
[si
])
1033 if (fd
[i
].skip_lang_id
[si
++] == system_lang_id
)
1038 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
1039 if (fd
[i
].height
& FH_SCALE
)
1040 ok(tm
.tmHeight
== fd
[i
].scaled_height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmHeight
, fd
[i
].scaled_height
);
1042 ok(tm
.tmHeight
== fd
[i
].height
, "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmHeight
, fd
[i
].height
);
1043 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
1044 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
1045 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1046 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1047 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
1048 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
1049 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
1050 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
1051 make default char test fail */
1052 if (tm
.tmCharSet
== lf
.lfCharSet
)
1053 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
1054 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
1055 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
);
1057 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
1058 that make the max width bigger */
1059 if ((strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
) && tm
.tmDigitizedAspectX
== 96)
1060 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd
[i
].face_name
, height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
1063 skip("Skipping font metrics test for system langid 0x%x\n",
1066 SelectObject(hdc
, old_hfont
);
1067 DeleteObject(hfont
);
1074 static void test_GdiGetCharDimensions(void)
1080 LONG avgwidth
, height
;
1081 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1083 if (!pGdiGetCharDimensions
)
1085 win_skip("GdiGetCharDimensions not available on this platform\n");
1089 hdc
= CreateCompatibleDC(NULL
);
1091 GetTextExtentPointA(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1092 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1094 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1095 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1096 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1098 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1099 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1101 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1102 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1105 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1106 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1107 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1112 static int CALLBACK
create_font_proc(const LOGFONTA
*lpelfe
,
1113 const TEXTMETRICA
*lpntme
,
1114 DWORD FontType
, LPARAM lParam
)
1116 if (FontType
& TRUETYPE_FONTTYPE
)
1120 hfont
= CreateFontIndirectA(lpelfe
);
1123 *(HFONT
*)lParam
= hfont
;
1131 static void ABCWidths_helper(const char* description
, HDC hdc
, WORD
*glyphs
, const ABC
*base_abci
, const ABC
*base_abcw
, const ABCFLOAT
*base_abcf
)
1137 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1138 ok(ret
, "%s: GetCharABCWidthsI should have succeeded\n", description
);
1139 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1140 ok(abc
->abcA
* base_abci
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1141 ok(abc
->abcC
* base_abci
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1143 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abc
);
1144 ok(ret
, "%s: GetCharABCWidthsW should have succeeded\n", description
);
1145 ok ((INT
)abc
->abcB
> 0, "%s: abcB should be positive\n", description
);
1146 ok(abc
->abcA
* base_abcw
->abcA
>= 0, "%s: abcA's sign should be unchanged\n", description
);
1147 ok(abc
->abcC
* base_abcw
->abcC
>= 0, "%s: abcC's sign should be unchanged\n", description
);
1149 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1150 ok(ret
, "%s: GetCharABCWidthsFloatW should have succeeded\n", description
);
1151 ok (abcf
->abcfB
> 0.0, "%s: abcfB should be positive\n", description
);
1152 ok(abcf
->abcfA
* base_abcf
->abcfA
>= 0.0, "%s: abcfA's sign should be unchanged\n", description
);
1153 ok(abcf
->abcfC
* base_abcf
->abcfC
>= 0.0, "%s: abcfC's sign should be unchanged\n", description
);
1156 static void test_GetCharABCWidths(void)
1158 static const WCHAR str
[] = {'i',0};
1182 {0xffffff, 0xffffff},
1183 {0x1000000, 0x1000000},
1184 {0xffffff, 0x1000000},
1185 {0xffffffff, 0xffffffff},
1193 BOOL r
[sizeof range
/ sizeof range
[0]];
1196 {ANSI_CHARSET
, 0x30, 0x30,
1197 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1198 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1199 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1200 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1201 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1202 {GB2312_CHARSET
, 0x8141, 0x4e04,
1203 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1204 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1205 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1209 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1211 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1215 memset(&lf
, 0, sizeof(lf
));
1216 strcpy(lf
.lfFaceName
, "System");
1219 hfont
= CreateFontIndirectA(&lf
);
1221 hfont
= SelectObject(hdc
, hfont
);
1223 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1224 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1226 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1227 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1229 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1230 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1232 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1233 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1235 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1236 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1238 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1239 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1241 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1242 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1244 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1245 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1247 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1248 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1250 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1251 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1253 hfont
= SelectObject(hdc
, hfont
);
1254 DeleteObject(hfont
);
1256 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1260 UINT code
= 0x41, j
;
1262 lf
.lfFaceName
[0] = '\0';
1263 lf
.lfCharSet
= c
[i
].cs
;
1264 lf
.lfPitchAndFamily
= 0;
1265 if (EnumFontFamiliesExA(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1267 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1271 memset(a
, 0, sizeof a
);
1272 memset(w
, 0, sizeof w
);
1273 hfont
= SelectObject(hdc
, hfont
);
1274 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1275 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1276 memcmp(a
, w
, sizeof a
) == 0,
1277 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1279 memset(a
, 0xbb, sizeof a
);
1280 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1281 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1282 memset(full
, 0xcc, sizeof full
);
1283 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1284 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1285 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1286 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1288 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1290 memset(full
, 0xdd, sizeof full
);
1291 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1292 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1293 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1296 UINT last
= range
[j
].last
- range
[j
].first
;
1297 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1298 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1299 "GetCharABCWidthsA %x should match. codepage = %u\n",
1300 range
[j
].last
, c
[i
].cs
);
1304 hfont
= SelectObject(hdc
, hfont
);
1305 DeleteObject(hfont
);
1308 memset(&lf
, 0, sizeof(lf
));
1309 strcpy(lf
.lfFaceName
, "Tahoma");
1311 hfont
= CreateFontIndirectA(&lf
);
1313 /* test empty glyph's metrics */
1314 hfont
= SelectObject(hdc
, hfont
);
1315 ret
= pGetCharABCWidthsFloatW(hdc
, ' ', ' ', abcf
);
1316 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1317 ok(abcf
[0].abcfB
== 1.0, "got %f\n", abcf
[0].abcfB
);
1318 ret
= pGetCharABCWidthsW(hdc
, ' ', ' ', abcw
);
1319 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1320 ok(abcw
[0].abcB
== 1, "got %u\n", abcw
[0].abcB
);
1322 /* 1) prepare unrotated font metrics */
1323 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abcw
);
1324 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1325 DeleteObject(SelectObject(hdc
, hfont
));
1327 /* 2) get rotated font metrics */
1328 lf
.lfEscapement
= lf
.lfOrientation
= 900;
1329 hfont
= CreateFontIndirectA(&lf
);
1330 hfont
= SelectObject(hdc
, hfont
);
1331 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1332 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1334 /* 3) compare ABC results */
1335 ok(match_off_by_1(abcw
[0].abcA
, abc
[0].abcA
, FALSE
),
1336 "got %d, expected %d (A)\n", abc
[0].abcA
, abcw
[0].abcA
);
1337 ok(match_off_by_1(abcw
[0].abcB
, abc
[0].abcB
, FALSE
),
1338 "got %d, expected %d (B)\n", abc
[0].abcB
, abcw
[0].abcB
);
1339 ok(match_off_by_1(abcw
[0].abcC
, abc
[0].abcC
, FALSE
),
1340 "got %d, expected %d (C)\n", abc
[0].abcC
, abcw
[0].abcC
);
1342 DeleteObject(SelectObject(hdc
, hfont
));
1344 /* test abcA == gmptGlyphOrigin.x && abcB == gmBlackBoxX
1345 in various widths. */
1346 for (i
= 1; i
<= 2; i
++)
1351 memset(&lf
, 0, sizeof(lf
));
1356 strcpy(lf
.lfFaceName
, "Tahoma");
1360 strcpy(lf
.lfFaceName
, "Times New Roman");
1365 if (!is_truetype_font_installed(lf
.lfFaceName
))
1367 skip("%s is not installed\n", lf
.lfFaceName
);
1370 for (j
= 1; j
<= 80; j
++)
1375 hfont
= CreateFontIndirectA(&lf
);
1376 hfont
= SelectObject(hdc
, hfont
);
1378 nb
= GetGlyphOutlineA(hdc
, code
, GGO_METRICS
, &gm
, 0, NULL
, &mat
);
1379 ok(nb
, "GetGlyphOutlineA should have succeeded at width %d\n", i
);
1381 ret
= GetCharABCWidthsA(hdc
, code
, code
, abc
);
1382 ok(ret
, "GetCharABCWidthsA should have succeeded at width %d\n", i
);
1384 ok(abc
[0].abcA
== gm
.gmptGlyphOrigin
.x
,
1385 "abcA(%d) and gmptGlyphOrigin.x(%d) values are different at width %d\n",
1386 abc
[0].abcA
, gm
.gmptGlyphOrigin
.x
, i
);
1387 ok(abc
[0].abcB
== gm
.gmBlackBoxX
,
1388 "abcB(%d) and gmBlackBoxX(%d) values are different at width %d\n",
1389 abc
[0].abcB
, gm
.gmBlackBoxX
, i
);
1390 DeleteObject(SelectObject(hdc
, hfont
));
1393 ReleaseDC(NULL
, hdc
);
1395 trace("ABC sign test for a variety of transforms:\n");
1396 memset(&lf
, 0, sizeof(lf
));
1397 strcpy(lf
.lfFaceName
, "Tahoma");
1399 hfont
= CreateFontIndirectA(&lf
);
1400 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1403 SetMapMode(hdc
, MM_ANISOTROPIC
);
1404 SelectObject(hdc
, hfont
);
1406 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1407 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1409 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1410 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1411 ret
= pGetCharABCWidthsW(hdc
, 'i', 'i', abcw
);
1412 ok(ret
, "GetCharABCWidthsW should have succeeded\n");
1413 ret
= pGetCharABCWidthsFloatW(hdc
, 'i', 'i', abcf
);
1414 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1416 ABCWidths_helper("LTR", hdc
, glyphs
, abc
, abcw
, abcf
);
1417 SetWindowExtEx(hdc
, -1, -1, NULL
);
1418 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1419 ABCWidths_helper("LTR -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1420 SetGraphicsMode(hdc
, GM_ADVANCED
);
1421 ABCWidths_helper("LTR -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1422 SetWindowExtEx(hdc
, 1, 1, NULL
);
1423 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1424 ABCWidths_helper("LTR 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1425 SetGraphicsMode(hdc
, GM_ADVANCED
);
1426 ABCWidths_helper("LTR 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1428 ReleaseDC(hwnd
, hdc
);
1429 DestroyWindow(hwnd
);
1431 trace("RTL layout\n");
1432 hwnd
= CreateWindowExA(WS_EX_LAYOUTRTL
, "static", "", WS_POPUP
, 0,0,100,100,
1435 SetMapMode(hdc
, MM_ANISOTROPIC
);
1436 SelectObject(hdc
, hfont
);
1438 ABCWidths_helper("RTL", hdc
, glyphs
, abc
, abcw
, abcf
);
1439 SetWindowExtEx(hdc
, -1, -1, NULL
);
1440 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1441 ABCWidths_helper("RTL -1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1442 SetGraphicsMode(hdc
, GM_ADVANCED
);
1443 ABCWidths_helper("RTL -1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1444 SetWindowExtEx(hdc
, 1, 1, NULL
);
1445 SetGraphicsMode(hdc
, GM_COMPATIBLE
);
1446 ABCWidths_helper("RTL 1 compatible", hdc
, glyphs
, abc
, abcw
, abcf
);
1447 SetGraphicsMode(hdc
, GM_ADVANCED
);
1448 ABCWidths_helper("RTL 1 advanced", hdc
, glyphs
, abc
, abcw
, abcf
);
1450 ReleaseDC(hwnd
, hdc
);
1451 DestroyWindow(hwnd
);
1452 DeleteObject(hfont
);
1455 static void test_text_extents(void)
1457 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1458 static const WCHAR emptyW
[] = {0};
1460 INT i
, len
, fit1
, fit2
, extents2
[3];
1469 memset(&lf
, 0, sizeof(lf
));
1470 strcpy(lf
.lfFaceName
, "Arial");
1473 hfont
= CreateFontIndirectA(&lf
);
1475 hfont
= SelectObject(hdc
, hfont
);
1476 GetTextMetricsA(hdc
, &tm
);
1477 ret
= GetTextExtentPointA(hdc
, "o", 1, &sz
);
1478 ok(ret
, "got %d\n", ret
);
1479 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1481 memset(&sz
, 0xcc, sizeof(sz
));
1482 ret
= GetTextExtentPointA(hdc
, "o", 0, &sz
);
1483 ok(ret
, "got %d\n", ret
);
1484 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1486 memset(&sz
, 0xcc, sizeof(sz
));
1487 ret
= GetTextExtentPointA(hdc
, "", 0, &sz
);
1488 ok(ret
, "got %d\n", ret
);
1489 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1491 SetLastError(0xdeadbeef);
1492 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1493 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1495 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1496 hfont
= SelectObject(hdc
, hfont
);
1497 DeleteObject(hfont
);
1502 memset(&sz
, 0xcc, sizeof(sz
));
1503 ret
= GetTextExtentPointW(hdc
, wt
, 0, &sz
);
1504 ok(ret
, "got %d\n", ret
);
1505 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1507 memset(&sz
, 0xcc, sizeof(sz
));
1508 ret
= GetTextExtentPointW(hdc
, emptyW
, 0, &sz
);
1509 ok(ret
, "got %d\n", ret
);
1510 ok(sz
.cx
== 0 && sz
.cy
== 0, "cx %d, cy %d\n", sz
.cx
, sz
.cy
);
1513 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1514 extents
[0] = 1; /* So that the increasing sequence test will fail
1515 if the extents array is untouched. */
1516 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1517 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1518 ok(sz1
.cy
== sz2
.cy
,
1519 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1520 /* Because of the '\n' in the string GetTextExtentExPoint and
1521 GetTextExtentPoint return different widths under Win2k, but
1522 under WinXP they return the same width. So we don't test that
1525 for (i
= 1; i
< len
; ++i
)
1526 ok(extents
[i
-1] <= extents
[i
],
1527 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1529 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1530 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1531 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1532 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1533 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1534 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1535 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1536 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1537 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1538 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1539 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1540 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1541 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1542 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1544 /* extents functions fail with -ve counts (the interesting case being -1) */
1545 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1546 ok(ret
== FALSE
, "got %d\n", ret
);
1547 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1548 ok(ret
== FALSE
, "got %d\n", ret
);
1549 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1550 ok(ret
== FALSE
, "got %d\n", ret
);
1552 /* max_extent = 0 succeeds and returns zero */
1554 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1556 broken(ret
== FALSE
), /* NT4, 2k */
1559 broken(fit1
== -215), /* NT4, 2k */
1560 "fit = %d\n", fit1
);
1561 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1562 ok(ret
== TRUE
, "got %d\n", ret
);
1563 ok(fit2
== 0, "fit = %d\n", fit2
);
1565 /* max_extent = -1 is interpreted as a very large width that will
1566 * definitely fit our three characters */
1568 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1569 ok(ret
== TRUE
, "got %d\n", ret
);
1570 ok(fit1
== 3, "fit = %d\n", fit1
);
1571 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1572 ok(ret
== TRUE
, "got %d\n", ret
);
1573 ok(fit2
== 3, "fit = %d\n", fit2
);
1575 /* max_extent = -2 is interpreted similarly, but the Ansi version
1576 * rejects it while the Unicode one accepts it */
1578 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1579 ok(ret
== FALSE
, "got %d\n", ret
);
1580 ok(fit1
== -215, "fit = %d\n", fit1
);
1581 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1582 ok(ret
== TRUE
, "got %d\n", ret
);
1583 ok(fit2
== 3, "fit = %d\n", fit2
);
1585 hfont
= SelectObject(hdc
, hfont
);
1586 DeleteObject(hfont
);
1588 /* non-MM_TEXT mapping mode */
1590 hfont
= CreateFontIndirectA(&lf
);
1591 hfont
= SelectObject(hdc
, hfont
);
1593 SetMapMode( hdc
, MM_HIMETRIC
);
1594 ret
= GetTextExtentExPointW(hdc
, wt
, 3, 0, NULL
, extents
, &sz
);
1595 ok(ret
, "got %d\n", ret
);
1596 ok(sz
.cx
== extents
[2], "got %d vs %d\n", sz
.cx
, extents
[2]);
1598 ret
= GetTextExtentExPointW(hdc
, wt
, 3, extents
[1], &fit1
, extents2
, &sz2
);
1599 ok(ret
, "got %d\n", ret
);
1600 ok(fit1
== 2, "got %d\n", fit1
);
1601 ok(sz2
.cx
== sz
.cx
, "got %d vs %d\n", sz2
.cx
, sz
.cx
);
1602 for(i
= 0; i
< 2; i
++)
1603 ok(extents2
[i
] == extents
[i
], "%d: %d, %d\n", i
, extents2
[i
], extents
[i
]);
1605 hfont
= SelectObject(hdc
, hfont
);
1606 DeleteObject(hfont
);
1607 HeapFree(GetProcessHeap(), 0, extents
);
1608 ReleaseDC(NULL
, hdc
);
1611 static void test_GetGlyphIndices(void)
1618 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1619 WORD glyphs
[(sizeof(testtext
)/2)-1];
1623 if (!pGetGlyphIndicesW
) {
1624 win_skip("GetGlyphIndicesW not available on platform\n");
1630 memset(&lf
, 0, sizeof(lf
));
1631 strcpy(lf
.lfFaceName
, "System");
1633 lf
.lfCharSet
= ANSI_CHARSET
;
1635 hfont
= CreateFontIndirectA(&lf
);
1636 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1637 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1638 if (textm
.tmCharSet
== ANSI_CHARSET
)
1640 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1641 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1642 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1643 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1645 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1646 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1647 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1648 textm
.tmDefaultChar
, glyphs
[4]);
1651 /* FIXME: Write tests for non-ANSI charsets. */
1652 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1654 if(!is_font_installed("Tahoma"))
1656 skip("Tahoma is not installed so skipping this test\n");
1659 memset(&lf
, 0, sizeof(lf
));
1660 strcpy(lf
.lfFaceName
, "Tahoma");
1663 hfont
= CreateFontIndirectA(&lf
);
1664 hOldFont
= SelectObject(hdc
, hfont
);
1665 ok(GetTextMetricsA(hdc
, &textm
), "GetTextMetric failed\n");
1666 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1667 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1668 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1669 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1671 testtext
[0] = textm
.tmDefaultChar
;
1672 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1673 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1674 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1675 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1676 DeleteObject(SelectObject(hdc
, hOldFont
));
1679 static void test_GetKerningPairs(void)
1681 static const struct kerning_data
1683 const char face_name
[LF_FACESIZE
];
1685 /* some interesting fields from OUTLINETEXTMETRIC */
1686 LONG tmHeight
, tmAscent
, tmDescent
;
1691 UINT otmsCapEmHeight
;
1696 UINT otmusMinimumPPEM
;
1697 /* small subset of kerning pairs to test */
1698 DWORD total_kern_pairs
;
1699 const KERNINGPAIR kern_pair
[26];
1702 {"Arial", 12, 12, 9, 3,
1703 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1706 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1707 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1708 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1709 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1710 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1711 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1712 {933,970,+1},{933,972,-1}
1715 {"Arial", -34, 39, 32, 7,
1716 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1719 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1720 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1721 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1722 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1723 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1724 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1725 {933,970,+2},{933,972,-3}
1728 { "Arial", 120, 120, 97, 23,
1729 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1732 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1733 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1734 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1735 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1736 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1737 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1738 {933,970,+6},{933,972,-10}
1741 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1742 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1743 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1746 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1747 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1748 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1749 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1750 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1751 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1752 {933,970,+54},{933,972,-83}
1758 HFONT hfont
, hfont_old
;
1759 KERNINGPAIR
*kern_pair
;
1761 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1765 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1766 * which may render this test unusable, so we're trying to avoid that.
1768 SetLastError(0xdeadbeef);
1769 GetKerningPairsW(hdc
, 0, NULL
);
1770 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1772 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1777 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1779 OUTLINETEXTMETRICW otm
;
1782 if (!is_font_installed(kd
[i
].face_name
))
1784 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1788 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1790 memset(&lf
, 0, sizeof(lf
));
1791 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1792 lf
.lfHeight
= kd
[i
].height
;
1793 hfont
= CreateFontIndirectA(&lf
);
1794 ok(hfont
!= NULL
, "failed to create a font, name %s\n", kd
[i
].face_name
);
1796 hfont_old
= SelectObject(hdc
, hfont
);
1798 SetLastError(0xdeadbeef);
1799 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1800 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1801 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1803 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
, FALSE
), "expected %d, got %d\n",
1804 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1805 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
, FALSE
), "expected %d, got %d\n",
1806 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1807 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1808 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1810 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1811 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1812 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1813 kd
[i
].otmAscent
, otm
.otmAscent
);
1814 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1815 kd
[i
].otmDescent
, otm
.otmDescent
);
1816 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1817 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1818 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1819 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1820 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1821 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1823 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1824 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1826 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1827 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1828 ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1829 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1831 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1832 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1834 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1835 trace("total_kern_pairs %u\n", total_kern_pairs
);
1836 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1838 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1841 SetLastError(0xdeadbeef);
1842 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1843 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1844 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1845 ok(ret
== 0, "got %u, expected 0\n", ret
);
1847 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1848 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1850 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1851 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1853 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1854 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1858 for (n
= 0; n
< ret
; n
++)
1861 /* Disabled to limit console spam */
1862 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1863 trace("{'%c','%c',%d},\n",
1864 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1865 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1867 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1868 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1870 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1871 "pair %d:%d got %d, expected %d\n",
1872 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1873 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1879 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1880 matches
, kd
[i
].total_kern_pairs
);
1882 HeapFree(GetProcessHeap(), 0, kern_pair
);
1884 SelectObject(hdc
, hfont_old
);
1885 DeleteObject(hfont
);
1893 const char face_name
[LF_FACESIZE
];
1894 int requested_height
;
1895 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1899 static void test_height( HDC hdc
, const struct font_data
*fd
)
1902 HFONT hfont
, old_hfont
;
1906 for (i
= 0; fd
[i
].face_name
[0]; i
++)
1908 if (!is_truetype_font_installed(fd
[i
].face_name
))
1910 skip("%s is not installed\n", fd
[i
].face_name
);
1914 memset(&lf
, 0, sizeof(lf
));
1915 lf
.lfHeight
= fd
[i
].requested_height
;
1916 lf
.lfWeight
= fd
[i
].weight
;
1917 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1919 hfont
= CreateFontIndirectA(&lf
);
1920 ok(hfont
!= NULL
, "failed to create a font, name %s\n", fd
[i
].face_name
);
1922 old_hfont
= SelectObject(hdc
, hfont
);
1923 ret
= GetTextMetricsA(hdc
, &tm
);
1924 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1925 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1927 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmWeight
, fd
[i
].weight
);
1928 ok(match_off_by_1(tm
.tmHeight
, fd
[i
].height
, fd
[i
].exact
), "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmHeight
, fd
[i
].height
);
1929 ok(match_off_by_1(tm
.tmAscent
, fd
[i
].ascent
, fd
[i
].exact
), "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmAscent
, fd
[i
].ascent
);
1930 ok(match_off_by_1(tm
.tmDescent
, fd
[i
].descent
, fd
[i
].exact
), "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmDescent
, fd
[i
].descent
);
1931 ok(match_off_by_1(tm
.tmInternalLeading
, fd
[i
].int_leading
, fd
[i
].exact
), "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1932 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
1935 SelectObject(hdc
, old_hfont
);
1936 /* force GDI to use new font, otherwise Windows leaks the font reference */
1937 GetTextMetricsA(hdc
, &tm
);
1938 DeleteObject(hfont
);
1942 static void *find_ttf_table( void *ttf
, DWORD size
, DWORD tag
)
1944 WORD i
, num_tables
= GET_BE_WORD(*((WORD
*)ttf
+ 2));
1945 DWORD
*table
= (DWORD
*)ttf
+ 3;
1947 for (i
= 0; i
< num_tables
; i
++)
1949 if (table
[0] == tag
)
1950 return (BYTE
*)ttf
+ GET_BE_DWORD(table
[2]);
1956 static void test_height_selection_vdmx( HDC hdc
)
1958 static const struct font_data charset_0
[] = /* doesn't use VDMX */
1960 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
1961 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
1962 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1963 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1964 { "wine_vdmx", 14, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1965 { "wine_vdmx", 15, FW_NORMAL
, 15, 12, 3, 3, 0, 96, FALSE
},
1966 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1967 { "wine_vdmx", 17, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1968 { "wine_vdmx", 18, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1969 { "wine_vdmx", 19, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1970 { "wine_vdmx", 20, FW_NORMAL
, 20, 17, 3, 4, 0, 96, FALSE
},
1971 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1972 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1973 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1974 { "wine_vdmx", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1975 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1976 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 5, 0, 96, FALSE
},
1977 { "wine_vdmx", 27, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1978 { "wine_vdmx", 28, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
1979 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
1980 { "wine_vdmx", 30, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
1981 { "wine_vdmx", 31, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
1982 { "wine_vdmx", 32, FW_NORMAL
, 32, 27, 5, 6, 0, 96, FALSE
},
1983 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
1984 { "wine_vdmx", 64, FW_NORMAL
, 64, 53, 11, 11, 0, 96, TRUE
},
1985 { "wine_vdmx", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
1986 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
1987 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
1988 { "wine_vdmx", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
1989 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
1990 { "wine_vdmx", -14, FW_NORMAL
, 17, 14, 3, 3, 0, 96, TRUE
},
1991 { "wine_vdmx", -15, FW_NORMAL
, 18, 15, 3, 3, 0, 96, TRUE
},
1992 { "wine_vdmx", -16, FW_NORMAL
, 19, 16, 3, 3, 0, 96, TRUE
},
1993 { "wine_vdmx", -17, FW_NORMAL
, 21, 17, 4, 4, 0, 96, TRUE
},
1994 { "wine_vdmx", -18, FW_NORMAL
, 22, 18, 4, 4, 0, 96, TRUE
},
1995 { "wine_vdmx", -19, FW_NORMAL
, 23, 19, 4, 4, 0, 96, TRUE
},
1996 { "wine_vdmx", -20, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
1997 { "wine_vdmx", -21, FW_NORMAL
, 25, 21, 4, 4, 0, 96, TRUE
},
1998 { "wine_vdmx", -22, FW_NORMAL
, 27, 22, 5, 5, 0, 96, TRUE
},
1999 { "wine_vdmx", -23, FW_NORMAL
, 28, 23, 5, 5, 0, 96, TRUE
},
2000 { "wine_vdmx", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2001 { "wine_vdmx", -25, FW_NORMAL
, 30, 25, 5, 5, 0, 96, TRUE
},
2002 { "wine_vdmx", -26, FW_NORMAL
, 31, 26, 5, 5, 0, 96, TRUE
},
2003 { "wine_vdmx", -27, FW_NORMAL
, 33, 27, 6, 6, 0, 96, TRUE
},
2004 { "wine_vdmx", -28, FW_NORMAL
, 34, 28, 6, 6, 0, 96, TRUE
},
2005 { "wine_vdmx", -29, FW_NORMAL
, 35, 29, 6, 6, 0, 96, TRUE
},
2006 { "wine_vdmx", -30, FW_NORMAL
, 36, 30, 6, 6, 0, 96, TRUE
},
2007 { "wine_vdmx", -31, FW_NORMAL
, 37, 31, 6, 6, 0, 96, TRUE
},
2008 { "wine_vdmx", -32, FW_NORMAL
, 39, 32, 7, 7, 0, 96, TRUE
},
2009 { "wine_vdmx", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2010 { "wine_vdmx", -64, FW_NORMAL
, 77, 64, 13, 13, 0, 96, TRUE
},
2011 { "wine_vdmx", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2012 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2015 static const struct font_data charset_1
[] = /* Uses VDMX */
2017 { "wine_vdmx", 10, FW_NORMAL
, 10, 8, 2, 2, 0, 96, TRUE
},
2018 { "wine_vdmx", 11, FW_NORMAL
, 11, 9, 2, 2, 0, 96, TRUE
},
2019 { "wine_vdmx", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2020 { "wine_vdmx", 13, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2021 { "wine_vdmx", 14, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2022 { "wine_vdmx", 15, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2023 { "wine_vdmx", 16, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2024 { "wine_vdmx", 17, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2025 { "wine_vdmx", 18, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2026 { "wine_vdmx", 19, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2027 { "wine_vdmx", 20, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2028 { "wine_vdmx", 21, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2029 { "wine_vdmx", 22, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2030 { "wine_vdmx", 23, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2031 { "wine_vdmx", 24, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2032 { "wine_vdmx", 25, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2033 { "wine_vdmx", 26, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2034 { "wine_vdmx", 27, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2035 { "wine_vdmx", 28, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2036 { "wine_vdmx", 29, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2037 { "wine_vdmx", 30, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2038 { "wine_vdmx", 31, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2039 { "wine_vdmx", 32, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2040 { "wine_vdmx", 48, FW_NORMAL
, 48, 40, 8, 10, 0, 96, TRUE
},
2041 { "wine_vdmx", 64, FW_NORMAL
, 64, 54, 10, 13, 0, 96, TRUE
},
2042 { "wine_vdmx", 96, FW_NORMAL
, 95, 79, 16, 18, 0, 96, TRUE
},
2043 { "wine_vdmx", -10, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2044 { "wine_vdmx", -11, FW_NORMAL
, 13, 11, 2, 2, 0, 96, TRUE
},
2045 { "wine_vdmx", -12, FW_NORMAL
, 16, 13, 3, 4, 0, 96, TRUE
},
2046 { "wine_vdmx", -13, FW_NORMAL
, 16, 13, 3, 3, 0, 96, TRUE
},
2047 { "wine_vdmx", -14, FW_NORMAL
, 19, 15, 4, 5, 0, 96, TRUE
},
2048 { "wine_vdmx", -15, FW_NORMAL
, 20, 16, 4, 5, 0, 96, TRUE
},
2049 { "wine_vdmx", -16, FW_NORMAL
, 21, 17, 4, 5, 0, 96, TRUE
},
2050 { "wine_vdmx", -17, FW_NORMAL
, 22, 18, 4, 5, 0, 96, TRUE
},
2051 { "wine_vdmx", -18, FW_NORMAL
, 23, 19, 4, 5, 0, 96, TRUE
},
2052 { "wine_vdmx", -19, FW_NORMAL
, 25, 21, 4, 6, 0, 96, TRUE
},
2053 { "wine_vdmx", -20, FW_NORMAL
, 26, 22, 4, 6, 0, 96, TRUE
},
2054 { "wine_vdmx", -21, FW_NORMAL
, 27, 23, 4, 6, 0, 96, TRUE
},
2055 { "wine_vdmx", -22, FW_NORMAL
, 27, 23, 4, 5, 0, 96, TRUE
},
2056 { "wine_vdmx", -23, FW_NORMAL
, 29, 24, 5, 6, 0, 96, TRUE
},
2057 { "wine_vdmx", -24, FW_NORMAL
, 32, 26, 6, 8, 0, 96, TRUE
},
2058 { "wine_vdmx", -25, FW_NORMAL
, 32, 26, 6, 7, 0, 96, TRUE
},
2059 { "wine_vdmx", -26, FW_NORMAL
, 33, 27, 6, 7, 0, 96, TRUE
},
2060 { "wine_vdmx", -27, FW_NORMAL
, 35, 29, 6, 8, 0, 96, TRUE
},
2061 { "wine_vdmx", -28, FW_NORMAL
, 36, 30, 6, 8, 0, 96, TRUE
},
2062 { "wine_vdmx", -29, FW_NORMAL
, 36, 30, 6, 7, 0, 96, TRUE
},
2063 { "wine_vdmx", -30, FW_NORMAL
, 38, 32, 6, 8, 0, 96, TRUE
},
2064 { "wine_vdmx", -31, FW_NORMAL
, 39, 33, 6, 8, 0, 96, TRUE
},
2065 { "wine_vdmx", -32, FW_NORMAL
, 40, 33, 7, 8, 0, 96, TRUE
},
2066 { "wine_vdmx", -48, FW_NORMAL
, 60, 50, 10, 12, 0, 96, TRUE
},
2067 { "wine_vdmx", -64, FW_NORMAL
, 81, 67, 14, 17, 0, 96, TRUE
},
2068 { "wine_vdmx", -96, FW_NORMAL
, 119, 99, 20, 23, 0, 96, TRUE
},
2069 { "", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2072 static const struct vdmx_data
2076 const struct font_data
*fd
;
2079 { 0, 0, charset_0
},
2080 { 0, 1, charset_1
},
2081 { 1, 0, charset_0
},
2088 char ttf_name
[MAX_PATH
];
2092 if (!pAddFontResourceExA
)
2094 win_skip("AddFontResourceExA unavailable\n");
2098 for (i
= 0; i
< sizeof(data
) / sizeof(data
[0]); i
++)
2100 res
= get_res_data( "wine_vdmx.ttf", &size
);
2102 copy
= HeapAlloc( GetProcessHeap(), 0, size
);
2103 memcpy( copy
, res
, size
);
2104 vdmx_header
= find_ttf_table( copy
, size
, MS_MAKE_TAG('V','D','M','X') );
2105 vdmx_header
[0] = GET_BE_WORD( data
[i
].version
);
2106 ok( GET_BE_WORD( vdmx_header
[1] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[1] ) );
2107 ok( GET_BE_WORD( vdmx_header
[2] ) == 1, "got %04x\n", GET_BE_WORD( vdmx_header
[2] ) );
2108 ratio_rec
= (BYTE
*)&vdmx_header
[3];
2109 ratio_rec
[0] = data
[i
].bCharSet
;
2111 write_tmp_file( copy
, &size
, ttf_name
);
2112 HeapFree( GetProcessHeap(), 0, copy
);
2114 ok( !is_truetype_font_installed("wine_vdmx"), "Already installed\n" );
2115 num
= pAddFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2116 if (!num
) win_skip("Unable to add ttf font resource\n");
2119 ok( is_truetype_font_installed("wine_vdmx"), "Not installed\n" );
2120 test_height( hdc
, data
[i
].fd
);
2121 pRemoveFontResourceExA( ttf_name
, FR_PRIVATE
, 0 );
2123 ret
= DeleteFileA( ttf_name
);
2124 ok(ret
|| broken(!ret
&& GetLastError() == ERROR_ACCESS_DENIED
),
2125 "DeleteFile error %d\n", GetLastError());
2129 static void test_height_selection(void)
2131 static const struct font_data tahoma
[] =
2133 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96, TRUE
},
2134 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96, TRUE
},
2135 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96, TRUE
},
2136 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96, TRUE
},
2137 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96, TRUE
},
2138 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96, TRUE
},
2139 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96, TRUE
},
2140 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96, TRUE
},
2141 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96, FALSE
},
2142 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96, TRUE
},
2143 {"", 0, 0, 0, 0, 0, 0, 0, 0, 0 }
2145 HDC hdc
= CreateCompatibleDC(0);
2146 ok(hdc
!= NULL
, "failed to create hdc\n");
2148 test_height( hdc
, tahoma
);
2149 test_height_selection_vdmx( hdc
);
2154 static UINT
get_font_fsselection(LOGFONTA
*lf
)
2156 OUTLINETEXTMETRICA
*otm
;
2157 HFONT hfont
, hfont_old
;
2158 DWORD ret
, otm_size
;
2163 hfont
= CreateFontIndirectA(lf
);
2164 ok(hfont
!= NULL
, "failed to create a font\n");
2166 hfont_old
= SelectObject(hdc
, hfont
);
2168 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2169 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2170 otm
->otmSize
= sizeof(*otm
);
2171 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2172 ok(ret
== otm
->otmSize
, "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2173 fsSelection
= otm
->otmfsSelection
;
2174 HeapFree(GetProcessHeap(), 0, otm
);
2175 SelectObject(hdc
, hfont_old
);
2176 DeleteObject(hfont
);
2182 static void test_GetOutlineTextMetrics(void)
2184 OUTLINETEXTMETRICA
*otm
;
2186 HFONT hfont
, hfont_old
;
2188 DWORD ret
, otm_size
;
2192 /* check fsSelection field with bold simulation */
2193 memset(&lf
, 0, sizeof(lf
));
2194 strcpy(lf
.lfFaceName
, "Wingdings");
2195 lf
.lfCharSet
= SYMBOL_CHARSET
;
2198 fsSelection
= get_font_fsselection(&lf
);
2199 ok((fsSelection
& (1 << 5)) == 0, "got 0x%x\n", fsSelection
);
2201 /* face with bold simulation */
2202 lf
.lfWeight
= FW_BOLD
;
2203 fsSelection
= get_font_fsselection(&lf
);
2204 ok((fsSelection
& (1 << 5)) != 0, "got 0x%x\n", fsSelection
);
2206 /* check fsSelection field with oblique simulation */
2207 memset(&lf
, 0, sizeof(lf
));
2208 strcpy(lf
.lfFaceName
, "Tahoma");
2210 lf
.lfWeight
= FW_NORMAL
;
2211 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2212 lf
.lfQuality
= PROOF_QUALITY
;
2215 fsSelection
= get_font_fsselection(&lf
);
2216 ok((fsSelection
& 1) == 0, "got 0x%x\n", fsSelection
);
2219 /* face with oblique simulation */
2220 fsSelection
= get_font_fsselection(&lf
);
2221 ok((fsSelection
& 1) == 1, "got 0x%x\n", fsSelection
);
2223 if (!is_font_installed("Arial"))
2225 skip("Arial is not installed\n");
2231 memset(&lf
, 0, sizeof(lf
));
2232 strcpy(lf
.lfFaceName
, "Arial");
2234 lf
.lfWeight
= FW_NORMAL
;
2235 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
2236 lf
.lfQuality
= PROOF_QUALITY
;
2237 hfont
= CreateFontIndirectA(&lf
);
2238 ok(hfont
!= NULL
, "failed to create a font\n");
2240 hfont_old
= SelectObject(hdc
, hfont
);
2241 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
2242 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
2244 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
2246 memset(otm
, 0xAA, otm_size
);
2247 SetLastError(0xdeadbeef);
2248 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
2249 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2250 ok(ret
== 1 /* Win9x */ ||
2251 ret
== otm
->otmSize
/* XP*/,
2252 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2253 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2255 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2256 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2257 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2258 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
2261 memset(otm
, 0xAA, otm_size
);
2262 SetLastError(0xdeadbeef);
2263 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
2264 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2265 ok(ret
== 1 /* Win9x */ ||
2266 ret
== otm
->otmSize
/* XP*/,
2267 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2268 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2270 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
2271 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
2272 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
2273 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
2276 /* ask about truncated data */
2277 memset(otm
, 0xAA, otm_size
);
2278 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
2279 SetLastError(0xdeadbeef);
2280 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
2281 ret
= GetOutlineTextMetricsA(hdc
, otm
->otmSize
, otm
);
2282 ok(ret
== 1 /* Win9x */ ||
2283 ret
== otm
->otmSize
/* XP*/,
2284 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
2285 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
2287 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
2288 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
2289 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
2291 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
2293 /* check handling of NULL pointer */
2294 SetLastError(0xdeadbeef);
2295 ret
= GetOutlineTextMetricsA(hdc
, otm_size
, NULL
);
2296 ok(ret
== otm_size
, "expected %u, got %u, error %d\n", otm_size
, ret
, GetLastError());
2298 HeapFree(GetProcessHeap(), 0, otm
);
2300 SelectObject(hdc
, hfont_old
);
2301 DeleteObject(hfont
);
2306 static void testJustification(HDC hdc
, PCSTR str
, RECT
*clientArea
)
2310 areaWidth
= clientArea
->right
- clientArea
->left
,
2312 const char *pFirstChar
, *pLastChar
;
2319 int GetTextExtentExPointWWidth
;
2322 GetTextMetricsA(hdc
, &tm
);
2323 y
= clientArea
->top
;
2326 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
2332 /* if not at the end of the string, ... */
2333 if (*str
== '\0') break;
2334 /* ... add the next word to the current extent */
2335 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
2337 SetTextJustification(hdc
, 0, 0);
2338 GetTextExtentPoint32A(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
2339 } while ((int) size
.cx
< areaWidth
);
2341 /* ignore trailing break chars */
2343 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
2349 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
2351 SetTextJustification(hdc
, 0, 0);
2352 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
2354 /* do not justify the last extent */
2355 if (*str
!= '\0' && breakCount
> 0)
2357 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
2358 GetTextExtentPoint32A(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);