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/test.h"
33 /* Do not allow more than 1 deviation here */
34 #define match_off_by_1(a, b) (abs((a) - (b)) <= 1)
36 #define near_match(a, b) (abs((a) - (b)) <= 6)
37 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
39 static LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
40 static DWORD (WINAPI
*pGdiGetCodePage
)(HDC hdc
);
41 static BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
42 static BOOL (WINAPI
*pGetCharABCWidthsA
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
43 static BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
44 static BOOL (WINAPI
*pGetCharABCWidthsFloatW
)(HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abc
);
45 static DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
46 static DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
47 static DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
48 static BOOL (WINAPI
*pGetTextExtentExPointI
)(HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
49 LPINT nfit
, LPINT dxs
, LPSIZE size
);
50 static BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
51 static HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDV
*);
52 static HANDLE (WINAPI
*pAddFontMemResourceEx
)(PVOID
, DWORD
, PVOID
, DWORD
*);
53 static BOOL (WINAPI
*pRemoveFontMemResourceEx
)(HANDLE
);
54 static INT (WINAPI
*pAddFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
55 static BOOL (WINAPI
*pRemoveFontResourceExA
)(LPCSTR
, DWORD
, PVOID
);
57 static HMODULE hgdi32
= 0;
58 static const MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
59 static WORD system_lang_id
;
61 static void init(void)
63 hgdi32
= GetModuleHandleA("gdi32.dll");
65 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
66 pGdiGetCodePage
= (void *) GetProcAddress(hgdi32
,"GdiGetCodePage");
67 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
68 pGetCharABCWidthsA
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsA");
69 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
70 pGetCharABCWidthsFloatW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsFloatW");
71 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
72 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
73 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
74 pGetTextExtentExPointI
= (void *)GetProcAddress(hgdi32
, "GetTextExtentExPointI");
75 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
76 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
77 pAddFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "AddFontMemResourceEx");
78 pRemoveFontMemResourceEx
= (void *)GetProcAddress(hgdi32
, "RemoveFontMemResourceEx");
79 pAddFontResourceExA
= (void *)GetProcAddress(hgdi32
, "AddFontResourceExA");
80 pRemoveFontResourceExA
= (void *)GetProcAddress(hgdi32
, "RemoveFontResourceExA");
82 system_lang_id
= PRIMARYLANGID(GetSystemDefaultLangID());
85 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
87 if (type
!= TRUETYPE_FONTTYPE
) return 1;
92 static BOOL
is_truetype_font_installed(const char *name
)
97 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
104 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
109 static BOOL
is_font_installed(const char *name
)
114 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
121 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
129 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
130 /* NT4 tries to be clever and only returns the minimum length */
131 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
133 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
134 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
135 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
136 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
137 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
138 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
139 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
140 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
141 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
142 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
143 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
144 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
145 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
146 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
147 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
148 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
149 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
150 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
151 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
152 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
153 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
154 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
155 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
156 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
157 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
158 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
159 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
160 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
163 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
165 HFONT hfont
= CreateFontIndirectA(lf
);
166 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
168 check_font(test
, lf
, hfont
);
172 static void test_logfont(void)
177 memset(&lf
, 0, sizeof lf
);
179 lf
.lfCharSet
= ANSI_CHARSET
;
180 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
181 lf
.lfWeight
= FW_DONTCARE
;
184 lf
.lfQuality
= DEFAULT_QUALITY
;
186 lstrcpyA(lf
.lfFaceName
, "Arial");
187 hfont
= create_font("Arial", &lf
);
190 memset(&lf
, 'A', sizeof(lf
));
191 hfont
= CreateFontIndirectA(&lf
);
192 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
194 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
195 check_font("AAA...", &lf
, hfont
);
199 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
201 if (type
& RASTER_FONTTYPE
)
203 LOGFONT
*lf
= (LOGFONT
*)lParam
;
205 return 0; /* stop enumeration */
208 return 1; /* continue enumeration */
211 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
213 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
214 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
215 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
216 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
217 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
218 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
219 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
220 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
221 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
222 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
223 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
224 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
225 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
226 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
227 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
228 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
229 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
230 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
231 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
232 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
235 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
236 LONG lfWidth
, const char *test_str
,
237 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
238 const SIZE
*size_orig
, INT width_of_A_orig
,
239 INT scale_x
, INT scale_y
)
242 OUTLINETEXTMETRIC otm
;
245 INT width_of_A
, cx
, cy
;
251 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
253 GetObjectA(hfont
, sizeof(lf
), &lf
);
255 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
257 otm
.otmSize
= sizeof(otm
) / 2;
258 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
259 ok(ret
== sizeof(otm
)/2 /* XP */ ||
260 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
262 memset(&otm
, 0x1, sizeof(otm
));
263 otm
.otmSize
= sizeof(otm
);
264 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
265 ok(ret
== sizeof(otm
) /* XP */ ||
266 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
268 memset(&tm
, 0x2, sizeof(tm
));
269 ret
= GetTextMetricsA(hdc
, &tm
);
270 ok(ret
, "GetTextMetricsA failed\n");
271 /* the structure size is aligned */
272 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
274 ok(0, "tm != otm\n");
275 compare_tm(&tm
, &otm
.otmTextMetrics
);
278 tm
= otm
.otmTextMetrics
;
279 if (0) /* these metrics are scaled too, but with rounding errors */
281 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
282 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
284 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
285 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
286 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
287 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
288 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
289 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
293 ret
= GetTextMetricsA(hdc
, &tm
);
294 ok(ret
, "GetTextMetricsA failed\n");
297 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
298 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
299 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
300 lfHeight
, scale_x
, scale_y
, cx
, cy
);
301 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
302 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
303 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
304 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
305 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
307 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
311 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
314 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
316 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
318 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
319 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
321 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
323 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
);
326 /* Test how GDI scales bitmap font metrics */
327 static void test_bitmap_font(void)
329 static const char test_str
[11] = "Test String";
332 HFONT hfont
, old_hfont
;
335 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
337 if(!winetest_interactive
)
339 skip("reactos bug 5401: Skipping bitmap font tests!\n");
343 hdc
= CreateCompatibleDC(0);
345 /* "System" has only 1 pixel size defined, otherwise the test breaks */
346 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
350 trace("no bitmap fonts were found, skipping the test\n");
354 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
356 height_orig
= bitmap_lf
.lfHeight
;
357 lfWidth
= bitmap_lf
.lfWidth
;
359 hfont
= create_font("bitmap", &bitmap_lf
);
360 old_hfont
= SelectObject(hdc
, hfont
);
361 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
362 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
363 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
364 SelectObject(hdc
, old_hfont
);
367 bitmap_lf
.lfHeight
= 0;
368 bitmap_lf
.lfWidth
= 4;
369 hfont
= create_font("bitmap", &bitmap_lf
);
370 old_hfont
= SelectObject(hdc
, hfont
);
371 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
372 SelectObject(hdc
, old_hfont
);
375 bitmap_lf
.lfHeight
= height_orig
;
376 bitmap_lf
.lfWidth
= lfWidth
;
378 /* test fractional scaling */
379 for (i
= 1; i
<= height_orig
* 6; i
++)
383 bitmap_lf
.lfHeight
= i
;
384 hfont
= create_font("fractional", &bitmap_lf
);
385 scale
= (i
+ height_orig
- 1) / height_orig
;
386 nearest_height
= scale
* height_orig
;
387 /* Only jump to the next height if the difference <= 25% original height */
388 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
389 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
390 so we'll not test this particular height. */
391 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
392 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
393 old_hfont
= SelectObject(hdc
, hfont
);
394 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
395 SelectObject(hdc
, old_hfont
);
399 /* test integer scaling 3x2 */
400 bitmap_lf
.lfHeight
= height_orig
* 2;
401 bitmap_lf
.lfWidth
*= 3;
402 hfont
= create_font("3x2", &bitmap_lf
);
403 old_hfont
= SelectObject(hdc
, hfont
);
404 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
405 SelectObject(hdc
, old_hfont
);
408 /* test integer scaling 3x3 */
409 bitmap_lf
.lfHeight
= height_orig
* 3;
410 bitmap_lf
.lfWidth
= 0;
411 hfont
= create_font("3x3", &bitmap_lf
);
412 old_hfont
= SelectObject(hdc
, hfont
);
413 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
414 SelectObject(hdc
, old_hfont
);
420 /* Test how GDI scales outline font metrics */
421 static void test_outline_font(void)
423 static const char test_str
[11] = "Test String";
426 HFONT hfont
, old_hfont
, old_hfont_2
;
427 OUTLINETEXTMETRICA otm
;
429 INT width_orig
, height_orig
, lfWidth
;
432 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
436 if(!winetest_interactive
)
438 skip("reactos bug 5401: Skipping outline font tests!\n");
442 if (!is_truetype_font_installed("Arial"))
444 skip("Arial is not installed\n");
448 hdc
= CreateCompatibleDC(0);
450 memset(&lf
, 0, sizeof(lf
));
451 strcpy(lf
.lfFaceName
, "Arial");
453 hfont
= create_font("outline", &lf
);
454 old_hfont
= SelectObject(hdc
, hfont
);
455 otm
.otmSize
= sizeof(otm
);
456 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
457 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
458 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
460 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
461 SelectObject(hdc
, old_hfont
);
464 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
465 lf
.lfHeight
= otm
.otmEMSquare
;
466 lf
.lfHeight
= -lf
.lfHeight
;
467 hfont
= create_font("outline", &lf
);
468 old_hfont
= SelectObject(hdc
, hfont
);
469 otm
.otmSize
= sizeof(otm
);
470 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
471 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
472 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
473 SelectObject(hdc
, old_hfont
);
476 height_orig
= otm
.otmTextMetrics
.tmHeight
;
477 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
479 /* test integer scaling 3x2 */
480 lf
.lfHeight
= height_orig
* 2;
481 lf
.lfWidth
= lfWidth
* 3;
482 hfont
= create_font("3x2", &lf
);
483 old_hfont
= SelectObject(hdc
, hfont
);
484 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
485 SelectObject(hdc
, old_hfont
);
488 /* test integer scaling 3x3 */
489 lf
.lfHeight
= height_orig
* 3;
490 lf
.lfWidth
= lfWidth
* 3;
491 hfont
= create_font("3x3", &lf
);
492 old_hfont
= SelectObject(hdc
, hfont
);
493 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
494 SelectObject(hdc
, old_hfont
);
497 /* test integer scaling 1x1 */
498 lf
.lfHeight
= height_orig
* 1;
499 lf
.lfWidth
= lfWidth
* 1;
500 hfont
= create_font("1x1", &lf
);
501 old_hfont
= SelectObject(hdc
, hfont
);
502 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
503 SelectObject(hdc
, old_hfont
);
506 /* test integer scaling 1x1 */
507 lf
.lfHeight
= height_orig
;
509 hfont
= create_font("1x1", &lf
);
510 old_hfont
= SelectObject(hdc
, hfont
);
511 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
513 /* with an identity matrix */
514 memset(&gm
, 0, sizeof(gm
));
515 SetLastError(0xdeadbeef);
516 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
517 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
518 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
519 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
520 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
521 /* with a custom matrix */
522 memset(&gm
, 0, sizeof(gm
));
523 SetLastError(0xdeadbeef);
524 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
525 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
526 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
527 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
528 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
530 /* Test that changing the DC transformation affects only the font
531 * selected on this DC and doesn't affect the same font selected on
534 hdc_2
= CreateCompatibleDC(0);
535 old_hfont_2
= SelectObject(hdc_2
, hfont
);
536 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
538 SetMapMode(hdc
, MM_ANISOTROPIC
);
540 /* font metrics on another DC should be unchanged */
541 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
543 /* test restrictions of compatibility mode GM_COMPATIBLE */
544 /* part 1: rescaling only X should not change font scaling on screen.
545 So compressing the X axis by 2 is not done, and this
546 appears as X scaling of 2 that no one requested. */
547 SetWindowExtEx(hdc
, 100, 100, NULL
);
548 SetViewportExtEx(hdc
, 50, 100, NULL
);
549 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
550 /* font metrics on another DC should be unchanged */
551 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
553 /* part 2: rescaling only Y should change font scaling.
554 As also X is scaled by a factor of 2, but this is not
555 requested by the DC transformation, we get a scaling factor
556 of 2 in the X coordinate. */
557 SetViewportExtEx(hdc
, 100, 200, NULL
);
558 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
559 /* font metrics on another DC should be unchanged */
560 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
562 /* restore scaling */
563 SetMapMode(hdc
, MM_TEXT
);
565 /* font metrics on another DC should be unchanged */
566 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
568 SelectObject(hdc_2
, old_hfont_2
);
571 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
573 SelectObject(hdc
, old_hfont
);
576 skip("GM_ADVANCED is not supported on this platform\n");
587 SetLastError(0xdeadbeef);
588 ret
= SetWorldTransform(hdc
, &xform
);
589 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
591 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
593 /* with an identity matrix */
594 memset(&gm
, 0, sizeof(gm
));
595 SetLastError(0xdeadbeef);
596 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
597 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
598 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
599 pt
.x
= width_orig
; pt
.y
= 0;
601 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
602 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
603 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
604 /* with a custom matrix */
605 memset(&gm
, 0, sizeof(gm
));
606 SetLastError(0xdeadbeef);
607 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
608 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
609 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
610 pt
.x
= width_orig
; pt
.y
= 0;
612 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
613 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
614 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
616 SetLastError(0xdeadbeef);
617 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
618 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
620 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
622 /* with an identity matrix */
623 memset(&gm
, 0, sizeof(gm
));
624 SetLastError(0xdeadbeef);
625 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
626 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
627 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
628 pt
.x
= width_orig
; pt
.y
= 0;
630 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
631 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
632 /* with a custom matrix */
633 memset(&gm
, 0, sizeof(gm
));
634 SetLastError(0xdeadbeef);
635 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
636 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
637 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
638 pt
.x
= width_orig
; pt
.y
= 0;
640 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
641 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
643 SetLastError(0xdeadbeef);
644 ret
= SetMapMode(hdc
, MM_TEXT
);
645 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
647 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
649 /* with an identity matrix */
650 memset(&gm
, 0, sizeof(gm
));
651 SetLastError(0xdeadbeef);
652 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
653 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
654 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
655 pt
.x
= width_orig
; pt
.y
= 0;
657 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
658 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
659 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
660 /* with a custom matrix */
661 memset(&gm
, 0, sizeof(gm
));
662 SetLastError(0xdeadbeef);
663 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
664 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
665 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
666 pt
.x
= width_orig
; pt
.y
= 0;
668 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
669 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
670 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
672 SelectObject(hdc
, old_hfont
);
677 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
679 LOGFONT
*lf
= (LOGFONT
*)lParam
;
681 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
684 return 0; /* stop enumeration */
686 return 1; /* continue enumeration */
689 static BOOL
is_CJK(void)
691 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
694 #define FH_SCALE 0x80000000
695 static void test_bitmap_font_metrics(void)
697 static const struct font_data
699 const char face_name
[LF_FACESIZE
];
700 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
701 int ave_char_width
, max_char_width
, dpi
;
702 BYTE first_char
, last_char
, def_char
, break_char
;
708 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
709 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
710 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
711 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
712 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
713 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
714 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 13 },
715 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
716 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
, 16 },
717 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
719 { "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 },
720 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
721 { "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 },
722 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
723 { "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 },
724 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
725 { "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 },
726 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
727 { "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 },
728 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
730 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
731 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
732 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
733 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
734 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
735 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
736 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
737 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
738 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
739 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
740 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
741 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
742 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
743 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
744 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
745 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
747 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
748 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
749 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
750 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
751 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
752 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
753 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
754 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
755 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
756 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
757 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
758 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
760 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
761 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
762 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
763 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
764 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
765 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
766 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
767 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
768 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
769 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
770 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
771 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
772 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
773 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
774 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
775 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
776 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
778 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
779 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
780 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
781 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
782 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
783 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
784 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
785 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
786 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
787 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
788 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
790 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
791 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
792 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
794 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
795 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
796 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
798 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
799 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
800 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
802 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
803 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
805 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
806 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
807 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
808 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
809 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
810 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
811 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
812 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
813 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
814 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
815 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
816 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
817 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
818 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
819 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
820 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
821 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
822 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
823 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
824 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
825 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
827 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
828 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
829 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
830 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
831 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
832 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
833 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
834 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
835 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
836 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
837 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
838 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
840 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
841 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
842 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
844 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
846 /* FIXME: add "Terminal" */
848 static const int font_log_pixels
[] = { 96, 120 };
851 HFONT hfont
, old_hfont
;
853 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
854 char face_name
[LF_FACESIZE
];
857 trace("system language id %04x\n", system_lang_id
);
859 expected_cs
= GetACP();
860 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
862 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
865 expected_cs
= csi
.ciCharset
;
866 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
868 hdc
= CreateCompatibleDC(0);
871 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
872 GetDeviceCaps(hdc
, LOGPIXELSY
));
874 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
877 for (i
= 0; i
< sizeof(font_log_pixels
)/sizeof(font_log_pixels
[0]); i
++)
879 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
883 font_res
= font_log_pixels
[i
];
886 trace("best font resolution is %d\n", font_res
);
888 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
892 memset(&lf
, 0, sizeof(lf
));
894 height
= fd
[i
].height
& ~FH_SCALE
;
895 lf
.lfHeight
= height
;
896 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
898 for(bit
= 0; bit
< 32; bit
++)
906 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
907 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
909 lf
.lfCharSet
= csi
.ciCharset
;
910 trace("looking for %s height %d charset %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
911 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
912 if (fd
[i
].height
& FH_SCALE
)
913 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
916 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
918 if (ret
) /* FIXME: Remove once Wine is fixed */
919 todo_wine
ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
921 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
924 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
927 hfont
= create_font(lf
.lfFaceName
, &lf
);
928 old_hfont
= SelectObject(hdc
, hfont
);
930 SetLastError(0xdeadbeef);
931 ret
= GetTextFace(hdc
, sizeof(face_name
), face_name
);
932 ok(ret
, "GetTextFace error %u\n", GetLastError());
934 if (lstrcmp(face_name
, fd
[i
].face_name
) != 0)
936 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
937 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
938 trace("Skipping replacement %s height %d charset %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
);
939 SelectObject(hdc
, old_hfont
);
944 memset(&gm
, 0, sizeof(gm
));
945 SetLastError(0xdeadbeef);
946 ret
= GetGlyphOutline(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
948 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
949 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
952 bRet
= GetTextMetrics(hdc
, &tm
);
953 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
955 SetLastError(0xdeadbeef);
956 ret
= GetTextCharset(hdc
);
957 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
958 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
960 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
962 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
963 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
965 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
967 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
968 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
970 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
971 if (fd
[i
].height
& FH_SCALE
)
972 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
);
974 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
);
975 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
976 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
977 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
);
978 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
);
979 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
);
980 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
981 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
982 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
983 make default char test fail */
984 if (tm
.tmCharSet
== lf
.lfCharSet
)
985 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
986 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
987 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
);
989 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
990 that make the max width bigger */
991 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
992 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
);
995 skip("Skipping font metrics test for system langid 0x%x\n",
998 SelectObject(hdc
, old_hfont
);
1006 static void test_GdiGetCharDimensions(void)
1012 LONG avgwidth
, height
;
1013 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1015 if (!pGdiGetCharDimensions
)
1017 win_skip("GdiGetCharDimensions not available on this platform\n");
1021 hdc
= CreateCompatibleDC(NULL
);
1023 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1024 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1026 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1027 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1028 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1030 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1031 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1033 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1034 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1037 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1038 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1039 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1044 static int CALLBACK
create_font_proc(const LOGFONT
*lpelfe
,
1045 const TEXTMETRIC
*lpntme
,
1046 DWORD FontType
, LPARAM lParam
)
1048 if (FontType
& TRUETYPE_FONTTYPE
)
1052 hfont
= CreateFontIndirect(lpelfe
);
1055 *(HFONT
*)lParam
= hfont
;
1063 static void test_GetCharABCWidths(void)
1065 static const WCHAR str
[] = {'a',0};
1087 {0xffffff, 0xffffff},
1088 {0x1000000, 0x1000000},
1089 {0xffffff, 0x1000000},
1090 {0xffffffff, 0xffffffff},
1098 BOOL r
[sizeof range
/ sizeof range
[0]];
1101 {ANSI_CHARSET
, 0x30, 0x30,
1102 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1103 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1104 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1105 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1106 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1107 {JOHAB_CHARSET
, 0x8446, 0x3135,
1108 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1109 {GB2312_CHARSET
, 0x8141, 0x4e04,
1110 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1111 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1112 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1116 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1118 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1122 memset(&lf
, 0, sizeof(lf
));
1123 strcpy(lf
.lfFaceName
, "System");
1126 hfont
= CreateFontIndirectA(&lf
);
1128 hfont
= SelectObject(hdc
, hfont
);
1130 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1131 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1133 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1134 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1136 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1137 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1139 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1140 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1142 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1143 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1145 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1146 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1148 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1149 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1151 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1152 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1154 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1155 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1157 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1158 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1160 hfont
= SelectObject(hdc
, hfont
);
1161 DeleteObject(hfont
);
1163 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1167 UINT code
= 0x41, j
;
1169 lf
.lfFaceName
[0] = '\0';
1170 lf
.lfCharSet
= c
[i
].cs
;
1171 lf
.lfPitchAndFamily
= 0;
1172 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1174 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1178 memset(a
, 0, sizeof a
);
1179 memset(w
, 0, sizeof w
);
1180 hfont
= SelectObject(hdc
, hfont
);
1181 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1182 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1183 memcmp(a
, w
, sizeof a
) == 0,
1184 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1186 memset(a
, 0xbb, sizeof a
);
1187 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1188 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1189 memset(full
, 0xcc, sizeof full
);
1190 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1191 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1192 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1193 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1195 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1197 memset(full
, 0xdd, sizeof full
);
1198 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1199 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1200 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1203 UINT last
= range
[j
].last
- range
[j
].first
;
1204 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1205 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1206 "GetCharABCWidthsA %x should match. codepage = %u\n",
1207 range
[j
].last
, c
[i
].cs
);
1211 hfont
= SelectObject(hdc
, hfont
);
1212 DeleteObject(hfont
);
1215 ReleaseDC(NULL
, hdc
);
1218 static void test_text_extents(void)
1220 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1222 INT i
, len
, fit1
, fit2
;
1231 memset(&lf
, 0, sizeof(lf
));
1232 strcpy(lf
.lfFaceName
, "Arial");
1235 hfont
= CreateFontIndirectA(&lf
);
1237 hfont
= SelectObject(hdc
, hfont
);
1238 GetTextMetricsA(hdc
, &tm
);
1239 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1240 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1242 SetLastError(0xdeadbeef);
1243 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1244 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1246 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1247 hfont
= SelectObject(hdc
, hfont
);
1248 DeleteObject(hfont
);
1254 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1255 extents
[0] = 1; /* So that the increasing sequence test will fail
1256 if the extents array is untouched. */
1257 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1258 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1259 ok(sz1
.cy
== sz2
.cy
,
1260 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1261 /* Because of the '\n' in the string GetTextExtentExPoint and
1262 GetTextExtentPoint return different widths under Win2k, but
1263 under WinXP they return the same width. So we don't test that
1266 for (i
= 1; i
< len
; ++i
)
1267 ok(extents
[i
-1] <= extents
[i
],
1268 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1270 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1271 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1272 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1273 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1274 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1275 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1276 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1277 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1278 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1279 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1280 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1281 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1282 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1283 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1284 HeapFree(GetProcessHeap(), 0, extents
);
1286 /* extents functions fail with -ve counts (the interesting case being -1) */
1287 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1288 ok(ret
== FALSE
, "got %d\n", ret
);
1289 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1290 ok(ret
== FALSE
, "got %d\n", ret
);
1291 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1292 ok(ret
== FALSE
, "got %d\n", ret
);
1294 /* max_extent = 0 succeeds and returns zero */
1296 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1298 broken(ret
== FALSE
), /* NT4, 2k */
1301 broken(fit1
== -215), /* NT4, 2k */
1302 "fit = %d\n", fit1
);
1303 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1304 ok(ret
== TRUE
, "got %d\n", ret
);
1305 ok(fit2
== 0, "fit = %d\n", fit2
);
1307 /* max_extent = -1 is interpreted as a very large width that will
1308 * definitely fit our three characters */
1310 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1311 ok(ret
== TRUE
, "got %d\n", ret
);
1312 ok(fit1
== 3, "fit = %d\n", fit1
);
1313 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1314 ok(ret
== TRUE
, "got %d\n", ret
);
1315 ok(fit2
== 3, "fit = %d\n", fit2
);
1317 /* max_extent = -2 is interpreted similarly, but the Ansi version
1318 * rejects it while the Unicode one accepts it */
1320 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1321 ok(ret
== FALSE
, "got %d\n", ret
);
1322 ok(fit1
== -215, "fit = %d\n", fit1
);
1323 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1324 ok(ret
== TRUE
, "got %d\n", ret
);
1325 ok(fit2
== 3, "fit = %d\n", fit2
);
1327 hfont
= SelectObject(hdc
, hfont
);
1328 DeleteObject(hfont
);
1329 ReleaseDC(NULL
, hdc
);
1332 static void test_GetGlyphIndices(void)
1339 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1340 WORD glyphs
[(sizeof(testtext
)/2)-1];
1344 if (!pGetGlyphIndicesW
) {
1345 win_skip("GetGlyphIndicesW not available on platform\n");
1351 memset(&lf
, 0, sizeof(lf
));
1352 strcpy(lf
.lfFaceName
, "System");
1354 lf
.lfCharSet
= ANSI_CHARSET
;
1356 hfont
= CreateFontIndirectA(&lf
);
1357 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1358 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1359 if (textm
.tmCharSet
== ANSI_CHARSET
)
1361 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1362 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1363 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1364 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1366 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1367 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1368 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1369 textm
.tmDefaultChar
, glyphs
[4]);
1372 /* FIXME: Write tests for non-ANSI charsets. */
1373 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1375 if(!is_font_installed("Tahoma"))
1377 skip("Tahoma is not installed so skipping this test\n");
1380 memset(&lf
, 0, sizeof(lf
));
1381 strcpy(lf
.lfFaceName
, "Tahoma");
1384 hfont
= CreateFontIndirectA(&lf
);
1385 hOldFont
= SelectObject(hdc
, hfont
);
1386 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1387 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1388 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1389 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1390 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1392 testtext
[0] = textm
.tmDefaultChar
;
1393 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1394 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1395 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1396 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1397 DeleteObject(SelectObject(hdc
, hOldFont
));
1400 static void test_GetKerningPairs(void)
1402 static const struct kerning_data
1404 const char face_name
[LF_FACESIZE
];
1406 /* some interesting fields from OUTLINETEXTMETRIC */
1407 LONG tmHeight
, tmAscent
, tmDescent
;
1412 UINT otmsCapEmHeight
;
1417 UINT otmusMinimumPPEM
;
1418 /* small subset of kerning pairs to test */
1419 DWORD total_kern_pairs
;
1420 const KERNINGPAIR kern_pair
[26];
1423 {"Arial", 12, 12, 9, 3,
1424 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1427 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1428 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1429 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1430 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1431 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1432 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1433 {933,970,+1},{933,972,-1}
1436 {"Arial", -34, 39, 32, 7,
1437 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1440 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1441 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1442 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1443 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1444 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1445 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1446 {933,970,+2},{933,972,-3}
1449 { "Arial", 120, 120, 97, 23,
1450 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1453 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1454 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1455 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1456 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1457 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1458 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1459 {933,970,+6},{933,972,-10}
1462 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1463 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1464 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1467 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1468 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1469 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1470 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1471 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1472 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1473 {933,970,+54},{933,972,-83}
1479 HFONT hfont
, hfont_old
;
1480 KERNINGPAIR
*kern_pair
;
1482 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1486 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1487 * which may render this test unusable, so we're trying to avoid that.
1489 SetLastError(0xdeadbeef);
1490 GetKerningPairsW(hdc
, 0, NULL
);
1491 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1493 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1498 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1500 OUTLINETEXTMETRICW otm
;
1503 if (!is_font_installed(kd
[i
].face_name
))
1505 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1509 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1511 memset(&lf
, 0, sizeof(lf
));
1512 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1513 lf
.lfHeight
= kd
[i
].height
;
1514 hfont
= CreateFontIndirect(&lf
);
1517 hfont_old
= SelectObject(hdc
, hfont
);
1519 SetLastError(0xdeadbeef);
1520 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1521 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1522 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1524 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
), "expected %d, got %d\n",
1525 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1526 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
), "expected %d, got %d\n",
1527 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1528 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1529 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1531 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1532 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1533 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1534 kd
[i
].otmAscent
, otm
.otmAscent
);
1535 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1536 kd
[i
].otmDescent
, otm
.otmDescent
);
1537 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1538 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1539 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1540 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1541 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1542 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1544 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1545 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1546 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1547 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1548 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1549 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1550 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1551 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1552 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1555 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1556 trace("total_kern_pairs %u\n", total_kern_pairs
);
1557 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1559 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1562 SetLastError(0xdeadbeef);
1563 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1564 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1565 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1566 ok(ret
== 0, "got %u, expected 0\n", ret
);
1568 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1569 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1571 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1572 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1574 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1575 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1579 for (n
= 0; n
< ret
; n
++)
1582 /* Disabled to limit console spam */
1583 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1584 trace("{'%c','%c',%d},\n",
1585 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1586 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1588 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1589 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1591 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1592 "pair %d:%d got %d, expected %d\n",
1593 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1594 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1600 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1601 matches
, kd
[i
].total_kern_pairs
);
1603 HeapFree(GetProcessHeap(), 0, kern_pair
);
1605 SelectObject(hdc
, hfont_old
);
1606 DeleteObject(hfont
);
1612 static void test_height_selection(void)
1614 static const struct font_data
1616 const char face_name
[LF_FACESIZE
];
1617 int requested_height
;
1618 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1621 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96 },
1622 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96 },
1623 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96 },
1624 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96 },
1625 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96 },
1626 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96 },
1627 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96 },
1628 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96 },
1629 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96 },
1630 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96 }
1634 HFONT hfont
, old_hfont
;
1638 hdc
= CreateCompatibleDC(0);
1641 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
1643 if (!is_truetype_font_installed(fd
[i
].face_name
))
1645 skip("%s is not installed\n", fd
[i
].face_name
);
1649 memset(&lf
, 0, sizeof(lf
));
1650 lf
.lfHeight
= fd
[i
].requested_height
;
1651 lf
.lfWeight
= fd
[i
].weight
;
1652 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1654 hfont
= CreateFontIndirect(&lf
);
1657 old_hfont
= SelectObject(hdc
, hfont
);
1658 ret
= GetTextMetrics(hdc
, &tm
);
1659 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1660 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1662 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1663 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
);
1664 ok(match_off_by_1(tm
.tmHeight
, fd
[i
].height
), "%s(%d): tm.tmHeight %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmHeight
, fd
[i
].height
);
1665 ok(match_off_by_1(tm
.tmAscent
, fd
[i
].ascent
), "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmAscent
, fd
[i
].ascent
);
1666 ok(match_off_by_1(tm
.tmDescent
, fd
[i
].descent
), "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmDescent
, fd
[i
].descent
);
1667 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1668 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].requested_height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
1670 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
);
1673 SelectObject(hdc
, old_hfont
);
1674 DeleteObject(hfont
);
1680 static void test_GetOutlineTextMetrics(void)
1682 OUTLINETEXTMETRIC
*otm
;
1684 HFONT hfont
, hfont_old
;
1686 DWORD ret
, otm_size
;
1689 if (!is_font_installed("Arial"))
1691 skip("Arial is not installed\n");
1697 memset(&lf
, 0, sizeof(lf
));
1698 strcpy(lf
.lfFaceName
, "Arial");
1700 lf
.lfWeight
= FW_NORMAL
;
1701 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1702 lf
.lfQuality
= PROOF_QUALITY
;
1703 hfont
= CreateFontIndirect(&lf
);
1706 hfont_old
= SelectObject(hdc
, hfont
);
1707 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1708 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1710 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1712 memset(otm
, 0xAA, otm_size
);
1713 SetLastError(0xdeadbeef);
1714 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1715 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1716 ok(ret
== 1 /* Win9x */ ||
1717 ret
== otm
->otmSize
/* XP*/,
1718 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1719 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1721 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1722 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1723 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1724 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1727 memset(otm
, 0xAA, otm_size
);
1728 SetLastError(0xdeadbeef);
1729 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1730 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1731 ok(ret
== 1 /* Win9x */ ||
1732 ret
== otm
->otmSize
/* XP*/,
1733 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1734 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1736 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1737 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1738 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1739 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1742 /* ask about truncated data */
1743 memset(otm
, 0xAA, otm_size
);
1744 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1745 SetLastError(0xdeadbeef);
1746 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1747 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1748 ok(ret
== 1 /* Win9x */ ||
1749 ret
== otm
->otmSize
/* XP*/,
1750 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1751 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1753 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1754 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1755 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1757 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1759 HeapFree(GetProcessHeap(), 0, otm
);
1761 SelectObject(hdc
, hfont_old
);
1762 DeleteObject(hfont
);
1767 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1771 areaWidth
= clientArea
->right
- clientArea
->left
,
1773 PSTR pFirstChar
, pLastChar
;
1780 int GetTextExtentExPointWWidth
;
1783 GetTextMetricsA(hdc
, &tm
);
1784 y
= clientArea
->top
;
1787 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1793 /* if not at the end of the string, ... */
1794 if (*str
== '\0') break;
1795 /* ... add the next word to the current extent */
1796 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1798 SetTextJustification(hdc
, 0, 0);
1799 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1800 } while ((int) size
.cx
< areaWidth
);
1802 /* ignore trailing break chars */
1804 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1810 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1812 SetTextJustification(hdc
, 0, 0);
1813 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1815 /* do not justify the last extent */
1816 if (*str
!= '\0' && breakCount
> 0)
1818 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1819 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1820 if (size
.cx
!= areaWidth
&& nErrors
< sizeof(error
)/sizeof(error
[0]) - 1)
1822 error
[nErrors
].start
= pFirstChar
;
1823 error
[nErrors
].len
= pLastChar
- pFirstChar
;
1824 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
1829 trace( "%u %.*s\n", size
.cx
, (int)(pLastChar
- pFirstChar
), pFirstChar
);
1833 } while (*str
&& y
< clientArea
->bottom
);
1835 for (e
= 0; e
< nErrors
; e
++)
1837 /* The width returned by GetTextExtentPoint32() is exactly the same
1838 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1839 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1840 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
1841 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1845 static void test_SetTextJustification(void)
1855 static char testText
[] =
1856 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1857 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1858 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1859 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1860 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1861 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1862 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1864 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1865 GetClientRect( hwnd
, &clientArea
);
1866 hdc
= GetDC( hwnd
);
1868 memset(&lf
, 0, sizeof lf
);
1869 lf
.lfCharSet
= ANSI_CHARSET
;
1870 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1871 lf
.lfWeight
= FW_DONTCARE
;
1873 lf
.lfQuality
= DEFAULT_QUALITY
;
1874 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1875 hfont
= create_font("Times New Roman", &lf
);
1876 SelectObject(hdc
, hfont
);
1878 testJustification(hdc
, testText
, &clientArea
);
1880 if (!pGetGlyphIndicesA
|| !pGetTextExtentExPointI
) goto done
;
1881 pGetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
1883 SetTextJustification(hdc
, 0, 0);
1884 GetTextExtentPoint32(hdc
, " ", 1, &expect
);
1885 GetTextExtentPoint32(hdc
, " ", 3, &size
);
1886 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1887 SetTextJustification(hdc
, 4, 1);
1888 GetTextExtentPoint32(hdc
, " ", 1, &size
);
1889 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1890 SetTextJustification(hdc
, 9, 2);
1891 GetTextExtentPoint32(hdc
, " ", 2, &size
);
1892 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1893 SetTextJustification(hdc
, 7, 3);
1894 GetTextExtentPoint32(hdc
, " ", 3, &size
);
1895 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1896 SetTextJustification(hdc
, 7, 3);
1897 SetTextCharacterExtra(hdc
, 2 );
1898 GetTextExtentPoint32(hdc
, " ", 3, &size
);
1899 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1900 SetTextJustification(hdc
, 0, 0);
1901 SetTextCharacterExtra(hdc
, 0);
1902 size
.cx
= size
.cy
= 1234;
1903 GetTextExtentPoint32(hdc
, " ", 0, &size
);
1904 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
1905 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
1906 SetTextJustification(hdc
, 5, 1);
1907 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
1908 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1909 SetTextJustification(hdc
, 0, 0);
1911 SetMapMode( hdc
, MM_ANISOTROPIC
);
1912 SetWindowExtEx( hdc
, 2, 2, NULL
);
1913 GetClientRect( hwnd
, &clientArea
);
1914 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
1915 testJustification(hdc
, testText
, &clientArea
);
1917 GetTextExtentPoint32(hdc
, "A", 1, &expect
);
1918 for (i
= 0; i
< 10; i
++)
1920 SetTextCharacterExtra(hdc
, i
);
1921 GetTextExtentPoint32(hdc
, "A", 1, &size
);
1922 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
1924 SetTextCharacterExtra(hdc
, 0);
1925 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
1926 for (i
= 0; i
< 10; i
++)
1928 SetTextCharacterExtra(hdc
, i
);
1929 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
1930 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
1932 SetTextCharacterExtra(hdc
, 0);
1934 SetViewportExtEx( hdc
, 3, 3, NULL
);
1935 GetClientRect( hwnd
, &clientArea
);
1936 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
1937 testJustification(hdc
, testText
, &clientArea
);
1939 GetTextExtentPoint32(hdc
, "A", 1, &expect
);
1940 for (i
= 0; i
< 10; i
++)
1942 SetTextCharacterExtra(hdc
, i
);
1943 GetTextExtentPoint32(hdc
, "A", 1, &size
);
1944 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
1948 DeleteObject(hfont
);
1949 ReleaseDC(hwnd
, hdc
);
1950 DestroyWindow(hwnd
);
1953 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1957 HFONT hfont
, hfont_old
;
1964 assert(count
<= 128);
1966 memset(&lf
, 0, sizeof(lf
));
1968 lf
.lfCharSet
= charset
;
1970 lstrcpyA(lf
.lfFaceName
, "Arial");
1971 SetLastError(0xdeadbeef);
1972 hfont
= CreateFontIndirectA(&lf
);
1973 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1976 hfont_old
= SelectObject(hdc
, hfont
);
1978 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1979 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1981 SetLastError(0xdeadbeef);
1982 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1983 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1985 if (charset
== SYMBOL_CHARSET
)
1987 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1988 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1992 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1993 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1996 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1998 trace("Can't find codepage for charset %d\n", cs
);
2002 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
2004 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
2006 skip("Font code page %d, looking for code page %d\n",
2007 pGdiGetCodePage(hdc
), code_page
);
2015 WCHAR unicode_buf
[128];
2017 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2019 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2021 SetLastError(0xdeadbeef);
2022 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2023 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2024 count
, ret
, GetLastError());
2030 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2032 SetLastError(0xdeadbeef);
2033 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2034 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2035 count
, ret
, GetLastError());
2038 SelectObject(hdc
, hfont_old
);
2039 DeleteObject(hfont
);
2046 static void test_font_charset(void)
2048 static struct charset_data
2052 WORD font_idxA
[128], font_idxW
[128];
2055 { ANSI_CHARSET
, 1252 },
2056 { RUSSIAN_CHARSET
, 1251 },
2057 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2061 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
2063 win_skip("Skipping the font charset test on a Win9x platform\n");
2067 if (!is_font_installed("Arial"))
2069 skip("Arial is not installed\n");
2073 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
2075 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2077 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2079 skip("Symbol or Wingdings is not installed\n");
2083 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2084 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2085 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2088 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2091 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2092 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2095 skip("Symbol or Wingdings is not installed\n");
2098 static void test_GdiGetCodePage(void)
2100 static const struct _matching_data
2102 UINT current_codepage
;
2105 UINT expected_codepage
;
2106 } matching_data
[] = {
2107 {1251, "Arial", ANSI_CHARSET
, 1252},
2108 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2110 {1252, "Arial", ANSI_CHARSET
, 1252},
2111 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2113 {1253, "Arial", ANSI_CHARSET
, 1252},
2114 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2116 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2117 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2118 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2120 { 936, "Arial", ANSI_CHARSET
, 936},
2121 { 936, "Tahoma", ANSI_CHARSET
, 936},
2122 { 936, "Simsun", ANSI_CHARSET
, 936},
2124 { 949, "Arial", ANSI_CHARSET
, 949},
2125 { 949, "Tahoma", ANSI_CHARSET
, 949},
2126 { 949, "Gulim", ANSI_CHARSET
, 949},
2128 { 950, "Arial", ANSI_CHARSET
, 950},
2129 { 950, "Tahoma", ANSI_CHARSET
, 950},
2130 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2139 if (!pGdiGetCodePage
)
2141 skip("GdiGetCodePage not available on this platform\n");
2147 for (i
= 0; i
< sizeof(matching_data
) / sizeof(struct _matching_data
); i
++)
2149 /* only test data matched current locale codepage */
2150 if (matching_data
[i
].current_codepage
!= acp
)
2153 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2155 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2161 memset(&lf
, 0, sizeof(lf
));
2163 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2164 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2165 hfont
= CreateFontIndirectA(&lf
);
2166 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2168 hfont
= SelectObject(hdc
, hfont
);
2169 charset
= GetTextCharset(hdc
);
2170 codepage
= pGdiGetCodePage(hdc
);
2171 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2172 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
, matching_data
[i
].expected_codepage
);
2173 ok(codepage
== matching_data
[i
].expected_codepage
,
2174 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2176 hfont
= SelectObject(hdc
, hfont
);
2177 DeleteObject(hfont
);
2178 ReleaseDC(NULL
, hdc
);
2182 static void test_GetFontUnicodeRanges(void)
2186 HFONT hfont
, hfont_old
;
2191 if (!pGetFontUnicodeRanges
)
2193 win_skip("GetFontUnicodeRanges not available before W2K\n");
2197 memset(&lf
, 0, sizeof(lf
));
2198 lstrcpyA(lf
.lfFaceName
, "Arial");
2199 hfont
= create_font("Arial", &lf
);
2202 hfont_old
= SelectObject(hdc
, hfont
);
2204 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2205 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2207 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2208 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2210 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2212 size
= pGetFontUnicodeRanges(hdc
, gs
);
2213 ok(size
, "GetFontUnicodeRanges failed\n");
2215 if (0) /* Disabled to limit console spam */
2216 for (i
= 0; i
< gs
->cRanges
; i
++)
2217 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2218 trace("found %u ranges\n", gs
->cRanges
);
2220 HeapFree(GetProcessHeap(), 0, gs
);
2222 SelectObject(hdc
, hfont_old
);
2223 DeleteObject(hfont
);
2224 ReleaseDC(NULL
, hdc
);
2227 #define MAX_ENUM_FONTS 4096
2229 struct enum_font_data
2232 LOGFONT lf
[MAX_ENUM_FONTS
];
2235 struct enum_fullname_data
2238 ENUMLOGFONT elf
[MAX_ENUM_FONTS
];
2241 struct enum_font_dataW
2244 LOGFONTW lf
[MAX_ENUM_FONTS
];
2247 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
2249 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2250 const NEWTEXTMETRIC
*ntm
= (const NEWTEXTMETRIC
*)tm
;
2252 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2253 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2255 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2257 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2259 if (0) /* Disabled to limit console spam */
2260 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2261 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2262 if (efd
->total
< MAX_ENUM_FONTS
)
2263 efd
->lf
[efd
->total
++] = *lf
;
2265 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2270 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2272 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2273 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2275 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2276 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2278 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2280 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2282 if (0) /* Disabled to limit console spam */
2283 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2284 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2285 if (efd
->total
< MAX_ENUM_FONTS
)
2286 efd
->lf
[efd
->total
++] = *lf
;
2288 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2293 static void get_charset_stats(struct enum_font_data
*efd
,
2294 int *ansi_charset
, int *symbol_charset
,
2295 int *russian_charset
)
2300 *symbol_charset
= 0;
2301 *russian_charset
= 0;
2303 for (i
= 0; i
< efd
->total
; i
++)
2305 switch (efd
->lf
[i
].lfCharSet
)
2310 case SYMBOL_CHARSET
:
2311 (*symbol_charset
)++;
2313 case RUSSIAN_CHARSET
:
2314 (*russian_charset
)++;
2320 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2321 int *ansi_charset
, int *symbol_charset
,
2322 int *russian_charset
)
2327 *symbol_charset
= 0;
2328 *russian_charset
= 0;
2330 for (i
= 0; i
< efd
->total
; i
++)
2332 switch (efd
->lf
[i
].lfCharSet
)
2337 case SYMBOL_CHARSET
:
2338 (*symbol_charset
)++;
2340 case RUSSIAN_CHARSET
:
2341 (*russian_charset
)++;
2347 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2349 struct enum_font_data efd
;
2350 struct enum_font_dataW efdw
;
2353 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2355 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2357 if (*font_name
&& !is_truetype_font_installed(font_name
))
2359 skip("%s is not installed\n", font_name
);
2365 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2366 * while EnumFontFamiliesEx doesn't.
2368 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2371 * Use EnumFontFamiliesW since win98 crashes when the
2372 * second parameter is NULL using EnumFontFamilies
2375 SetLastError(0xdeadbeef);
2376 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2377 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2380 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2381 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2382 ansi_charset
, symbol_charset
, russian_charset
);
2383 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2384 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2385 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2386 ok(russian_charset
> 0 ||
2387 broken(russian_charset
== 0), /* NT4 */
2388 "NULL family should enumerate RUSSIAN_CHARSET\n");
2392 SetLastError(0xdeadbeef);
2393 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2394 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2397 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2398 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2399 ansi_charset
, symbol_charset
, russian_charset
);
2400 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2401 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2402 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2403 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2408 SetLastError(0xdeadbeef);
2409 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2410 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2411 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2412 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2413 ansi_charset
, symbol_charset
, russian_charset
,
2414 *font_name
? font_name
: "<empty>");
2416 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2418 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2419 for (i
= 0; i
< efd
.total
; i
++)
2421 /* FIXME: remove completely once Wine is fixed */
2422 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2425 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2428 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2429 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2430 font_name
, efd
.lf
[i
].lfFaceName
);
2433 memset(&lf
, 0, sizeof(lf
));
2434 lf
.lfCharSet
= ANSI_CHARSET
;
2435 lstrcpy(lf
.lfFaceName
, font_name
);
2437 SetLastError(0xdeadbeef);
2438 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2439 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2440 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2441 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2442 ansi_charset
, symbol_charset
, russian_charset
,
2443 *font_name
? font_name
: "<empty>");
2444 if (font_charset
== SYMBOL_CHARSET
)
2447 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2449 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2453 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2454 for (i
= 0; i
< efd
.total
; i
++)
2456 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2458 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2459 font_name
, efd
.lf
[i
].lfFaceName
);
2463 /* DEFAULT_CHARSET should enumerate all available charsets */
2464 memset(&lf
, 0, sizeof(lf
));
2465 lf
.lfCharSet
= DEFAULT_CHARSET
;
2466 lstrcpy(lf
.lfFaceName
, font_name
);
2468 SetLastError(0xdeadbeef);
2469 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2470 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2471 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2472 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2473 ansi_charset
, symbol_charset
, russian_charset
,
2474 *font_name
? font_name
: "<empty>");
2475 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2476 for (i
= 0; i
< efd
.total
; i
++)
2479 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2480 font_name
, efd
.lf
[i
].lfFaceName
);
2484 switch (font_charset
)
2487 ok(ansi_charset
> 0,
2488 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2490 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2491 ok(russian_charset
> 0,
2492 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2494 case SYMBOL_CHARSET
:
2496 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2498 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2499 ok(!russian_charset
,
2500 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2502 case DEFAULT_CHARSET
:
2503 ok(ansi_charset
> 0,
2504 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2505 ok(symbol_charset
> 0,
2506 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2507 ok(russian_charset
> 0,
2508 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2514 ok(ansi_charset
> 0,
2515 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2516 ok(symbol_charset
> 0,
2517 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2518 ok(russian_charset
> 0,
2519 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2522 memset(&lf
, 0, sizeof(lf
));
2523 lf
.lfCharSet
= SYMBOL_CHARSET
;
2524 lstrcpy(lf
.lfFaceName
, font_name
);
2526 SetLastError(0xdeadbeef);
2527 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2528 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2529 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2530 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2531 ansi_charset
, symbol_charset
, russian_charset
,
2532 *font_name
? font_name
: "<empty>");
2533 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2534 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2537 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2538 for (i
= 0; i
< efd
.total
; i
++)
2540 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2542 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2543 font_name
, efd
.lf
[i
].lfFaceName
);
2547 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2548 ok(symbol_charset
> 0,
2549 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2550 ok(!russian_charset
,
2551 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2557 static INT CALLBACK
enum_font_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2559 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2561 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2563 if (efd
->total
< MAX_ENUM_FONTS
)
2564 efd
->lf
[efd
->total
++] = *lf
;
2566 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2571 static INT CALLBACK
enum_fullname_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2573 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
2575 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2577 if (efnd
->total
< MAX_ENUM_FONTS
)
2578 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONT
*)lf
;
2580 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2585 static void test_EnumFontFamiliesEx_default_charset(void)
2587 struct enum_font_data efd
;
2588 LOGFONT gui_font
, enum_font
;
2592 ret
= GetObject(GetStockObject(DEFAULT_GUI_FONT
), sizeof(gui_font
), &gui_font
);
2593 ok(ret
, "GetObject failed.\n");
2600 memset(&enum_font
, 0, sizeof(enum_font
));
2601 lstrcpy(enum_font
.lfFaceName
, gui_font
.lfFaceName
);
2602 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
2603 EnumFontFamiliesEx(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
2606 if (efd
.total
== 0) {
2607 skip("'%s' is not found or not a TrueType font.\n", gui_font
.lfFaceName
);
2610 trace("'%s' has %d charsets.\n", gui_font
.lfFaceName
, efd
.total
);
2612 ok(efd
.lf
[0].lfCharSet
== gui_font
.lfCharSet
|| broken(system_lang_id
== LANG_ARABIC
),
2613 "(%s) got charset %d expected %d\n",
2614 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, gui_font
.lfCharSet
);
2619 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2621 HFONT hfont
, hfont_prev
;
2623 GLYPHMETRICS gm1
, gm2
;
2627 if(!pGetGlyphIndicesA
)
2630 /* negative widths are handled just as positive ones */
2631 lf2
.lfWidth
= -lf
->lfWidth
;
2633 SetLastError(0xdeadbeef);
2634 hfont
= CreateFontIndirectA(lf
);
2635 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2636 check_font("original", lf
, hfont
);
2638 hfont_prev
= SelectObject(hdc
, hfont
);
2640 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2641 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2643 SelectObject(hdc
, hfont_prev
);
2644 DeleteObject(hfont
);
2645 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2649 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2650 memset(&gm1
, 0xab, sizeof(gm1
));
2651 SetLastError(0xdeadbeef);
2652 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2653 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2655 SelectObject(hdc
, hfont_prev
);
2656 DeleteObject(hfont
);
2658 SetLastError(0xdeadbeef);
2659 hfont
= CreateFontIndirectA(&lf2
);
2660 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2661 check_font("negative width", &lf2
, hfont
);
2663 hfont_prev
= SelectObject(hdc
, hfont
);
2665 memset(&gm2
, 0xbb, sizeof(gm2
));
2666 SetLastError(0xdeadbeef);
2667 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2668 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2670 SelectObject(hdc
, hfont_prev
);
2671 DeleteObject(hfont
);
2673 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2674 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2675 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2676 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2677 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2678 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2679 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2680 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2681 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2682 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2683 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2686 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2687 #include "pshpack2.h"
2691 SHORT xAvgCharWidth
;
2692 USHORT usWeightClass
;
2693 USHORT usWidthClass
;
2695 SHORT ySubscriptXSize
;
2696 SHORT ySubscriptYSize
;
2697 SHORT ySubscriptXOffset
;
2698 SHORT ySubscriptYOffset
;
2699 SHORT ySuperscriptXSize
;
2700 SHORT ySuperscriptYSize
;
2701 SHORT ySuperscriptXOffset
;
2702 SHORT ySuperscriptYOffset
;
2703 SHORT yStrikeoutSize
;
2704 SHORT yStrikeoutPosition
;
2707 ULONG ulUnicodeRange1
;
2708 ULONG ulUnicodeRange2
;
2709 ULONG ulUnicodeRange3
;
2710 ULONG ulUnicodeRange4
;
2713 USHORT usFirstCharIndex
;
2714 USHORT usLastCharIndex
;
2715 /* According to the Apple spec, original version didn't have the below fields,
2716 * version numbers were taken from the OpenType spec.
2718 /* version 0 (TrueType 1.5) */
2719 USHORT sTypoAscender
;
2720 USHORT sTypoDescender
;
2721 USHORT sTypoLineGap
;
2723 USHORT usWinDescent
;
2724 /* version 1 (TrueType 1.66) */
2725 ULONG ulCodePageRange1
;
2726 ULONG ulCodePageRange2
;
2727 /* version 2 (OpenType 1.2) */
2730 USHORT usDefaultChar
;
2732 USHORT usMaxContext
;
2734 #include "poppack.h"
2736 #ifdef WORDS_BIGENDIAN
2737 #define GET_BE_WORD(x) (x)
2738 #define GET_BE_DWORD(x) (x)
2740 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2741 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2744 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2745 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2746 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2747 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2748 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2749 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2762 } cmap_encoding_record
;
2770 BYTE glyph_ids
[256];
2780 USHORT search_range
;
2781 USHORT entry_selector
;
2784 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2787 USHORT start_count[seg_countx2 / 2];
2788 USHORT id_delta[seg_countx2 / 2];
2789 USHORT id_range_offset[seg_countx2 / 2];
2799 USHORT id_range_offset
;
2800 } cmap_format_4_seg
;
2802 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2804 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
2805 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
2806 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2807 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2808 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2811 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2814 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2818 for(i
= 0; i
< 256; i
++)
2820 if(cmap
->glyph_ids
[i
] == 0) continue;
2822 if(*first
== 256) *first
= i
;
2824 if(*first
== 256) return FALSE
;
2828 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2830 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2831 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2832 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2833 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2834 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2837 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2840 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2841 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2842 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2846 for(i
= 0; i
< seg_count
; i
++)
2849 cmap_format_4_seg seg
;
2851 get_seg4(cmap
, i
, &seg
);
2852 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2854 if(seg
.id_range_offset
== 0)
2855 index
= (seg
.id_delta
+ code
) & 0xffff;
2858 index
= seg
.id_range_offset
/ 2
2859 + code
- seg
.start_count
2862 /* some fonts have broken last segment */
2863 if ((char *)(glyph_ids
+ index
+ 1) < (char *)ptr
+ limit
)
2864 index
= GET_BE_WORD(glyph_ids
[index
]);
2867 trace("segment %04x/%04x index %04x points to nowhere\n",
2868 seg
.start_count
, seg
.end_count
, index
);
2871 if(index
) index
+= seg
.id_delta
;
2873 if(*first
== 0x10000)
2874 *last
= *first
= code
;
2880 if(*first
== 0x10000) return FALSE
;
2884 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2887 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2889 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2891 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2892 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2905 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2908 cmap_header
*header
;
2913 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2914 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2915 if(size
== GDI_ERROR
) return FALSE
;
2917 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2918 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2919 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2920 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2922 cmap
= get_cmap(header
, 3, 1);
2924 *cmap_type
= cmap_ms_unicode
;
2927 cmap
= get_cmap(header
, 3, 0);
2928 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2932 *cmap_type
= cmap_none
;
2936 format
= GET_BE_WORD(*(WORD
*)cmap
);
2940 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2943 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2946 trace("unhandled cmap format %d\n", format
);
2951 HeapFree(GetProcessHeap(), 0, header
);
2955 #define TT_PLATFORM_MICROSOFT 3
2956 #define TT_MS_ID_SYMBOL_CS 0
2957 #define TT_MS_ID_UNICODE_CS 1
2958 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2959 #define TT_NAME_ID_FONT_FAMILY 1
2960 #define TT_NAME_ID_FONT_SUBFAMILY 2
2961 #define TT_NAME_ID_UNIQUE_ID 3
2962 #define TT_NAME_ID_FULL_NAME 4
2964 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
2966 struct sfnt_name_header
2969 USHORT number_of_record
;
2970 USHORT storage_offset
;
2982 LONG size
, offset
, length
;
2988 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
2989 ok(size
!= GDI_ERROR
, "no name table found\n");
2990 if(size
== GDI_ERROR
) return FALSE
;
2992 data
= HeapAlloc(GetProcessHeap(), 0, size
);
2993 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
2994 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2996 header
= (void *)data
;
2997 header
->format
= GET_BE_WORD(header
->format
);
2998 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
2999 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
3000 if (header
->format
!= 0)
3002 trace("got format %u\n", header
->format
);
3005 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
3007 trace("number records out of range: %d\n", header
->number_of_record
);
3010 if (header
->storage_offset
>= size
)
3012 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3016 entry
= (void *)&header
[1];
3017 for (i
= 0; i
< header
->number_of_record
; i
++)
3019 if (GET_BE_WORD(entry
[i
].platform_id
) != TT_PLATFORM_MICROSOFT
||
3020 (GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_UNICODE_CS
&& GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_SYMBOL_CS
) ||
3021 GET_BE_WORD(entry
[i
].language_id
) != language_id
||
3022 GET_BE_WORD(entry
[i
].name_id
) != name_id
)
3027 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[i
].offset
);
3028 length
= GET_BE_WORD(entry
[i
].length
);
3029 if (offset
+ length
> size
)
3031 trace("entry %d is out of range\n", i
);
3034 if (length
>= out_size
)
3036 trace("buffer too small for entry %d\n", i
);
3040 name
= (WCHAR
*)(data
+ offset
);
3041 for (c
= 0; c
< length
/ 2; c
++)
3042 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3050 HeapFree(GetProcessHeap(), 0, data
);
3054 static void test_text_metrics(const LOGFONT
*lf
, const NEWTEXTMETRIC
*ntm
)
3057 HFONT hfont
, hfont_old
;
3061 const char *font_name
= lf
->lfFaceName
;
3062 DWORD cmap_first
= 0, cmap_last
= 0;
3063 UINT ascent
, descent
, cell_height
;
3064 cmap_type cmap_type
;
3065 BOOL sys_lang_non_english
;
3067 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3070 SetLastError(0xdeadbeef);
3071 hfont
= CreateFontIndirectA(lf
);
3072 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3074 hfont_old
= SelectObject(hdc
, hfont
);
3076 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3077 if (size
== GDI_ERROR
)
3079 trace("OS/2 chunk was not found\n");
3082 if (size
> sizeof(tt_os2
))
3084 trace("got too large OS/2 chunk of size %u\n", size
);
3085 size
= sizeof(tt_os2
);
3088 memset(&tt_os2
, 0, sizeof(tt_os2
));
3089 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3090 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3092 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3093 descent
= GET_BE_WORD(tt_os2
.usWinDescent
);
3094 cell_height
= ascent
+ descent
;
3095 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3096 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3098 SetLastError(0xdeadbeef);
3099 ret
= GetTextMetricsA(hdc
, &tmA
);
3100 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3102 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3104 skip("Unable to retrieve first and last glyphs from cmap\n");
3108 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3109 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3110 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3114 version
= GET_BE_WORD(tt_os2
.version
);
3116 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3117 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3118 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3119 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3121 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3122 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3123 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3125 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3130 case 1257: /* Baltic */
3131 expect_last_W
= 0xf8fd;
3134 expect_last_W
= 0xf0ff;
3136 expect_break_W
= 0x20;
3137 expect_default_W
= expect_break_W
- 1;
3138 expect_first_A
= 0x1e;
3139 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3143 expect_first_W
= cmap_first
;
3144 expect_last_W
= min(cmap_last
, os2_last_char
);
3145 if(os2_first_char
<= 1)
3146 expect_break_W
= os2_first_char
+ 2;
3147 else if(os2_first_char
> 0xff)
3148 expect_break_W
= 0x20;
3150 expect_break_W
= os2_first_char
;
3151 expect_default_W
= expect_break_W
- 1;
3152 expect_first_A
= expect_default_W
- 1;
3153 expect_last_A
= min(expect_last_W
, 0xff);
3155 expect_break_A
= expect_break_W
;
3156 expect_default_A
= expect_default_W
;
3158 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3159 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3160 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
3161 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3162 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3164 ok(tmA
.tmFirstChar
== expect_first_A
||
3165 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3166 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3167 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3168 ok(tmA
.tmLastChar
== expect_last_A
||
3169 tmA
.tmLastChar
== 0xff /* win9x */,
3170 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3172 skip("tmLastChar is DBCS lead byte\n");
3173 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3174 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3175 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3176 "A: tmDefaultChar for %s got %02x expected %02x\n",
3177 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3180 SetLastError(0xdeadbeef);
3181 ret
= GetTextMetricsW(hdc
, &tmW
);
3182 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3183 "GetTextMetricsW error %u\n", GetLastError());
3186 /* Wine uses the os2 first char */
3187 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3188 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3189 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3191 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3192 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3194 /* Wine uses the os2 last char */
3195 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3196 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3197 font_name
, tmW
.tmLastChar
, expect_last_W
);
3199 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3200 font_name
, tmW
.tmLastChar
, expect_last_W
);
3201 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3202 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3203 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3204 "W: tmDefaultChar for %s got %02x expected %02x\n",
3205 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3207 /* Test the aspect ratio while we have tmW */
3208 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3209 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3210 tmW
.tmDigitizedAspectX
, ret
);
3211 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3212 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3213 tmW
.tmDigitizedAspectX
, ret
);
3217 /* test FF_ values */
3218 switch(tt_os2
.panose
.bFamilyType
)
3222 case PAN_FAMILY_TEXT_DISPLAY
:
3223 case PAN_FAMILY_PICTORIAL
:
3225 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3226 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3228 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3231 switch(tt_os2
.panose
.bSerifStyle
)
3236 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3239 case PAN_SERIF_COVE
:
3240 case PAN_SERIF_OBTUSE_COVE
:
3241 case PAN_SERIF_SQUARE_COVE
:
3242 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3243 case PAN_SERIF_SQUARE
:
3244 case PAN_SERIF_THIN
:
3245 case PAN_SERIF_BONE
:
3246 case PAN_SERIF_EXAGGERATED
:
3247 case PAN_SERIF_TRIANGLE
:
3248 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3251 case PAN_SERIF_NORMAL_SANS
:
3252 case PAN_SERIF_OBTUSE_SANS
:
3253 case PAN_SERIF_PERP_SANS
:
3254 case PAN_SERIF_FLARED
:
3255 case PAN_SERIF_ROUNDED
:
3256 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3261 case PAN_FAMILY_SCRIPT
:
3262 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3265 case PAN_FAMILY_DECORATIVE
:
3266 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3270 test_negative_width(hdc
, lf
);
3273 SelectObject(hdc
, hfont_old
);
3274 DeleteObject(hfont
);
3279 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
3281 INT
*enumed
= (INT
*)lParam
;
3283 if (type
== TRUETYPE_FONTTYPE
)
3286 test_text_metrics(lf
, (const NEWTEXTMETRIC
*)ntm
);
3291 static void test_GetTextMetrics(void)
3297 /* Report only once */
3298 if(!pGetGlyphIndicesA
)
3299 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3303 memset(&lf
, 0, sizeof(lf
));
3304 lf
.lfCharSet
= DEFAULT_CHARSET
;
3306 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
3307 trace("Tested metrics of %d truetype fonts\n", enumed
);
3312 static void test_nonexistent_font(void)
3320 { "Times New Roman Baltic", 186 },
3321 { "Times New Roman CE", 238 },
3322 { "Times New Roman CYR", 204 },
3323 { "Times New Roman Greek", 161 },
3324 { "Times New Roman TUR", 162 }
3330 INT cs
, expected_cs
, i
;
3331 char buf
[LF_FACESIZE
];
3333 if (!is_truetype_font_installed("Arial") ||
3334 !is_truetype_font_installed("Times New Roman"))
3336 skip("Arial or Times New Roman not installed\n");
3340 expected_cs
= GetACP();
3341 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3343 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3346 expected_cs
= csi
.ciCharset
;
3347 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3351 memset(&lf
, 0, sizeof(lf
));
3353 lf
.lfWeight
= FW_REGULAR
;
3354 lf
.lfCharSet
= ANSI_CHARSET
;
3355 lf
.lfPitchAndFamily
= FF_SWISS
;
3356 strcpy(lf
.lfFaceName
, "Nonexistent font");
3357 hfont
= CreateFontIndirectA(&lf
);
3358 hfont
= SelectObject(hdc
, hfont
);
3359 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3360 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
3361 cs
= GetTextCharset(hdc
);
3362 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3363 DeleteObject(SelectObject(hdc
, hfont
));
3365 memset(&lf
, 0, sizeof(lf
));
3367 lf
.lfWeight
= FW_DONTCARE
;
3368 strcpy(lf
.lfFaceName
, "Nonexistent font");
3369 hfont
= CreateFontIndirectA(&lf
);
3370 hfont
= SelectObject(hdc
, hfont
);
3371 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3372 todo_wine
/* Wine uses Arial for all substitutions */
3373 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
3374 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
3375 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3377 cs
= GetTextCharset(hdc
);
3378 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
3379 DeleteObject(SelectObject(hdc
, hfont
));
3381 memset(&lf
, 0, sizeof(lf
));
3383 lf
.lfWeight
= FW_REGULAR
;
3384 strcpy(lf
.lfFaceName
, "Nonexistent font");
3385 hfont
= CreateFontIndirectA(&lf
);
3386 hfont
= SelectObject(hdc
, hfont
);
3387 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3388 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3389 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
3390 cs
= GetTextCharset(hdc
);
3391 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3392 DeleteObject(SelectObject(hdc
, hfont
));
3394 memset(&lf
, 0, sizeof(lf
));
3396 lf
.lfWeight
= FW_DONTCARE
;
3397 strcpy(lf
.lfFaceName
, "Times New Roman");
3398 hfont
= CreateFontIndirectA(&lf
);
3399 hfont
= SelectObject(hdc
, hfont
);
3400 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3401 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
3402 cs
= GetTextCharset(hdc
);
3403 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3404 DeleteObject(SelectObject(hdc
, hfont
));
3406 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
3408 memset(&lf
, 0, sizeof(lf
));
3410 lf
.lfWeight
= FW_REGULAR
;
3411 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3412 hfont
= CreateFontIndirectA(&lf
);
3413 hfont
= SelectObject(hdc
, hfont
);
3414 cs
= GetTextCharset(hdc
);
3415 if (font_subst
[i
].charset
== expected_cs
)
3417 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3418 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3419 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
3423 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
3424 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3425 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3426 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
3428 DeleteObject(SelectObject(hdc
, hfont
));
3430 memset(&lf
, 0, sizeof(lf
));
3432 lf
.lfWeight
= FW_DONTCARE
;
3433 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3434 hfont
= CreateFontIndirectA(&lf
);
3435 hfont
= SelectObject(hdc
, hfont
);
3436 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3437 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
3438 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
3439 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
3440 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3441 "got %s for font %s\n", buf
, font_subst
[i
].name
);
3442 cs
= GetTextCharset(hdc
);
3443 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3444 DeleteObject(SelectObject(hdc
, hfont
));
3450 static void test_GdiRealizationInfo(void)
3455 HFONT hfont
, hfont_old
;
3458 if(!pGdiRealizationInfo
)
3460 win_skip("GdiRealizationInfo not available\n");
3466 memset(info
, 0xcc, sizeof(info
));
3467 r
= pGdiRealizationInfo(hdc
, info
);
3468 ok(r
!= 0, "ret 0\n");
3469 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
3470 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3472 if (!is_truetype_font_installed("Arial"))
3474 skip("skipping GdiRealizationInfo with truetype font\n");
3478 memset(&lf
, 0, sizeof(lf
));
3479 strcpy(lf
.lfFaceName
, "Arial");
3481 lf
.lfWeight
= FW_NORMAL
;
3482 hfont
= CreateFontIndirectA(&lf
);
3483 hfont_old
= SelectObject(hdc
, hfont
);
3485 memset(info
, 0xcc, sizeof(info
));
3486 r
= pGdiRealizationInfo(hdc
, info
);
3487 ok(r
!= 0, "ret 0\n");
3488 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
3489 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3491 DeleteObject(SelectObject(hdc
, hfont_old
));
3497 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3498 the nul in the count of characters copied when the face name buffer is not
3499 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3500 always includes it. */
3501 static void test_GetTextFace(void)
3503 static const char faceA
[] = "Tahoma";
3504 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
3507 char bufA
[LF_FACESIZE
];
3508 WCHAR bufW
[LF_FACESIZE
];
3513 if(!is_font_installed("Tahoma"))
3515 skip("Tahoma is not installed so skipping this test\n");
3520 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
3521 f
= CreateFontIndirectA(&fA
);
3522 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
3525 g
= SelectObject(dc
, f
);
3526 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
3527 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
3528 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
3530 /* Play with the count arg. */
3532 n
= GetTextFaceA(dc
, 0, bufA
);
3533 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3534 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3537 n
= GetTextFaceA(dc
, 1, bufA
);
3538 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3539 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3541 bufA
[0] = 'x'; bufA
[1] = 'y';
3542 n
= GetTextFaceA(dc
, 2, bufA
);
3543 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
3544 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
3546 n
= GetTextFaceA(dc
, 0, NULL
);
3547 ok(n
== sizeof faceA
||
3548 broken(n
== 0), /* win98, winMe */
3549 "GetTextFaceA returned %d\n", n
);
3551 DeleteObject(SelectObject(dc
, g
));
3552 ReleaseDC(NULL
, dc
);
3555 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3556 SetLastError(0xdeadbeef);
3557 f
= CreateFontIndirectW(&fW
);
3558 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3560 win_skip("CreateFontIndirectW is not implemented\n");
3563 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3566 g
= SelectObject(dc
, f
);
3567 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3568 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3569 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3571 /* Play with the count arg. */
3573 n
= GetTextFaceW(dc
, 0, bufW
);
3574 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3575 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3578 n
= GetTextFaceW(dc
, 1, bufW
);
3579 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3580 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3582 bufW
[0] = 'x'; bufW
[1] = 'y';
3583 n
= GetTextFaceW(dc
, 2, bufW
);
3584 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
3585 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
3587 n
= GetTextFaceW(dc
, 0, NULL
);
3588 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3590 DeleteObject(SelectObject(dc
, g
));
3591 ReleaseDC(NULL
, dc
);
3594 static void test_orientation(void)
3596 static const char test_str
[11] = "Test String";
3599 HFONT hfont
, old_hfont
;
3602 if (!is_truetype_font_installed("Arial"))
3604 skip("Arial is not installed\n");
3608 hdc
= CreateCompatibleDC(0);
3609 memset(&lf
, 0, sizeof(lf
));
3610 lstrcpyA(lf
.lfFaceName
, "Arial");
3612 lf
.lfOrientation
= lf
.lfEscapement
= 900;
3613 hfont
= create_font("orientation", &lf
);
3614 old_hfont
= SelectObject(hdc
, hfont
);
3615 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
3616 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
3617 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
3618 SelectObject(hdc
, old_hfont
);
3619 DeleteObject(hfont
);
3623 static void test_oemcharset(void)
3627 HFONT hfont
, old_hfont
;
3630 hdc
= CreateCompatibleDC(0);
3631 ZeroMemory(&lf
, sizeof(lf
));
3633 lf
.lfCharSet
= OEM_CHARSET
;
3634 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
3635 lstrcpyA(lf
.lfFaceName
, "Terminal");
3636 hfont
= CreateFontIndirectA(&lf
);
3637 old_hfont
= SelectObject(hdc
, hfont
);
3638 charset
= GetTextCharset(hdc
);
3640 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
3641 hfont
= SelectObject(hdc
, old_hfont
);
3642 GetObjectA(hfont
, sizeof(clf
), &clf
);
3643 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
3644 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
3645 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
3646 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
3647 DeleteObject(hfont
);
3651 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONT
*lpelfe
,
3652 const TEXTMETRIC
*lpntme
,
3653 DWORD FontType
, LPARAM lParam
)
3655 const NEWTEXTMETRICEX
*lpntmex
= (const NEWTEXTMETRICEX
*)lpntme
;
3657 LOGFONT lf
= *lpelfe
;
3660 /* skip bitmap, proportional or vertical font */
3661 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
3662 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
3663 lf
.lfFaceName
[0] == '@')
3666 /* skip linked font */
3667 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
3668 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
3671 /* test with an odd height */
3674 hfont
= CreateFontIndirect(&lf
);
3677 *(HFONT
*)lParam
= hfont
;
3683 static void test_GetGlyphOutline(void)
3686 GLYPHMETRICS gm
, gm2
;
3688 HFONT hfont
, old_hfont
;
3697 {ANSI_CHARSET
, 0x30, 0x30},
3698 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
3699 {HANGEUL_CHARSET
, 0x8141, 0xac02},
3700 {JOHAB_CHARSET
, 0x8446, 0x3135},
3701 {GB2312_CHARSET
, 0x8141, 0x4e04},
3702 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
3706 if (!is_truetype_font_installed("Tahoma"))
3708 skip("Tahoma is not installed\n");
3712 hdc
= CreateCompatibleDC(0);
3713 memset(&lf
, 0, sizeof(lf
));
3715 lstrcpyA(lf
.lfFaceName
, "Tahoma");
3716 SetLastError(0xdeadbeef);
3717 hfont
= CreateFontIndirectA(&lf
);
3718 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
3719 old_hfont
= SelectObject(hdc
, hfont
);
3721 memset(&gm
, 0, sizeof(gm
));
3722 SetLastError(0xdeadbeef);
3723 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3724 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3726 memset(&gm
, 0, sizeof(gm
));
3727 SetLastError(0xdeadbeef);
3728 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3729 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
3730 ok(GetLastError() == 0xdeadbeef ||
3731 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
3732 "expected 0xdeadbeef, got %u\n", GetLastError());
3734 memset(&gm
, 0, sizeof(gm
));
3735 SetLastError(0xdeadbeef);
3736 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3737 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3738 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
3740 memset(&gm
, 0, sizeof(gm
));
3741 SetLastError(0xdeadbeef);
3742 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3743 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3745 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
3746 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3749 /* test for needed buffer size request on space char */
3750 memset(&gm
, 0, sizeof(gm
));
3751 SetLastError(0xdeadbeef);
3752 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3753 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3754 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3756 /* requesting buffer size for space char + error */
3757 memset(&gm
, 0, sizeof(gm
));
3758 SetLastError(0xdeadbeef);
3759 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3760 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3762 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3763 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3766 SelectObject(hdc
, old_hfont
);
3767 DeleteObject(hfont
);
3769 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
3771 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
3773 lf
.lfFaceName
[0] = '\0';
3774 lf
.lfCharSet
= c
[i
].cs
;
3775 lf
.lfPitchAndFamily
= 0;
3776 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
3778 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
3782 old_hfont
= SelectObject(hdc
, hfont
);
3784 /* expected to ignore superfluous bytes (sigle-byte character) */
3785 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3786 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3787 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3789 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3790 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3791 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3793 /* expected to ignore superfluous bytes (double-byte character) */
3794 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3795 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3796 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3797 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3799 /* expected to match wide-char version results */
3800 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3801 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3803 if (EnumFontFamiliesEx(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
3805 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
3808 DeleteObject(SelectObject(hdc
, hfont
));
3811 DeleteObject(SelectObject(hdc
, old_hfont
));
3815 ret
= GetObject(hfont
, sizeof lf
, &lf
);
3816 ok(ret
> 0, "GetObject error %u\n", GetLastError());
3818 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3819 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3820 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3821 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3822 trace("Tests with height=%d,half=%d,full=%d,face=%s,charset=%d\n",
3823 -lf
.lfHeight
, gm
.gmCellIncX
, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
3824 ok(gm2
.gmCellIncX
== gm
.gmCellIncX
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
3825 "expected %d, got %d (%s:%d)\n",
3826 gm
.gmCellIncX
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
3828 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
3829 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3830 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
3831 "expected %d, got %d (%s:%d)\n",
3832 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
3835 hfont
= CreateFontIndirect(&lf
);
3836 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
3837 DeleteObject(SelectObject(hdc
, hfont
));
3838 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3839 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3840 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3841 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3842 ok(gm2
.gmCellIncX
== gm
.gmCellIncX
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
3843 "expected %d, got %d (%s:%d)\n",
3844 gm
.gmCellIncX
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
3846 lf
.lfItalic
= FALSE
;
3847 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
3848 hfont
= CreateFontIndirect(&lf
);
3849 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
3850 DeleteObject(SelectObject(hdc
, hfont
));
3851 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3852 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3853 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
3854 "expected %d, got %d (%s:%d)\n",
3855 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
3857 hfont
= SelectObject(hdc
, old_hfont
);
3858 DeleteObject(hfont
);
3864 /* bug #9995: there is a limit to the character width that can be specified */
3865 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3871 int ave_width
, height
, width
, ratio
, scale
;
3873 if (!is_truetype_font_installed( fontname
)) {
3874 skip("%s is not installed\n", fontname
);
3877 hdc
= CreateCompatibleDC(0);
3878 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3879 /* select width = 0 */
3880 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3881 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3882 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3884 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3885 of
= SelectObject( hdc
, hf
);
3886 ret
= GetTextMetricsA( hdc
, &tm
);
3887 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3888 height
= tm
.tmHeight
;
3889 ave_width
= tm
.tmAveCharWidth
;
3890 SelectObject( hdc
, of
);
3893 trace("height %d, ave width %d\n", height
, ave_width
);
3895 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3897 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3898 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3899 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3900 ok(hf
!= 0, "CreateFont failed\n");
3901 of
= SelectObject(hdc
, hf
);
3902 ret
= GetTextMetrics(hdc
, &tm
);
3903 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3904 SelectObject(hdc
, of
);
3907 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3913 ratio
= width
/ height
;
3914 scale
= width
/ ave_width
;
3916 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3917 width
, height
, ratio
, width
, ave_width
, scale
);
3919 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3922 static void test_CreateFontIndirect(void)
3924 LOGFONTA lf
, getobj_lf
;
3927 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3929 memset(&lf
, 0, sizeof(lf
));
3930 lf
.lfCharSet
= ANSI_CHARSET
;
3931 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3934 lf
.lfQuality
= DEFAULT_QUALITY
;
3935 lf
.lfItalic
= FALSE
;
3936 lf
.lfWeight
= FW_DONTCARE
;
3938 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3940 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3941 hfont
= CreateFontIndirectA(&lf
);
3942 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3943 SetLastError(0xdeadbeef);
3944 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3945 ok(ret
, "GetObject failed: %d\n", GetLastError());
3946 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3947 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3948 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3949 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3950 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3951 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3952 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3953 DeleteObject(hfont
);
3957 static void test_CreateFontIndirectEx(void)
3959 ENUMLOGFONTEXDVA lfex
;
3962 if (!pCreateFontIndirectExA
)
3964 win_skip("CreateFontIndirectExA is not available\n");
3968 if (!is_truetype_font_installed("Arial"))
3970 skip("Arial is not installed\n");
3974 SetLastError(0xdeadbeef);
3975 hfont
= pCreateFontIndirectExA(NULL
);
3976 ok(hfont
== NULL
, "got %p\n", hfont
);
3977 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3979 memset(&lfex
, 0, sizeof(lfex
));
3980 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3981 hfont
= pCreateFontIndirectExA(&lfex
);
3982 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3984 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3985 DeleteObject(hfont
);
3988 static void free_font(void *font
)
3990 UnmapViewOfFile(font
);
3993 static void *load_font(const char *font_name
, DWORD
*font_size
)
3995 char file_name
[MAX_PATH
];
3996 HANDLE file
, mapping
;
3999 if (!GetWindowsDirectory(file_name
, sizeof(file_name
))) return NULL
;
4000 strcat(file_name
, "\\fonts\\");
4001 strcat(file_name
, font_name
);
4003 file
= CreateFile(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
4004 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
4006 *font_size
= GetFileSize(file
, NULL
);
4008 mapping
= CreateFileMapping(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4015 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
4018 CloseHandle(mapping
);
4022 static void test_AddFontMemResource(void)
4025 DWORD font_size
, num_fonts
;
4029 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
4031 win_skip("AddFontMemResourceEx is not available on this platform\n");
4035 font
= load_font("sserife.fon", &font_size
);
4038 skip("Unable to locate and load font sserife.fon\n");
4042 SetLastError(0xdeadbeef);
4043 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
4044 ok(!ret
, "AddFontMemResourceEx should fail\n");
4045 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4046 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4049 SetLastError(0xdeadbeef);
4050 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
4051 ok(!ret
, "AddFontMemResourceEx should fail\n");
4052 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4053 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4056 SetLastError(0xdeadbeef);
4057 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
4058 ok(!ret
, "AddFontMemResourceEx should fail\n");
4059 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4060 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4063 SetLastError(0xdeadbeef);
4064 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
4065 ok(!ret
, "AddFontMemResourceEx should fail\n");
4066 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4067 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4070 SetLastError(0xdeadbeef);
4071 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
4072 ok(!ret
, "AddFontMemResourceEx should fail\n");
4073 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4074 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4077 SetLastError(0xdeadbeef);
4078 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
4079 ok(!ret
, "AddFontMemResourceEx should fail\n");
4080 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4081 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4084 num_fonts
= 0xdeadbeef;
4085 SetLastError(0xdeadbeef);
4086 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
4087 ok(!ret
, "AddFontMemResourceEx should fail\n");
4088 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4089 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4091 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4093 if (0) /* hangs under windows 2000 */
4095 num_fonts
= 0xdeadbeef;
4096 SetLastError(0xdeadbeef);
4097 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
4098 ok(!ret
, "AddFontMemResourceEx should fail\n");
4099 ok(GetLastError() == 0xdeadbeef,
4100 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4102 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4105 num_fonts
= 0xdeadbeef;
4106 SetLastError(0xdeadbeef);
4107 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
4108 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
4109 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4110 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
4114 SetLastError(0xdeadbeef);
4115 bRet
= pRemoveFontMemResourceEx(ret
);
4116 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
4118 /* test invalid pointer to number of loaded fonts */
4119 font
= load_font("sserife.fon", &font_size
);
4120 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
4122 SetLastError(0xdeadbeef);
4123 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
4124 ok(!ret
, "AddFontMemResourceEx should fail\n");
4125 ok(GetLastError() == 0xdeadbeef,
4126 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4129 SetLastError(0xdeadbeef);
4130 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
4131 ok(!ret
, "AddFontMemResourceEx should fail\n");
4132 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4133 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4139 static INT CALLBACK
enum_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
4143 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4145 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4147 lf
= (LOGFONT
*)lparam
;
4152 static INT CALLBACK
enum_all_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
4157 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4159 lf
= (LOGFONT
*)lparam
;
4160 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
4163 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4170 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
4175 static void test_EnumFonts(void)
4181 if (!is_truetype_font_installed("Arial"))
4183 skip("Arial is not installed\n");
4187 /* Windows uses localized font face names, so Arial Bold won't be found */
4188 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
4190 skip("User locale is not English, skipping the test\n");
4194 hdc
= CreateCompatibleDC(0);
4196 /* check that the enumproc's retval is returned */
4197 ret
= EnumFontFamilies(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
4198 ok(ret
== 0xcafe, "got %08x\n", ret
);
4200 ret
= EnumFontFamilies(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
4201 ok(!ret
, "font Arial is not enumerated\n");
4202 ret
= strcmp(lf
.lfFaceName
, "Arial");
4203 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4204 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4206 lstrcpy(lf
.lfFaceName
, "Arial");
4207 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4208 ok(!ret
, "font Arial is not enumerated\n");
4209 ret
= strcmp(lf
.lfFaceName
, "Arial");
4210 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4211 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4213 ret
= EnumFontFamilies(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4214 ok(!ret
, "font Arial Bold is not enumerated\n");
4215 ret
= strcmp(lf
.lfFaceName
, "Arial");
4216 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4217 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4219 lstrcpy(lf
.lfFaceName
, "Arial Bold");
4220 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4221 ok(ret
, "font Arial Bold should not be enumerated\n");
4223 ret
= EnumFontFamilies(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
4224 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
4225 ret
= strcmp(lf
.lfFaceName
, "Arial");
4226 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4227 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4229 lstrcpy(lf
.lfFaceName
, "Arial Bold Italic");
4230 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4231 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
4233 ret
= EnumFontFamilies(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4234 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4236 lstrcpy(lf
.lfFaceName
, "Arial Italic Bold");
4237 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4238 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4243 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
4245 const ENUMLOGFONT
*elf
= (const ENUMLOGFONT
*)lf
;
4246 const char *fullname
= (const char *)lParam
;
4248 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
4253 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
4258 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
4265 static void test_fullname(void)
4267 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4268 WCHAR bufW
[LF_FULLFACESIZE
];
4269 char bufA
[LF_FULLFACESIZE
];
4276 hdc
= CreateCompatibleDC(0);
4277 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4279 memset(&lf
, 0, sizeof(lf
));
4280 lf
.lfCharSet
= ANSI_CHARSET
;
4281 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4284 lf
.lfQuality
= DEFAULT_QUALITY
;
4285 lf
.lfItalic
= FALSE
;
4286 lf
.lfWeight
= FW_DONTCARE
;
4288 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
4290 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
4292 skip("%s is not installed\n", TestName
[i
]);
4296 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4297 hfont
= CreateFontIndirectA(&lf
);
4298 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4300 of
= SelectObject(hdc
, hfont
);
4303 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4304 ok(ret
, "face full name could not be read\n");
4305 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
4306 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
4307 SelectObject(hdc
, of
);
4308 DeleteObject(hfont
);
4313 static WCHAR
*prepend_at(WCHAR
*family
)
4318 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
4323 static void test_fullname2_helper(const char *Family
)
4325 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
4326 struct enum_fullname_data efnd
;
4333 DWORD otm_size
, ret
, buf_size
;
4334 OUTLINETEXTMETRICA
*otm
;
4335 BOOL want_vertical
, get_vertical
;
4336 want_vertical
= ( Family
[0] == '@' );
4338 hdc
= CreateCompatibleDC(0);
4339 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4341 memset(&lf
, 0, sizeof(lf
));
4342 lf
.lfCharSet
= DEFAULT_CHARSET
;
4343 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4346 lf
.lfQuality
= DEFAULT_QUALITY
;
4347 lf
.lfItalic
= FALSE
;
4348 lf
.lfWeight
= FW_DONTCARE
;
4349 lstrcpy(lf
.lfFaceName
, Family
);
4351 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4352 if (efnd
.total
== 0)
4353 skip("%s is not installed\n", lf
.lfFaceName
);
4355 for (i
= 0; i
< efnd
.total
; i
++)
4357 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
4358 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
4359 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
4361 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family
, FamilyName
, FaceName
, StyleName
);
4363 get_vertical
= ( FamilyName
[0] == '@' );
4364 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
4366 lstrcpyA(lf
.lfFaceName
, FaceName
);
4367 hfont
= CreateFontIndirectA(&lf
);
4368 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4370 of
= SelectObject(hdc
, hfont
);
4371 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
4372 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
4373 if (buf_size
== GDI_ERROR
) continue;
4375 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4376 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4378 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
4379 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
4380 memset(otm
, 0, otm_size
);
4381 ret
= GetOutlineTextMetrics(hdc
, otm_size
, otm
);
4382 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
4383 if (ret
== 0) continue;
4387 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4390 trace("no localized FONT_FAMILY found.\n");
4391 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4393 ok(ret
, "FAMILY (family name) could not be read\n");
4394 if (want_vertical
) bufW
= prepend_at(bufW
);
4395 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4396 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
4397 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
4398 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
4402 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
4405 trace("no localized FULL_NAME found.\n");
4406 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4408 ok(ret
, "FULL_NAME (face name) could not be read\n");
4409 if (want_vertical
) bufW
= prepend_at(bufW
);
4410 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4411 ok(!lstrcmpA(FaceName
, bufA
), "font face names don't match: returned %s, expect %s\n", FaceName
, bufA
);
4412 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
4413 ok(!lstrcmpA(FaceName
, otmStr
), "FaceName %s doesn't match otmpFaceName %s\n", FaceName
, otmStr
);
4417 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4420 trace("no localized FONT_SUBFAMILY found.\n");
4421 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4423 ok(ret
, "SUBFAMILY (style name) could not be read\n");
4424 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4425 ok(!lstrcmpA(StyleName
, bufA
), "style names don't match: returned %s, expect %s\n", StyleName
, bufA
);
4426 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
4427 ok(!lstrcmpA(StyleName
, otmStr
), "StyleName %s doesn't match otmpStyleName %s\n", StyleName
, otmStr
);
4431 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
4434 trace("no localized UNIQUE_ID found.\n");
4435 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4437 ok(ret
, "UNIQUE_ID (full name) could not be read\n");
4438 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4439 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
4440 ok(!lstrcmpA(otmStr
, bufA
), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr
, bufA
);
4442 SelectObject(hdc
, of
);
4443 DeleteObject(hfont
);
4445 HeapFree(GetProcessHeap(), 0, otm
);
4446 HeapFree(GetProcessHeap(), 0, bufW
);
4447 HeapFree(GetProcessHeap(), 0, bufA
);
4452 static void test_fullname2(void)
4454 test_fullname2_helper("Arial");
4455 test_fullname2_helper("DejaVu Sans");
4456 test_fullname2_helper("Lucida Sans");
4457 test_fullname2_helper("Tahoma");
4458 test_fullname2_helper("Webdings");
4459 test_fullname2_helper("Wingdings");
4460 test_fullname2_helper("SimSun");
4461 test_fullname2_helper("NSimSun");
4462 test_fullname2_helper("MingLiu");
4463 test_fullname2_helper("PMingLiu");
4464 test_fullname2_helper("WenQuanYi Micro Hei");
4465 test_fullname2_helper("MS UI Gothic");
4466 test_fullname2_helper("Ume UI Gothic");
4467 test_fullname2_helper("MS Gothic");
4468 test_fullname2_helper("Ume Gothic");
4469 test_fullname2_helper("MS PGothic");
4470 test_fullname2_helper("Ume P Gothic");
4471 test_fullname2_helper("Gulim");
4472 test_fullname2_helper("Batang");
4473 test_fullname2_helper("UnBatang");
4474 test_fullname2_helper("UnDotum");
4475 test_fullname2_helper("@SimSun");
4476 test_fullname2_helper("@NSimSun");
4477 test_fullname2_helper("@MingLiu");
4478 test_fullname2_helper("@PMingLiu");
4479 test_fullname2_helper("@WenQuanYi Micro Hei");
4480 test_fullname2_helper("@MS UI Gothic");
4481 test_fullname2_helper("@Ume UI Gothic");
4482 test_fullname2_helper("@MS Gothic");
4483 test_fullname2_helper("@Ume Gothic");
4484 test_fullname2_helper("@MS PGothic");
4485 test_fullname2_helper("@Ume P Gothic");
4486 test_fullname2_helper("@Gulim");
4487 test_fullname2_helper("@Batang");
4488 test_fullname2_helper("@UnBatang");
4489 test_fullname2_helper("@UnDotum");
4493 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
4495 char tmp_path
[MAX_PATH
];
4502 SetLastError(0xdeadbeef);
4503 rsrc
= FindResource(GetModuleHandle(0), fontname
, RT_RCDATA
);
4504 ok(rsrc
!= 0, "FindResource error %d\n", GetLastError());
4505 if (!rsrc
) return FALSE
;
4506 SetLastError(0xdeadbeef);
4507 rsrc_data
= LockResource(LoadResource(GetModuleHandle(0), rsrc
));
4508 ok(rsrc_data
!= 0, "LockResource error %d\n", GetLastError());
4509 if (!rsrc_data
) return FALSE
;
4510 SetLastError(0xdeadbeef);
4511 rsrc_size
= SizeofResource(GetModuleHandle(0), rsrc
);
4512 ok(rsrc_size
!= 0, "SizeofResource error %d\n", GetLastError());
4513 if (!rsrc_size
) return FALSE
;
4515 SetLastError(0xdeadbeef);
4516 ret
= GetTempPath(MAX_PATH
, tmp_path
);
4517 ok(ret
, "GetTempPath() error %d\n", GetLastError());
4518 SetLastError(0xdeadbeef);
4519 ret
= GetTempFileName(tmp_path
, "ttf", 0, tmp_name
);
4520 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
4522 SetLastError(0xdeadbeef);
4523 hfile
= CreateFile(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
4524 ok(hfile
!= INVALID_HANDLE_VALUE
, "CreateFile() error %d\n", GetLastError());
4525 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
4527 SetLastError(0xdeadbeef);
4528 ret
= WriteFile(hfile
, rsrc_data
, rsrc_size
, &rsrc_size
, NULL
);
4529 ok(ret
, "WriteFile() error %d\n", GetLastError());
4535 static void test_GetGlyphOutline_empty_contour(void)
4539 HFONT hfont
, hfont_prev
;
4540 TTPOLYGONHEADER
*header
;
4545 memset(&lf
, 0, sizeof(lf
));
4547 lstrcpyA(lf
.lfFaceName
, "wine_test");
4549 hfont
= CreateFontIndirectA(&lf
);
4550 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4554 hfont_prev
= SelectObject(hdc
, hfont
);
4555 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
4557 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4558 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
4560 header
= (TTPOLYGONHEADER
*)buf
;
4561 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
4562 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
4563 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
4564 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
4565 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
4566 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
4567 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
4568 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
4570 SelectObject(hdc
, hfont_prev
);
4571 DeleteObject(hfont
);
4572 ReleaseDC(NULL
, hdc
);
4575 static void test_CreateScalableFontResource(void)
4577 char ttf_name
[MAX_PATH
];
4578 char tmp_path
[MAX_PATH
];
4579 char fot_name
[MAX_PATH
];
4584 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
4586 win_skip("AddFontResourceExA is not available on this platform\n");
4590 if (!write_ttf_file("wine_test.ttf", ttf_name
))
4592 skip("Failed to create ttf file for testing\n");
4596 trace("created %s\n", ttf_name
);
4598 ret
= is_truetype_font_installed("wine_test");
4599 ok(!ret
, "font wine_test should not be enumerated\n");
4601 ret
= GetTempPath(MAX_PATH
, tmp_path
);
4602 ok(ret
, "GetTempPath() error %d\n", GetLastError());
4603 ret
= GetTempFileName(tmp_path
, "fot", 0, fot_name
);
4604 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
4606 ret
= GetFileAttributes(fot_name
);
4607 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
4609 SetLastError(0xdeadbeef);
4610 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
4611 ok(!ret
, "CreateScalableFontResource() should fail\n");
4612 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4614 SetLastError(0xdeadbeef);
4615 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, "");
4616 ok(!ret
, "CreateScalableFontResource() should fail\n");
4617 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4619 file_part
= strrchr(ttf_name
, '\\');
4620 SetLastError(0xdeadbeef);
4621 ret
= CreateScalableFontResource(0, fot_name
, file_part
, tmp_path
);
4622 ok(!ret
, "CreateScalableFontResource() should fail\n");
4623 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4625 SetLastError(0xdeadbeef);
4626 ret
= CreateScalableFontResource(0, fot_name
, "random file name", tmp_path
);
4627 ok(!ret
, "CreateScalableFontResource() should fail\n");
4628 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
4630 SetLastError(0xdeadbeef);
4631 ret
= CreateScalableFontResource(0, fot_name
, NULL
, ttf_name
);
4632 ok(!ret
, "CreateScalableFontResource() should fail\n");
4633 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
4635 ret
= DeleteFile(fot_name
);
4636 ok(ret
, "DeleteFile() error %d\n", GetLastError());
4638 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4639 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4641 /* test public font resource */
4642 SetLastError(0xdeadbeef);
4643 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
4644 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
4646 ret
= is_truetype_font_installed("wine_test");
4647 ok(!ret
, "font wine_test should not be enumerated\n");
4649 SetLastError(0xdeadbeef);
4650 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4651 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4653 ret
= is_truetype_font_installed("wine_test");
4654 ok(ret
, "font wine_test should be enumerated\n");
4656 test_GetGlyphOutline_empty_contour();
4658 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4659 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
4661 SetLastError(0xdeadbeef);
4662 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4663 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4665 ret
= is_truetype_font_installed("wine_test");
4666 ok(!ret
, "font wine_test should not be enumerated\n");
4668 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4669 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4671 /* test refcounting */
4672 for (i
= 0; i
< 5; i
++)
4674 SetLastError(0xdeadbeef);
4675 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4676 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4678 for (i
= 0; i
< 5; i
++)
4680 SetLastError(0xdeadbeef);
4681 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4682 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4684 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4685 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4687 DeleteFile(fot_name
);
4689 /* test hidden font resource */
4690 SetLastError(0xdeadbeef);
4691 ret
= CreateScalableFontResource(1, fot_name
, ttf_name
, NULL
);
4692 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
4694 ret
= is_truetype_font_installed("wine_test");
4695 ok(!ret
, "font wine_test should not be enumerated\n");
4697 SetLastError(0xdeadbeef);
4698 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4699 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4701 ret
= is_truetype_font_installed("wine_test");
4703 ok(!ret
, "font wine_test should not be enumerated\n");
4705 /* XP allows removing a private font added with 0 flags */
4706 SetLastError(0xdeadbeef);
4707 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4708 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4710 ret
= is_truetype_font_installed("wine_test");
4711 ok(!ret
, "font wine_test should not be enumerated\n");
4713 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4714 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4716 DeleteFile(fot_name
);
4717 DeleteFile(ttf_name
);
4720 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
4723 HFONT hfont
, hfont_prev
;
4727 static const WCHAR str
[] = { 0x2025 };
4729 *installed
= is_truetype_font_installed(name
);
4733 lf
.lfEscapement
= 0;
4734 lf
.lfOrientation
= 0;
4735 lf
.lfWeight
= FW_DONTCARE
;
4739 lf
.lfCharSet
= DEFAULT_CHARSET
;
4740 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
4741 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4742 lf
.lfQuality
= DEFAULT_QUALITY
;
4743 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
4744 strcpy(lf
.lfFaceName
, name
);
4746 hfont
= CreateFontIndirectA(&lf
);
4747 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
4751 hfont_prev
= SelectObject(hdc
, hfont
);
4752 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
4754 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
4755 ok(ret
, "GetTextFaceA failed\n");
4756 *selected
= !strcmp(facename
, name
);
4758 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
4759 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
4761 memset(gm
, 0, sizeof *gm
);
4763 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
4764 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
4766 SelectObject(hdc
, hfont_prev
);
4767 DeleteObject(hfont
);
4768 ReleaseDC(NULL
, hdc
);
4771 static void test_vertical_font(void)
4773 char ttf_name
[MAX_PATH
];
4775 BOOL ret
, installed
, selected
;
4779 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
4781 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4785 if (!write_ttf_file("vertical.ttf", ttf_name
))
4787 skip("Failed to create ttf file for testing\n");
4791 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
4792 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4794 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
4795 ok(installed
, "@WineTestVertical is not installed\n");
4796 ok(selected
, "@WineTestVertical is not selected\n");
4797 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
4798 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4799 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
4801 check_vertical_font("@@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
4802 ok(installed
, "@@WineTestVertical is not installed\n");
4803 ok(selected
, "@@WineTestVertical is not selected\n");
4804 ok(gm
.gmBlackBoxX
< gm
.gmBlackBoxY
,
4805 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4806 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
4808 ok(hgi
== vgi
, "different glyph h:%u v:%u\n", hgi
, vgi
);
4810 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
4811 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4813 DeleteFile(ttf_name
);
4816 static INT CALLBACK
has_vertical_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
,
4817 DWORD type
, LPARAM lParam
)
4819 if (lf
->lfFaceName
[0] == '@') {
4825 static void test_east_asian_font_selection(void)
4828 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
4829 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
4834 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
4838 char face_name
[LF_FACESIZE
];
4841 memset(&lf
, 0, sizeof lf
);
4842 lf
.lfFaceName
[0] = '\0';
4843 lf
.lfCharSet
= charset
[i
];
4845 if (EnumFontFamiliesEx(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
4847 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
4851 hfont
= CreateFontIndirectA(&lf
);
4852 hfont
= SelectObject(hdc
, hfont
);
4853 memset(face_name
, 0, sizeof face_name
);
4854 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
4855 ok(ret
&& face_name
[0] != '@',
4856 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
4857 DeleteObject(SelectObject(hdc
, hfont
));
4859 memset(&lf
, 0, sizeof lf
);
4860 strcpy(lf
.lfFaceName
, "@");
4861 lf
.lfCharSet
= charset
[i
];
4862 hfont
= CreateFontIndirectA(&lf
);
4863 hfont
= SelectObject(hdc
, hfont
);
4864 memset(face_name
, 0, sizeof face_name
);
4865 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
4866 ok(ret
&& face_name
[0] == '@',
4867 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
4868 DeleteObject(SelectObject(hdc
, hfont
));
4870 ReleaseDC(NULL
, hdc
);
4873 static int get_font_dpi(const LOGFONT
*lf
)
4875 HDC hdc
= CreateCompatibleDC(0);
4880 hfont
= CreateFontIndirect(lf
);
4881 ok(hfont
!= 0, "CreateFontIndirect failed\n");
4883 SelectObject(hdc
, hfont
);
4884 ret
= GetTextMetrics(hdc
, &tm
);
4885 ok(ret
, "GetTextMetrics failed\n");
4886 ret
= tm
.tmDigitizedAspectX
;
4889 DeleteObject(hfont
);
4894 static void test_stock_fonts(void)
4896 static const int font
[] =
4898 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
4899 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4901 static const struct test_data
4903 int charset
, weight
, height
, dpi
;
4904 const char face_name
[LF_FACESIZE
];
4907 { /* ANSI_FIXED_FONT */
4908 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 96, "Courier" },
4909 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 120, "Courier" },
4912 { /* ANSI_VAR_FONT */
4913 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 96, "MS Sans Serif" },
4914 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 120, "MS Sans Serif" },
4918 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 96, "System" },
4919 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 120, "System" },
4920 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 96, "System" },
4921 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 120, "System" },
4922 { DEFAULT_CHARSET
, FW_BOLD
, 16, 96, "System" },
4923 { DEFAULT_CHARSET
, FW_BOLD
, 20, 120, "System" },
4926 { /* DEVICE_DEFAULT_FONT */
4927 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 96, "System" },
4928 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 120, "System" },
4929 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 96, "System" },
4930 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 120, "System" },
4931 { DEFAULT_CHARSET
, FW_BOLD
, 16, 96, "System" },
4932 { DEFAULT_CHARSET
, FW_BOLD
, 20, 120, "System" },
4935 { /* DEFAULT_GUI_FONT */
4936 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 96, "?MS UI Gothic" },
4937 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 120, "?MS UI Gothic" },
4938 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 96, "?Gulim" },
4939 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 120, "?Gulim" },
4940 { GB2312_CHARSET
, FW_NORMAL
, -12, 96, "?SimHei" },
4941 { GB2312_CHARSET
, FW_NORMAL
, -15, 120, "?SimHei" },
4942 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 96, "?MingLiU" },
4943 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 120, "?MingLiU" },
4944 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 96, "MS Shell Dlg" },
4945 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 120, "MS Shell Dlg" },
4951 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
4957 hfont
= GetStockObject(font
[i
]);
4958 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
4960 ret
= GetObject(hfont
, sizeof(lf
), &lf
);
4961 if (ret
!= sizeof(lf
))
4964 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
4968 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
4970 if (lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
)
4975 ret
= get_font_dpi(&lf
);
4976 if (ret
!= td
[i
][j
].dpi
)
4978 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4979 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
4983 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
4984 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
4985 if (td
[i
][j
].face_name
[0] == '?')
4987 /* Wine doesn't have this font, skip this case for now.
4988 Actually, the face name is localized on Windows and varies
4989 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4990 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
4994 ok(!lstrcmp(td
[i
][j
].face_name
, lf
.lfFaceName
), "%d(%d): expected lfFaceName %s, got %s\n", i
, j
, td
[i
][j
].face_name
, lf
.lfFaceName
);
5008 test_outline_font();
5009 test_bitmap_font_metrics();
5010 test_GdiGetCharDimensions();
5011 test_GetCharABCWidths();
5012 test_text_extents();
5013 test_GetGlyphIndices();
5014 test_GetKerningPairs();
5015 test_GetOutlineTextMetrics();
5016 test_SetTextJustification();
5017 test_font_charset();
5018 test_GdiGetCodePage();
5019 test_GetFontUnicodeRanges();
5020 test_nonexistent_font();
5022 test_height_selection();
5023 test_AddFontMemResource();
5026 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
5027 * I'd like to avoid them in this test.
5029 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
5030 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
5031 if (is_truetype_font_installed("Arial Black") &&
5032 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
5034 test_EnumFontFamilies("", ANSI_CHARSET
);
5035 test_EnumFontFamilies("", SYMBOL_CHARSET
);
5036 test_EnumFontFamilies("", DEFAULT_CHARSET
);
5039 skip("Arial Black or Symbol/Wingdings is not installed\n");
5040 test_EnumFontFamiliesEx_default_charset();
5041 test_GetTextMetrics();
5042 test_GdiRealizationInfo();
5044 test_GetGlyphOutline();
5045 test_GetTextMetrics2("Tahoma", -11);
5046 test_GetTextMetrics2("Tahoma", -55);
5047 test_GetTextMetrics2("Tahoma", -110);
5048 test_GetTextMetrics2("Arial", -11);
5049 test_GetTextMetrics2("Arial", -55);
5050 test_GetTextMetrics2("Arial", -110);
5051 test_CreateFontIndirect();
5052 test_CreateFontIndirectEx();
5056 test_east_asian_font_selection();
5058 /* These tests should be last test until RemoveFontResource
5059 * is properly implemented.
5061 test_vertical_font();
5062 test_CreateScalableFontResource();