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 hdc
= CreateCompatibleDC(0);
339 /* "System" has only 1 pixel size defined, otherwise the test breaks */
340 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
344 trace("no bitmap fonts were found, skipping the test\n");
348 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
350 height_orig
= bitmap_lf
.lfHeight
;
351 lfWidth
= bitmap_lf
.lfWidth
;
353 hfont
= create_font("bitmap", &bitmap_lf
);
354 old_hfont
= SelectObject(hdc
, hfont
);
355 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
356 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
357 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
358 SelectObject(hdc
, old_hfont
);
361 bitmap_lf
.lfHeight
= 0;
362 bitmap_lf
.lfWidth
= 4;
363 hfont
= create_font("bitmap", &bitmap_lf
);
364 old_hfont
= SelectObject(hdc
, hfont
);
365 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
366 SelectObject(hdc
, old_hfont
);
369 bitmap_lf
.lfHeight
= height_orig
;
370 bitmap_lf
.lfWidth
= lfWidth
;
372 /* test fractional scaling */
373 for (i
= 1; i
<= height_orig
* 6; i
++)
377 bitmap_lf
.lfHeight
= i
;
378 hfont
= create_font("fractional", &bitmap_lf
);
379 scale
= (i
+ height_orig
- 1) / height_orig
;
380 nearest_height
= scale
* height_orig
;
381 /* Only jump to the next height if the difference <= 25% original height */
382 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
383 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
384 so we'll not test this particular height. */
385 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
386 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
387 old_hfont
= SelectObject(hdc
, hfont
);
388 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
389 SelectObject(hdc
, old_hfont
);
393 /* test integer scaling 3x2 */
394 bitmap_lf
.lfHeight
= height_orig
* 2;
395 bitmap_lf
.lfWidth
*= 3;
396 hfont
= create_font("3x2", &bitmap_lf
);
397 old_hfont
= SelectObject(hdc
, hfont
);
398 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
399 SelectObject(hdc
, old_hfont
);
402 /* test integer scaling 3x3 */
403 bitmap_lf
.lfHeight
= height_orig
* 3;
404 bitmap_lf
.lfWidth
= 0;
405 hfont
= create_font("3x3", &bitmap_lf
);
406 old_hfont
= SelectObject(hdc
, hfont
);
407 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
408 SelectObject(hdc
, old_hfont
);
414 /* Test how GDI scales outline font metrics */
415 static void test_outline_font(void)
417 static const char test_str
[11] = "Test String";
420 HFONT hfont
, old_hfont
, old_hfont_2
;
421 OUTLINETEXTMETRICA otm
;
423 INT width_orig
, height_orig
, lfWidth
;
426 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
430 if (!is_truetype_font_installed("Arial"))
432 skip("Arial is not installed\n");
436 hdc
= CreateCompatibleDC(0);
438 memset(&lf
, 0, sizeof(lf
));
439 strcpy(lf
.lfFaceName
, "Arial");
441 hfont
= create_font("outline", &lf
);
442 old_hfont
= SelectObject(hdc
, hfont
);
443 otm
.otmSize
= sizeof(otm
);
444 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
445 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
446 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
448 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
449 SelectObject(hdc
, old_hfont
);
452 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
453 lf
.lfHeight
= otm
.otmEMSquare
;
454 lf
.lfHeight
= -lf
.lfHeight
;
455 hfont
= create_font("outline", &lf
);
456 old_hfont
= SelectObject(hdc
, hfont
);
457 otm
.otmSize
= sizeof(otm
);
458 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
459 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
460 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
461 SelectObject(hdc
, old_hfont
);
464 height_orig
= otm
.otmTextMetrics
.tmHeight
;
465 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
467 /* test integer scaling 3x2 */
468 lf
.lfHeight
= height_orig
* 2;
469 lf
.lfWidth
= lfWidth
* 3;
470 hfont
= create_font("3x2", &lf
);
471 old_hfont
= SelectObject(hdc
, hfont
);
472 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
473 SelectObject(hdc
, old_hfont
);
476 /* test integer scaling 3x3 */
477 lf
.lfHeight
= height_orig
* 3;
478 lf
.lfWidth
= lfWidth
* 3;
479 hfont
= create_font("3x3", &lf
);
480 old_hfont
= SelectObject(hdc
, hfont
);
481 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
482 SelectObject(hdc
, old_hfont
);
485 /* test integer scaling 1x1 */
486 lf
.lfHeight
= height_orig
* 1;
487 lf
.lfWidth
= lfWidth
* 1;
488 hfont
= create_font("1x1", &lf
);
489 old_hfont
= SelectObject(hdc
, hfont
);
490 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
491 SelectObject(hdc
, old_hfont
);
494 /* test integer scaling 1x1 */
495 lf
.lfHeight
= height_orig
;
497 hfont
= create_font("1x1", &lf
);
498 old_hfont
= SelectObject(hdc
, hfont
);
499 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
501 /* with an identity matrix */
502 memset(&gm
, 0, sizeof(gm
));
503 SetLastError(0xdeadbeef);
504 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
505 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
506 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
507 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
508 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
509 /* with a custom matrix */
510 memset(&gm
, 0, sizeof(gm
));
511 SetLastError(0xdeadbeef);
512 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
513 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
514 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
515 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
516 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
518 /* Test that changing the DC transformation affects only the font
519 * selected on this DC and doesn't affect the same font selected on
522 hdc_2
= CreateCompatibleDC(0);
523 old_hfont_2
= SelectObject(hdc_2
, hfont
);
524 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
526 SetMapMode(hdc
, MM_ANISOTROPIC
);
528 /* font metrics on another DC should be unchanged */
529 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
531 /* test restrictions of compatibility mode GM_COMPATIBLE */
532 /* part 1: rescaling only X should not change font scaling on screen.
533 So compressing the X axis by 2 is not done, and this
534 appears as X scaling of 2 that no one requested. */
535 SetWindowExtEx(hdc
, 100, 100, NULL
);
536 SetViewportExtEx(hdc
, 50, 100, NULL
);
537 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
538 /* font metrics on another DC should be unchanged */
539 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
541 /* part 2: rescaling only Y should change font scaling.
542 As also X is scaled by a factor of 2, but this is not
543 requested by the DC transformation, we get a scaling factor
544 of 2 in the X coordinate. */
545 SetViewportExtEx(hdc
, 100, 200, NULL
);
546 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
547 /* font metrics on another DC should be unchanged */
548 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
550 /* restore scaling */
551 SetMapMode(hdc
, MM_TEXT
);
553 /* font metrics on another DC should be unchanged */
554 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
556 SelectObject(hdc_2
, old_hfont_2
);
559 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
561 SelectObject(hdc
, old_hfont
);
564 skip("GM_ADVANCED is not supported on this platform\n");
575 SetLastError(0xdeadbeef);
576 ret
= SetWorldTransform(hdc
, &xform
);
577 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
579 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
581 /* with an identity matrix */
582 memset(&gm
, 0, sizeof(gm
));
583 SetLastError(0xdeadbeef);
584 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
585 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
586 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
587 pt
.x
= width_orig
; pt
.y
= 0;
589 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
590 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
591 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
592 /* with a custom matrix */
593 memset(&gm
, 0, sizeof(gm
));
594 SetLastError(0xdeadbeef);
595 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
596 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
597 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
598 pt
.x
= width_orig
; pt
.y
= 0;
600 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
601 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
602 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
604 SetLastError(0xdeadbeef);
605 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
606 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
608 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
610 /* with an identity matrix */
611 memset(&gm
, 0, sizeof(gm
));
612 SetLastError(0xdeadbeef);
613 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
614 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
615 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
616 pt
.x
= width_orig
; pt
.y
= 0;
618 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
619 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
620 /* with a custom matrix */
621 memset(&gm
, 0, sizeof(gm
));
622 SetLastError(0xdeadbeef);
623 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
624 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
625 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
626 pt
.x
= width_orig
; pt
.y
= 0;
628 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
629 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
631 SetLastError(0xdeadbeef);
632 ret
= SetMapMode(hdc
, MM_TEXT
);
633 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
635 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
637 /* with an identity matrix */
638 memset(&gm
, 0, sizeof(gm
));
639 SetLastError(0xdeadbeef);
640 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
641 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
642 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
643 pt
.x
= width_orig
; pt
.y
= 0;
645 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
646 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
647 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
648 /* with a custom matrix */
649 memset(&gm
, 0, sizeof(gm
));
650 SetLastError(0xdeadbeef);
651 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
652 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
653 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
654 pt
.x
= width_orig
; pt
.y
= 0;
656 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
657 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
658 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
660 SelectObject(hdc
, old_hfont
);
665 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
667 LOGFONT
*lf
= (LOGFONT
*)lParam
;
669 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
672 return 0; /* stop enumeration */
674 return 1; /* continue enumeration */
677 static BOOL
is_CJK(void)
679 return (system_lang_id
== LANG_CHINESE
|| system_lang_id
== LANG_JAPANESE
|| system_lang_id
== LANG_KOREAN
);
682 #define FH_SCALE 0x80000000
683 static void test_bitmap_font_metrics(void)
685 static const struct font_data
687 const char face_name
[LF_FACESIZE
];
688 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
689 int ave_char_width
, max_char_width
, dpi
;
690 BYTE first_char
, last_char
, def_char
, break_char
;
696 { "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 },
697 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
698 { "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 },
699 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
700 { "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 },
701 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
702 { "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 },
703 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 13 },
704 { "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 },
705 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
707 { "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 },
708 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 6, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
709 { "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 },
710 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 8, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
711 { "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 },
712 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 10, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
713 { "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 },
714 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 14, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
715 { "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 },
716 { "MS Sans Serif", FW_NORMAL
, FH_SCALE
| 18, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
, 0, 16 },
718 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
719 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
720 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
721 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
722 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
723 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
724 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
725 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
726 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
727 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
728 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
729 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN2
},
730 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
731 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
},
732 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x81, 0x40, FS_LATIN2
},
733 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
735 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
736 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
737 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
738 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
739 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
740 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
741 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
742 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
743 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
744 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
745 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x81, 0x20, FS_LATIN1
| FS_LATIN2
},
746 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, 0x20, 0xff, 0x7f, 0x20, FS_CYRILLIC
},
748 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
749 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
750 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
751 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
752 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
753 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
754 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
755 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
756 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
757 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
758 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
759 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
760 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
761 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
762 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
763 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
764 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
766 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
767 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
768 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
769 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
770 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_CYRILLIC
},
771 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
},
772 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
773 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
774 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
775 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
776 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
778 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
779 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
780 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
782 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
783 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
784 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, 0x20, 0xff, 0x40, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
786 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
787 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
788 { "System", FW_NORMAL
, 18, 16, 2, 0, 2, 8, 16, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
790 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
791 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
793 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
},
794 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
795 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
796 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
797 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
798 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
799 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
800 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
801 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
802 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
803 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
, LANG_ARABIC
},
804 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
805 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
806 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
807 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
, LANG_ARABIC
},
808 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
809 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 9, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
810 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
811 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
, LANG_ARABIC
},
812 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 4, 10, 96, 0x00, 0xff, 0x60, 0x00, FS_ARABIC
},
813 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, 0x20, 0xff, 0x80, 0x20, FS_JISJAPAN
},
815 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
816 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
817 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
818 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
819 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_JISJAPAN
},
820 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN2
| FS_CYRILLIC
},
821 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
822 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
823 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
824 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
825 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
826 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
828 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
},
829 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, 0x20, 0xff, 0x80, 0x20, FS_CYRILLIC
},
830 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, 0x20, 0xff, 0xa0, 0x20, FS_JISJAPAN
},
832 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 120, 0x20, 0xff, 0x80, 0x20, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
834 /* FIXME: add "Terminal" */
836 static const int font_log_pixels
[] = { 96, 120 };
839 HFONT hfont
, old_hfont
;
841 INT ret
, i
, expected_cs
, screen_log_pixels
, diff
, font_res
;
842 char face_name
[LF_FACESIZE
];
845 trace("system language id %04x\n", system_lang_id
);
847 expected_cs
= GetACP();
848 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
850 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
853 expected_cs
= csi
.ciCharset
;
854 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
856 hdc
= CreateCompatibleDC(0);
859 trace("logpixelsX %d, logpixelsY %d\n", GetDeviceCaps(hdc
, LOGPIXELSX
),
860 GetDeviceCaps(hdc
, LOGPIXELSY
));
862 screen_log_pixels
= GetDeviceCaps(hdc
, LOGPIXELSY
);
865 for (i
= 0; i
< sizeof(font_log_pixels
)/sizeof(font_log_pixels
[0]); i
++)
867 int new_diff
= abs(font_log_pixels
[i
] - screen_log_pixels
);
871 font_res
= font_log_pixels
[i
];
874 trace("best font resolution is %d\n", font_res
);
876 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
880 memset(&lf
, 0, sizeof(lf
));
882 height
= fd
[i
].height
& ~FH_SCALE
;
883 lf
.lfHeight
= height
;
884 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
886 for(bit
= 0; bit
< 32; bit
++)
894 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
895 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
897 lf
.lfCharSet
= csi
.ciCharset
;
898 trace("looking for %s height %d charset %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
);
899 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
900 if (fd
[i
].height
& FH_SCALE
)
901 ok(ret
, "scaled font height %d should not be enumerated\n", height
);
904 if (font_res
== fd
[i
].dpi
&& lf
.lfCharSet
== expected_cs
)
906 if (ret
) /* FIXME: Remove once Wine is fixed */
907 todo_wine
ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
909 ok(!ret
, "%s height %d charset %d dpi %d should be enumerated\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
912 if (ret
&& !(fd
[i
].height
& FH_SCALE
))
915 hfont
= create_font(lf
.lfFaceName
, &lf
);
916 old_hfont
= SelectObject(hdc
, hfont
);
918 SetLastError(0xdeadbeef);
919 ret
= GetTextFace(hdc
, sizeof(face_name
), face_name
);
920 ok(ret
, "GetTextFace error %u\n", GetLastError());
922 if (lstrcmp(face_name
, fd
[i
].face_name
) != 0)
924 ok(ret
!= ANSI_CHARSET
, "font charset should not be ANSI_CHARSET\n");
925 ok(ret
!= expected_cs
, "font charset %d should not be %d\n", ret
, expected_cs
);
926 trace("Skipping replacement %s height %d charset %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
);
927 SelectObject(hdc
, old_hfont
);
932 memset(&gm
, 0, sizeof(gm
));
933 SetLastError(0xdeadbeef);
934 ret
= GetGlyphOutline(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
936 ok(ret
== GDI_ERROR
, "GetGlyphOutline should fail for a bitmap font\n");
937 ok(GetLastError() == ERROR_CAN_NOT_COMPLETE
, "expected ERROR_CAN_NOT_COMPLETE, got %u\n", GetLastError());
940 bRet
= GetTextMetrics(hdc
, &tm
);
941 ok(bRet
, "GetTextMetrics error %d\n", GetLastError());
943 SetLastError(0xdeadbeef);
944 ret
= GetTextCharset(hdc
);
945 if (is_CJK() && lf
.lfCharSet
== ANSI_CHARSET
)
946 ok(ret
== ANSI_CHARSET
, "got charset %d, expected ANSI_CHARSETd\n", ret
);
948 ok(ret
== expected_cs
, "got charset %d, expected %d\n", ret
, expected_cs
);
950 trace("created %s, height %d charset %x dpi %d\n", face_name
, tm
.tmHeight
, tm
.tmCharSet
, tm
.tmDigitizedAspectX
);
951 trace("expected %s, height %d scaled_hight %d, dpi %d\n", fd
[i
].face_name
, height
, fd
[i
].scaled_height
, fd
[i
].dpi
);
953 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
955 trace("matched %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
956 if (fd
[i
].skip_lang_id
== 0 || system_lang_id
!= fd
[i
].skip_lang_id
)
958 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, height
, tm
.tmWeight
, fd
[i
].weight
);
959 if (fd
[i
].height
& FH_SCALE
)
960 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
);
962 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
);
963 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmAscent
, fd
[i
].ascent
);
964 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, height
, tm
.tmDescent
, fd
[i
].descent
);
965 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
);
966 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
);
967 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
);
968 ok(tm
.tmFirstChar
== fd
[i
].first_char
, "%s(%d): tm.tmFirstChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmFirstChar
);
969 ok(tm
.tmLastChar
== fd
[i
].last_char
, "%s(%d): tm.tmLastChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmLastChar
);
970 /* Substitutions like MS Sans Serif,0=MS Sans Serif,204
971 make default char test fail */
972 if (tm
.tmCharSet
== lf
.lfCharSet
)
973 ok(tm
.tmDefaultChar
== fd
[i
].def_char
, "%s(%d): tm.tmDefaultChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmDefaultChar
);
974 ok(tm
.tmBreakChar
== fd
[i
].break_char
, "%s(%d): tm.tmBreakChar = %02x\n", fd
[i
].face_name
, height
, tm
.tmBreakChar
);
975 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
);
977 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
978 that make the max width bigger */
979 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
980 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
);
983 skip("Skipping font metrics test for system langid 0x%x\n",
986 SelectObject(hdc
, old_hfont
);
994 static void test_GdiGetCharDimensions(void)
1000 LONG avgwidth
, height
;
1001 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1003 if (!pGdiGetCharDimensions
)
1005 win_skip("GdiGetCharDimensions not available on this platform\n");
1009 hdc
= CreateCompatibleDC(NULL
);
1011 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
1012 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
1014 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
1015 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1016 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
1018 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
1019 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1021 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
1022 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1025 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
1026 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
1027 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
1032 static int CALLBACK
create_font_proc(const LOGFONT
*lpelfe
,
1033 const TEXTMETRIC
*lpntme
,
1034 DWORD FontType
, LPARAM lParam
)
1036 if (FontType
& TRUETYPE_FONTTYPE
)
1040 hfont
= CreateFontIndirect(lpelfe
);
1043 *(HFONT
*)lParam
= hfont
;
1051 static void test_GetCharABCWidths(void)
1053 static const WCHAR str
[] = {'a',0};
1075 {0xffffff, 0xffffff},
1076 {0x1000000, 0x1000000},
1077 {0xffffff, 0x1000000},
1078 {0xffffffff, 0xffffffff},
1086 BOOL r
[sizeof range
/ sizeof range
[0]];
1089 {ANSI_CHARSET
, 0x30, 0x30,
1090 {TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1091 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042,
1092 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1093 {HANGEUL_CHARSET
, 0x8141, 0xac02,
1094 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1095 {JOHAB_CHARSET
, 0x8446, 0x3135,
1096 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1097 {GB2312_CHARSET
, 0x8141, 0x4e04,
1098 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}},
1099 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001,
1100 {TRUE
, TRUE
, FALSE
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
, TRUE
}}
1104 if (!pGetCharABCWidthsA
|| !pGetCharABCWidthsW
|| !pGetCharABCWidthsFloatW
|| !pGetCharABCWidthsI
)
1106 win_skip("GetCharABCWidthsA/W/I not available on this platform\n");
1110 memset(&lf
, 0, sizeof(lf
));
1111 strcpy(lf
.lfFaceName
, "System");
1114 hfont
= CreateFontIndirectA(&lf
);
1116 hfont
= SelectObject(hdc
, hfont
);
1118 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
1119 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
1121 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
1122 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1124 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
1125 ok(!ret
, "GetCharABCWidthsI should have failed\n");
1127 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
1128 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
1130 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
1131 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1133 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
1134 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1136 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
1137 ok(!ret
, "GetCharABCWidthsW should have failed\n");
1139 ret
= pGetCharABCWidthsFloatW(NULL
, 'a', 'a', abcf
);
1140 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1142 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', NULL
);
1143 ok(!ret
, "GetCharABCWidthsFloatW should have failed\n");
1145 ret
= pGetCharABCWidthsFloatW(hdc
, 'a', 'a', abcf
);
1146 ok(ret
, "GetCharABCWidthsFloatW should have succeeded\n");
1148 hfont
= SelectObject(hdc
, hfont
);
1149 DeleteObject(hfont
);
1151 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
1155 UINT code
= 0x41, j
;
1157 lf
.lfFaceName
[0] = '\0';
1158 lf
.lfCharSet
= c
[i
].cs
;
1159 lf
.lfPitchAndFamily
= 0;
1160 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
1162 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
1166 memset(a
, 0, sizeof a
);
1167 memset(w
, 0, sizeof w
);
1168 hfont
= SelectObject(hdc
, hfont
);
1169 ok(pGetCharABCWidthsA(hdc
, c
[i
].a
, c
[i
].a
+ 1, a
) &&
1170 pGetCharABCWidthsW(hdc
, c
[i
].w
, c
[i
].w
+ 1, w
) &&
1171 memcmp(a
, w
, sizeof a
) == 0,
1172 "GetCharABCWidthsA and GetCharABCWidthsW should return same widths. charset = %u\n", c
[i
].cs
);
1174 memset(a
, 0xbb, sizeof a
);
1175 ret
= pGetCharABCWidthsA(hdc
, code
, code
, a
);
1176 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1177 memset(full
, 0xcc, sizeof full
);
1178 ret
= pGetCharABCWidthsA(hdc
, 0x00, code
, full
);
1179 ok(ret
, "GetCharABCWidthsA should have succeeded\n");
1180 ok(memcmp(&a
[0], &full
[code
], sizeof(ABC
)) == 0,
1181 "GetCharABCWidthsA info should match. codepage = %u\n", c
[i
].cs
);
1183 for (j
= 0; j
< sizeof range
/ sizeof range
[0]; ++j
)
1185 memset(full
, 0xdd, sizeof full
);
1186 ret
= pGetCharABCWidthsA(hdc
, range
[j
].first
, range
[j
].last
, full
);
1187 ok(ret
== c
[i
].r
[j
], "GetCharABCWidthsA %x - %x should have %s\n",
1188 range
[j
].first
, range
[j
].last
, c
[i
].r
[j
] ? "succeeded" : "failed");
1191 UINT last
= range
[j
].last
- range
[j
].first
;
1192 ret
= pGetCharABCWidthsA(hdc
, range
[j
].last
, range
[j
].last
, a
);
1193 ok(ret
&& memcmp(&full
[last
], &a
[0], sizeof(ABC
)) == 0,
1194 "GetCharABCWidthsA %x should match. codepage = %u\n",
1195 range
[j
].last
, c
[i
].cs
);
1199 hfont
= SelectObject(hdc
, hfont
);
1200 DeleteObject(hfont
);
1203 ReleaseDC(NULL
, hdc
);
1206 static void test_text_extents(void)
1208 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
1210 INT i
, len
, fit1
, fit2
;
1219 memset(&lf
, 0, sizeof(lf
));
1220 strcpy(lf
.lfFaceName
, "Arial");
1223 hfont
= CreateFontIndirectA(&lf
);
1225 hfont
= SelectObject(hdc
, hfont
);
1226 GetTextMetricsA(hdc
, &tm
);
1227 GetTextExtentPointA(hdc
, "o", 1, &sz
);
1228 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
1230 SetLastError(0xdeadbeef);
1231 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
1232 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1234 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
1235 hfont
= SelectObject(hdc
, hfont
);
1236 DeleteObject(hfont
);
1242 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
1243 extents
[0] = 1; /* So that the increasing sequence test will fail
1244 if the extents array is untouched. */
1245 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
1246 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
1247 ok(sz1
.cy
== sz2
.cy
,
1248 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
1249 /* Because of the '\n' in the string GetTextExtentExPoint and
1250 GetTextExtentPoint return different widths under Win2k, but
1251 under WinXP they return the same width. So we don't test that
1254 for (i
= 1; i
< len
; ++i
)
1255 ok(extents
[i
-1] <= extents
[i
],
1256 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
1258 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
1259 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
1260 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
1261 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
1262 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
1263 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
1264 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
1265 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
1266 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
1267 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
1268 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
1269 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
1270 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
1271 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
1272 HeapFree(GetProcessHeap(), 0, extents
);
1274 /* extents functions fail with -ve counts (the interesting case being -1) */
1275 ret
= GetTextExtentPointA(hdc
, "o", -1, &sz
);
1276 ok(ret
== FALSE
, "got %d\n", ret
);
1277 ret
= GetTextExtentExPointA(hdc
, "o", -1, 0, NULL
, NULL
, &sz
);
1278 ok(ret
== FALSE
, "got %d\n", ret
);
1279 ret
= GetTextExtentExPointW(hdc
, wt
, -1, 0, NULL
, NULL
, &sz1
);
1280 ok(ret
== FALSE
, "got %d\n", ret
);
1282 /* max_extent = 0 succeeds and returns zero */
1284 ret
= GetTextExtentExPointA(hdc
, NULL
, 0, 0, &fit1
, NULL
, &sz
);
1286 broken(ret
== FALSE
), /* NT4, 2k */
1289 broken(fit1
== -215), /* NT4, 2k */
1290 "fit = %d\n", fit1
);
1291 ret
= GetTextExtentExPointW(hdc
, NULL
, 0, 0, &fit2
, NULL
, &sz1
);
1292 ok(ret
== TRUE
, "got %d\n", ret
);
1293 ok(fit2
== 0, "fit = %d\n", fit2
);
1295 /* max_extent = -1 is interpreted as a very large width that will
1296 * definitely fit our three characters */
1298 ret
= GetTextExtentExPointA(hdc
, "One", 3, -1, &fit1
, NULL
, &sz
);
1299 ok(ret
== TRUE
, "got %d\n", ret
);
1300 ok(fit1
== 3, "fit = %d\n", fit1
);
1301 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -1, &fit2
, NULL
, &sz
);
1302 ok(ret
== TRUE
, "got %d\n", ret
);
1303 ok(fit2
== 3, "fit = %d\n", fit2
);
1305 /* max_extent = -2 is interpreted similarly, but the Ansi version
1306 * rejects it while the Unicode one accepts it */
1308 ret
= GetTextExtentExPointA(hdc
, "One", 3, -2, &fit1
, NULL
, &sz
);
1309 ok(ret
== FALSE
, "got %d\n", ret
);
1310 ok(fit1
== -215, "fit = %d\n", fit1
);
1311 ret
= GetTextExtentExPointW(hdc
, wt
, 3, -2, &fit2
, NULL
, &sz
);
1312 ok(ret
== TRUE
, "got %d\n", ret
);
1313 ok(fit2
== 3, "fit = %d\n", fit2
);
1315 hfont
= SelectObject(hdc
, hfont
);
1316 DeleteObject(hfont
);
1317 ReleaseDC(NULL
, hdc
);
1320 static void test_GetGlyphIndices(void)
1327 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1328 WORD glyphs
[(sizeof(testtext
)/2)-1];
1332 if (!pGetGlyphIndicesW
) {
1333 win_skip("GetGlyphIndicesW not available on platform\n");
1339 memset(&lf
, 0, sizeof(lf
));
1340 strcpy(lf
.lfFaceName
, "System");
1342 lf
.lfCharSet
= ANSI_CHARSET
;
1344 hfont
= CreateFontIndirectA(&lf
);
1345 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
1346 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1347 if (textm
.tmCharSet
== ANSI_CHARSET
)
1349 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1350 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1351 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1352 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1354 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1355 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1356 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1357 textm
.tmDefaultChar
, glyphs
[4]);
1360 /* FIXME: Write tests for non-ANSI charsets. */
1361 skip("GetGlyphIndices System font tests only for ANSI_CHARSET\n");
1363 if(!is_font_installed("Tahoma"))
1365 skip("Tahoma is not installed so skipping this test\n");
1368 memset(&lf
, 0, sizeof(lf
));
1369 strcpy(lf
.lfFaceName
, "Tahoma");
1372 hfont
= CreateFontIndirectA(&lf
);
1373 hOldFont
= SelectObject(hdc
, hfont
);
1374 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1375 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1376 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1377 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1378 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1380 testtext
[0] = textm
.tmDefaultChar
;
1381 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1382 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1383 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1384 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1385 DeleteObject(SelectObject(hdc
, hOldFont
));
1388 static void test_GetKerningPairs(void)
1390 static const struct kerning_data
1392 const char face_name
[LF_FACESIZE
];
1394 /* some interesting fields from OUTLINETEXTMETRIC */
1395 LONG tmHeight
, tmAscent
, tmDescent
;
1400 UINT otmsCapEmHeight
;
1405 UINT otmusMinimumPPEM
;
1406 /* small subset of kerning pairs to test */
1407 DWORD total_kern_pairs
;
1408 const KERNINGPAIR kern_pair
[26];
1411 {"Arial", 12, 12, 9, 3,
1412 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1415 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1416 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1417 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1418 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1419 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1420 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1421 {933,970,+1},{933,972,-1}
1424 {"Arial", -34, 39, 32, 7,
1425 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1428 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1429 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1430 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1431 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1432 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1433 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1434 {933,970,+2},{933,972,-3}
1437 { "Arial", 120, 120, 97, 23,
1438 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1441 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1442 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1443 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1444 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1445 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1446 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1447 {933,970,+6},{933,972,-10}
1450 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1451 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1452 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1455 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1456 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1457 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1458 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1459 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1460 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1461 {933,970,+54},{933,972,-83}
1467 HFONT hfont
, hfont_old
;
1468 KERNINGPAIR
*kern_pair
;
1470 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1474 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1475 * which may render this test unusable, so we're trying to avoid that.
1477 SetLastError(0xdeadbeef);
1478 GetKerningPairsW(hdc
, 0, NULL
);
1479 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1481 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1486 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1488 OUTLINETEXTMETRICW otm
;
1491 if (!is_font_installed(kd
[i
].face_name
))
1493 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1497 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1499 memset(&lf
, 0, sizeof(lf
));
1500 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1501 lf
.lfHeight
= kd
[i
].height
;
1502 hfont
= CreateFontIndirect(&lf
);
1505 hfont_old
= SelectObject(hdc
, hfont
);
1507 SetLastError(0xdeadbeef);
1508 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1509 uiRet
= GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
);
1510 ok(uiRet
== sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1512 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
), "expected %d, got %d\n",
1513 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1514 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
), "expected %d, got %d\n",
1515 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1516 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1517 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1519 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1520 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1521 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1522 kd
[i
].otmAscent
, otm
.otmAscent
);
1523 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1524 kd
[i
].otmDescent
, otm
.otmDescent
);
1525 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1526 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1527 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1528 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1529 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1530 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1532 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1533 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1534 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1535 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1536 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1537 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1538 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1539 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1540 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1543 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1544 trace("total_kern_pairs %u\n", total_kern_pairs
);
1545 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1547 /* Win98 (GetKerningPairsA) and XP behave differently here, the test
1550 SetLastError(0xdeadbeef);
1551 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1552 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1553 "got error %u, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1554 ok(ret
== 0, "got %u, expected 0\n", ret
);
1556 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1557 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1559 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1560 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1562 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1563 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1567 for (n
= 0; n
< ret
; n
++)
1570 /* Disabled to limit console spam */
1571 if (0 && kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1572 trace("{'%c','%c',%d},\n",
1573 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1574 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1576 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1577 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1579 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1580 "pair %d:%d got %d, expected %d\n",
1581 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1582 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1588 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1589 matches
, kd
[i
].total_kern_pairs
);
1591 HeapFree(GetProcessHeap(), 0, kern_pair
);
1593 SelectObject(hdc
, hfont_old
);
1594 DeleteObject(hfont
);
1600 static void test_height_selection(void)
1602 static const struct font_data
1604 const char face_name
[LF_FACESIZE
];
1605 int requested_height
;
1606 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1609 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96 },
1610 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96 },
1611 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96 },
1612 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96 },
1613 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96 },
1614 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96 },
1615 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96 },
1616 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96 },
1617 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96 },
1618 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96 }
1622 HFONT hfont
, old_hfont
;
1626 hdc
= CreateCompatibleDC(0);
1629 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
1631 if (!is_truetype_font_installed(fd
[i
].face_name
))
1633 skip("%s is not installed\n", fd
[i
].face_name
);
1637 memset(&lf
, 0, sizeof(lf
));
1638 lf
.lfHeight
= fd
[i
].requested_height
;
1639 lf
.lfWeight
= fd
[i
].weight
;
1640 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1642 hfont
= CreateFontIndirect(&lf
);
1645 old_hfont
= SelectObject(hdc
, hfont
);
1646 ret
= GetTextMetrics(hdc
, &tm
);
1647 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1648 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1650 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1651 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
);
1652 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
);
1653 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
);
1654 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
);
1655 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1656 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
);
1658 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
);
1661 SelectObject(hdc
, old_hfont
);
1662 DeleteObject(hfont
);
1668 static void test_GetOutlineTextMetrics(void)
1670 OUTLINETEXTMETRIC
*otm
;
1672 HFONT hfont
, hfont_old
;
1674 DWORD ret
, otm_size
;
1677 if (!is_font_installed("Arial"))
1679 skip("Arial is not installed\n");
1685 memset(&lf
, 0, sizeof(lf
));
1686 strcpy(lf
.lfFaceName
, "Arial");
1688 lf
.lfWeight
= FW_NORMAL
;
1689 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1690 lf
.lfQuality
= PROOF_QUALITY
;
1691 hfont
= CreateFontIndirect(&lf
);
1694 hfont_old
= SelectObject(hdc
, hfont
);
1695 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1696 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1698 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1700 memset(otm
, 0xAA, otm_size
);
1701 SetLastError(0xdeadbeef);
1702 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1703 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1704 ok(ret
== 1 /* Win9x */ ||
1705 ret
== otm
->otmSize
/* XP*/,
1706 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1707 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1709 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1710 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1711 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1712 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1715 memset(otm
, 0xAA, otm_size
);
1716 SetLastError(0xdeadbeef);
1717 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1718 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1719 ok(ret
== 1 /* Win9x */ ||
1720 ret
== otm
->otmSize
/* XP*/,
1721 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1722 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1724 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1725 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1726 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1727 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1730 /* ask about truncated data */
1731 memset(otm
, 0xAA, otm_size
);
1732 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1733 SetLastError(0xdeadbeef);
1734 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1735 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1736 ok(ret
== 1 /* Win9x */ ||
1737 ret
== otm
->otmSize
/* XP*/,
1738 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1739 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1741 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1742 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1743 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1745 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1747 HeapFree(GetProcessHeap(), 0, otm
);
1749 SelectObject(hdc
, hfont_old
);
1750 DeleteObject(hfont
);
1755 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1759 areaWidth
= clientArea
->right
- clientArea
->left
,
1761 PSTR pFirstChar
, pLastChar
;
1768 int GetTextExtentExPointWWidth
;
1771 GetTextMetricsA(hdc
, &tm
);
1772 y
= clientArea
->top
;
1775 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1781 /* if not at the end of the string, ... */
1782 if (*str
== '\0') break;
1783 /* ... add the next word to the current extent */
1784 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1786 SetTextJustification(hdc
, 0, 0);
1787 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1788 } while ((int) size
.cx
< areaWidth
);
1790 /* ignore trailing break chars */
1792 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1798 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1800 SetTextJustification(hdc
, 0, 0);
1801 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1803 /* do not justify the last extent */
1804 if (*str
!= '\0' && breakCount
> 0)
1806 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1807 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1808 if (size
.cx
!= areaWidth
&& nErrors
< sizeof(error
)/sizeof(error
[0]) - 1)
1810 error
[nErrors
].start
= pFirstChar
;
1811 error
[nErrors
].len
= pLastChar
- pFirstChar
;
1812 error
[nErrors
].GetTextExtentExPointWWidth
= size
.cx
;
1817 trace( "%u %.*s\n", size
.cx
, (int)(pLastChar
- pFirstChar
), pFirstChar
);
1821 } while (*str
&& y
< clientArea
->bottom
);
1823 for (e
= 0; e
< nErrors
; e
++)
1825 /* The width returned by GetTextExtentPoint32() is exactly the same
1826 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1827 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1828 "GetTextExtentPointW() for \"%.*s\" should have returned a width of %d, not %d.\n",
1829 error
[e
].len
, error
[e
].start
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1833 static void test_SetTextJustification(void)
1843 static char testText
[] =
1844 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1845 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1846 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1847 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1848 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1849 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1850 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1852 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1853 GetClientRect( hwnd
, &clientArea
);
1854 hdc
= GetDC( hwnd
);
1856 memset(&lf
, 0, sizeof lf
);
1857 lf
.lfCharSet
= ANSI_CHARSET
;
1858 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1859 lf
.lfWeight
= FW_DONTCARE
;
1861 lf
.lfQuality
= DEFAULT_QUALITY
;
1862 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1863 hfont
= create_font("Times New Roman", &lf
);
1864 SelectObject(hdc
, hfont
);
1866 testJustification(hdc
, testText
, &clientArea
);
1868 if (!pGetGlyphIndicesA
|| !pGetTextExtentExPointI
) goto done
;
1869 pGetGlyphIndicesA( hdc
, "A ", 2, indices
, 0 );
1871 SetTextJustification(hdc
, 0, 0);
1872 GetTextExtentPoint32(hdc
, " ", 1, &expect
);
1873 GetTextExtentPoint32(hdc
, " ", 3, &size
);
1874 ok( size
.cx
== 3 * expect
.cx
, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1875 SetTextJustification(hdc
, 4, 1);
1876 GetTextExtentPoint32(hdc
, " ", 1, &size
);
1877 ok( size
.cx
== expect
.cx
+ 4, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1878 SetTextJustification(hdc
, 9, 2);
1879 GetTextExtentPoint32(hdc
, " ", 2, &size
);
1880 ok( size
.cx
== 2 * expect
.cx
+ 9, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1881 SetTextJustification(hdc
, 7, 3);
1882 GetTextExtentPoint32(hdc
, " ", 3, &size
);
1883 ok( size
.cx
== 3 * expect
.cx
+ 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1884 SetTextJustification(hdc
, 7, 3);
1885 SetTextCharacterExtra(hdc
, 2 );
1886 GetTextExtentPoint32(hdc
, " ", 3, &size
);
1887 ok( size
.cx
== 3 * (expect
.cx
+ 2) + 7, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1888 SetTextJustification(hdc
, 0, 0);
1889 SetTextCharacterExtra(hdc
, 0);
1890 size
.cx
= size
.cy
= 1234;
1891 GetTextExtentPoint32(hdc
, " ", 0, &size
);
1892 ok( size
.cx
== 0 && size
.cy
== 0, "wrong size %d,%d\n", size
.cx
, size
.cy
);
1893 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &expect
);
1894 SetTextJustification(hdc
, 5, 1);
1895 pGetTextExtentExPointI(hdc
, indices
, 2, -1, NULL
, NULL
, &size
);
1896 ok( size
.cx
== expect
.cx
+ 5, "wrong size %d/%d\n", size
.cx
, expect
.cx
);
1897 SetTextJustification(hdc
, 0, 0);
1899 SetMapMode( hdc
, MM_ANISOTROPIC
);
1900 SetWindowExtEx( hdc
, 2, 2, NULL
);
1901 GetClientRect( hwnd
, &clientArea
);
1902 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
1903 testJustification(hdc
, testText
, &clientArea
);
1905 GetTextExtentPoint32(hdc
, "A", 1, &expect
);
1906 for (i
= 0; i
< 10; i
++)
1908 SetTextCharacterExtra(hdc
, i
);
1909 GetTextExtentPoint32(hdc
, "A", 1, &size
);
1910 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
1912 SetTextCharacterExtra(hdc
, 0);
1913 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &expect
);
1914 for (i
= 0; i
< 10; i
++)
1916 SetTextCharacterExtra(hdc
, i
);
1917 pGetTextExtentExPointI(hdc
, indices
, 1, -1, NULL
, NULL
, &size
);
1918 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
1920 SetTextCharacterExtra(hdc
, 0);
1922 SetViewportExtEx( hdc
, 3, 3, NULL
);
1923 GetClientRect( hwnd
, &clientArea
);
1924 DPtoLP( hdc
, (POINT
*)&clientArea
, 2 );
1925 testJustification(hdc
, testText
, &clientArea
);
1927 GetTextExtentPoint32(hdc
, "A", 1, &expect
);
1928 for (i
= 0; i
< 10; i
++)
1930 SetTextCharacterExtra(hdc
, i
);
1931 GetTextExtentPoint32(hdc
, "A", 1, &size
);
1932 ok( size
.cx
== expect
.cx
+ i
, "wrong size %d/%d+%d\n", size
.cx
, expect
.cx
, i
);
1936 DeleteObject(hfont
);
1937 ReleaseDC(hwnd
, hdc
);
1938 DestroyWindow(hwnd
);
1941 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1945 HFONT hfont
, hfont_old
;
1952 assert(count
<= 128);
1954 memset(&lf
, 0, sizeof(lf
));
1956 lf
.lfCharSet
= charset
;
1958 lstrcpyA(lf
.lfFaceName
, "Arial");
1959 SetLastError(0xdeadbeef);
1960 hfont
= CreateFontIndirectA(&lf
);
1961 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1964 hfont_old
= SelectObject(hdc
, hfont
);
1966 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1967 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1969 SetLastError(0xdeadbeef);
1970 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1971 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1973 if (charset
== SYMBOL_CHARSET
)
1975 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1976 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1980 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1981 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1984 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1986 trace("Can't find codepage for charset %d\n", cs
);
1990 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1992 if (pGdiGetCodePage
!= NULL
&& pGdiGetCodePage(hdc
) != code_page
)
1994 skip("Font code page %d, looking for code page %d\n",
1995 pGdiGetCodePage(hdc
), code_page
);
2003 WCHAR unicode_buf
[128];
2005 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2007 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
2009 SetLastError(0xdeadbeef);
2010 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
2011 ok(ret
== count
, "GetGlyphIndicesW expected %d got %d, error %u\n",
2012 count
, ret
, GetLastError());
2018 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
2020 SetLastError(0xdeadbeef);
2021 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
2022 ok(ret
== count
, "GetGlyphIndicesA expected %d got %d, error %u\n",
2023 count
, ret
, GetLastError());
2026 SelectObject(hdc
, hfont_old
);
2027 DeleteObject(hfont
);
2034 static void test_font_charset(void)
2036 static struct charset_data
2040 WORD font_idxA
[128], font_idxW
[128];
2043 { ANSI_CHARSET
, 1252 },
2044 { RUSSIAN_CHARSET
, 1251 },
2045 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
2049 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
2051 win_skip("Skipping the font charset test on a Win9x platform\n");
2055 if (!is_font_installed("Arial"))
2057 skip("Arial is not installed\n");
2061 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
2063 if (cd
[i
].charset
== SYMBOL_CHARSET
)
2065 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
2067 skip("Symbol or Wingdings is not installed\n");
2071 if (get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
) &&
2072 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
))
2073 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
2076 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
2079 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
2080 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
2083 skip("Symbol or Wingdings is not installed\n");
2086 static void test_GetFontUnicodeRanges(void)
2090 HFONT hfont
, hfont_old
;
2095 if (!pGetFontUnicodeRanges
)
2097 win_skip("GetFontUnicodeRanges not available before W2K\n");
2101 memset(&lf
, 0, sizeof(lf
));
2102 lstrcpyA(lf
.lfFaceName
, "Arial");
2103 hfont
= create_font("Arial", &lf
);
2106 hfont_old
= SelectObject(hdc
, hfont
);
2108 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2109 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2111 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2112 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2114 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2116 size
= pGetFontUnicodeRanges(hdc
, gs
);
2117 ok(size
, "GetFontUnicodeRanges failed\n");
2119 if (0) /* Disabled to limit console spam */
2120 for (i
= 0; i
< gs
->cRanges
; i
++)
2121 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2122 trace("found %u ranges\n", gs
->cRanges
);
2124 HeapFree(GetProcessHeap(), 0, gs
);
2126 SelectObject(hdc
, hfont_old
);
2127 DeleteObject(hfont
);
2128 ReleaseDC(NULL
, hdc
);
2131 #define MAX_ENUM_FONTS 4096
2133 struct enum_font_data
2136 LOGFONT lf
[MAX_ENUM_FONTS
];
2139 struct enum_fullname_data
2142 ENUMLOGFONT elf
[MAX_ENUM_FONTS
];
2145 struct enum_font_dataW
2148 LOGFONTW lf
[MAX_ENUM_FONTS
];
2151 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
2153 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2154 const NEWTEXTMETRIC
*ntm
= (const NEWTEXTMETRIC
*)tm
;
2156 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2157 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2159 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2161 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2163 if (0) /* Disabled to limit console spam */
2164 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2165 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2166 if (efd
->total
< MAX_ENUM_FONTS
)
2167 efd
->lf
[efd
->total
++] = *lf
;
2169 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2174 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2176 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2177 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2179 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2180 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2182 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2184 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2186 if (0) /* Disabled to limit console spam */
2187 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2188 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2189 if (efd
->total
< MAX_ENUM_FONTS
)
2190 efd
->lf
[efd
->total
++] = *lf
;
2192 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2197 static void get_charset_stats(struct enum_font_data
*efd
,
2198 int *ansi_charset
, int *symbol_charset
,
2199 int *russian_charset
)
2204 *symbol_charset
= 0;
2205 *russian_charset
= 0;
2207 for (i
= 0; i
< efd
->total
; i
++)
2209 switch (efd
->lf
[i
].lfCharSet
)
2214 case SYMBOL_CHARSET
:
2215 (*symbol_charset
)++;
2217 case RUSSIAN_CHARSET
:
2218 (*russian_charset
)++;
2224 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2225 int *ansi_charset
, int *symbol_charset
,
2226 int *russian_charset
)
2231 *symbol_charset
= 0;
2232 *russian_charset
= 0;
2234 for (i
= 0; i
< efd
->total
; i
++)
2236 switch (efd
->lf
[i
].lfCharSet
)
2241 case SYMBOL_CHARSET
:
2242 (*symbol_charset
)++;
2244 case RUSSIAN_CHARSET
:
2245 (*russian_charset
)++;
2251 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2253 struct enum_font_data efd
;
2254 struct enum_font_dataW efdw
;
2257 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2259 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2261 if (*font_name
&& !is_truetype_font_installed(font_name
))
2263 skip("%s is not installed\n", font_name
);
2269 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2270 * while EnumFontFamiliesEx doesn't.
2272 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2275 * Use EnumFontFamiliesW since win98 crashes when the
2276 * second parameter is NULL using EnumFontFamilies
2279 SetLastError(0xdeadbeef);
2280 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2281 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2284 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2285 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2286 ansi_charset
, symbol_charset
, russian_charset
);
2287 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2288 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2289 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2290 ok(russian_charset
> 0 ||
2291 broken(russian_charset
== 0), /* NT4 */
2292 "NULL family should enumerate RUSSIAN_CHARSET\n");
2296 SetLastError(0xdeadbeef);
2297 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2298 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2301 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2302 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2303 ansi_charset
, symbol_charset
, russian_charset
);
2304 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2305 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2306 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2307 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2312 SetLastError(0xdeadbeef);
2313 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2314 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2315 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2316 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2317 ansi_charset
, symbol_charset
, russian_charset
,
2318 *font_name
? font_name
: "<empty>");
2320 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2322 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2323 for (i
= 0; i
< efd
.total
; i
++)
2325 /* FIXME: remove completely once Wine is fixed */
2326 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2329 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2332 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2333 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2334 font_name
, efd
.lf
[i
].lfFaceName
);
2337 memset(&lf
, 0, sizeof(lf
));
2338 lf
.lfCharSet
= ANSI_CHARSET
;
2339 lstrcpy(lf
.lfFaceName
, font_name
);
2341 SetLastError(0xdeadbeef);
2342 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2343 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2344 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2345 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2346 ansi_charset
, symbol_charset
, russian_charset
,
2347 *font_name
? font_name
: "<empty>");
2348 if (font_charset
== SYMBOL_CHARSET
)
2351 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2353 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2357 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2358 for (i
= 0; i
< efd
.total
; i
++)
2360 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2362 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2363 font_name
, efd
.lf
[i
].lfFaceName
);
2367 /* DEFAULT_CHARSET should enumerate all available charsets */
2368 memset(&lf
, 0, sizeof(lf
));
2369 lf
.lfCharSet
= DEFAULT_CHARSET
;
2370 lstrcpy(lf
.lfFaceName
, font_name
);
2372 SetLastError(0xdeadbeef);
2373 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2374 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2375 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2376 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2377 ansi_charset
, symbol_charset
, russian_charset
,
2378 *font_name
? font_name
: "<empty>");
2379 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2380 for (i
= 0; i
< efd
.total
; i
++)
2383 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2384 font_name
, efd
.lf
[i
].lfFaceName
);
2388 switch (font_charset
)
2391 ok(ansi_charset
> 0,
2392 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2394 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2395 ok(russian_charset
> 0,
2396 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2398 case SYMBOL_CHARSET
:
2400 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2402 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2403 ok(!russian_charset
,
2404 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2406 case DEFAULT_CHARSET
:
2407 ok(ansi_charset
> 0,
2408 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2409 ok(symbol_charset
> 0,
2410 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2411 ok(russian_charset
> 0,
2412 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2418 ok(ansi_charset
> 0,
2419 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2420 ok(symbol_charset
> 0,
2421 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2422 ok(russian_charset
> 0,
2423 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2426 memset(&lf
, 0, sizeof(lf
));
2427 lf
.lfCharSet
= SYMBOL_CHARSET
;
2428 lstrcpy(lf
.lfFaceName
, font_name
);
2430 SetLastError(0xdeadbeef);
2431 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2432 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2433 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2434 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2435 ansi_charset
, symbol_charset
, russian_charset
,
2436 *font_name
? font_name
: "<empty>");
2437 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2438 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2441 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2442 for (i
= 0; i
< efd
.total
; i
++)
2444 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2446 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2447 font_name
, efd
.lf
[i
].lfFaceName
);
2451 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2452 ok(symbol_charset
> 0,
2453 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2454 ok(!russian_charset
,
2455 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2461 static INT CALLBACK
enum_font_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2463 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2465 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2467 if (efd
->total
< MAX_ENUM_FONTS
)
2468 efd
->lf
[efd
->total
++] = *lf
;
2470 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2475 static INT CALLBACK
enum_fullname_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2477 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
2479 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2481 if (efnd
->total
< MAX_ENUM_FONTS
)
2482 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONT
*)lf
;
2484 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2489 static void test_EnumFontFamiliesEx_default_charset(void)
2491 struct enum_font_data efd
;
2492 LOGFONT gui_font
, enum_font
;
2496 ret
= GetObject(GetStockObject(DEFAULT_GUI_FONT
), sizeof(gui_font
), &gui_font
);
2497 ok(ret
, "GetObject failed.\n");
2504 memset(&enum_font
, 0, sizeof(enum_font
));
2505 lstrcpy(enum_font
.lfFaceName
, gui_font
.lfFaceName
);
2506 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
2507 EnumFontFamiliesEx(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
2510 if (efd
.total
== 0) {
2511 skip("'%s' is not found or not a TrueType font.\n", gui_font
.lfFaceName
);
2514 trace("'%s' has %d charsets.\n", gui_font
.lfFaceName
, efd
.total
);
2516 ok(efd
.lf
[0].lfCharSet
== gui_font
.lfCharSet
|| broken(system_lang_id
== LANG_ARABIC
),
2517 "(%s) got charset %d expected %d\n",
2518 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, gui_font
.lfCharSet
);
2523 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2525 HFONT hfont
, hfont_prev
;
2527 GLYPHMETRICS gm1
, gm2
;
2531 if(!pGetGlyphIndicesA
)
2534 /* negative widths are handled just as positive ones */
2535 lf2
.lfWidth
= -lf
->lfWidth
;
2537 SetLastError(0xdeadbeef);
2538 hfont
= CreateFontIndirectA(lf
);
2539 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2540 check_font("original", lf
, hfont
);
2542 hfont_prev
= SelectObject(hdc
, hfont
);
2544 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2545 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2547 SelectObject(hdc
, hfont_prev
);
2548 DeleteObject(hfont
);
2549 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2553 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2554 memset(&gm1
, 0xab, sizeof(gm1
));
2555 SetLastError(0xdeadbeef);
2556 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2557 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2559 SelectObject(hdc
, hfont_prev
);
2560 DeleteObject(hfont
);
2562 SetLastError(0xdeadbeef);
2563 hfont
= CreateFontIndirectA(&lf2
);
2564 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2565 check_font("negative width", &lf2
, hfont
);
2567 hfont_prev
= SelectObject(hdc
, hfont
);
2569 memset(&gm2
, 0xbb, sizeof(gm2
));
2570 SetLastError(0xdeadbeef);
2571 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2572 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2574 SelectObject(hdc
, hfont_prev
);
2575 DeleteObject(hfont
);
2577 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2578 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2579 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2580 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2581 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2582 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2583 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2584 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2585 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2586 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2587 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2590 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2591 #include "pshpack2.h"
2595 SHORT xAvgCharWidth
;
2596 USHORT usWeightClass
;
2597 USHORT usWidthClass
;
2599 SHORT ySubscriptXSize
;
2600 SHORT ySubscriptYSize
;
2601 SHORT ySubscriptXOffset
;
2602 SHORT ySubscriptYOffset
;
2603 SHORT ySuperscriptXSize
;
2604 SHORT ySuperscriptYSize
;
2605 SHORT ySuperscriptXOffset
;
2606 SHORT ySuperscriptYOffset
;
2607 SHORT yStrikeoutSize
;
2608 SHORT yStrikeoutPosition
;
2611 ULONG ulUnicodeRange1
;
2612 ULONG ulUnicodeRange2
;
2613 ULONG ulUnicodeRange3
;
2614 ULONG ulUnicodeRange4
;
2617 USHORT usFirstCharIndex
;
2618 USHORT usLastCharIndex
;
2619 /* According to the Apple spec, original version didn't have the below fields,
2620 * version numbers were taken from the OpenType spec.
2622 /* version 0 (TrueType 1.5) */
2623 USHORT sTypoAscender
;
2624 USHORT sTypoDescender
;
2625 USHORT sTypoLineGap
;
2627 USHORT usWinDescent
;
2628 /* version 1 (TrueType 1.66) */
2629 ULONG ulCodePageRange1
;
2630 ULONG ulCodePageRange2
;
2631 /* version 2 (OpenType 1.2) */
2634 USHORT usDefaultChar
;
2636 USHORT usMaxContext
;
2638 #include "poppack.h"
2640 #ifdef WORDS_BIGENDIAN
2641 #define GET_BE_WORD(x) (x)
2642 #define GET_BE_DWORD(x) (x)
2644 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2645 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2648 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2649 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2650 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2651 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2652 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2653 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2666 } cmap_encoding_record
;
2674 BYTE glyph_ids
[256];
2684 USHORT search_range
;
2685 USHORT entry_selector
;
2688 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2691 USHORT start_count[seg_countx2 / 2];
2692 USHORT id_delta[seg_countx2 / 2];
2693 USHORT id_range_offset[seg_countx2 / 2];
2703 USHORT id_range_offset
;
2704 } cmap_format_4_seg
;
2706 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2708 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
2709 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
2710 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2711 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2712 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2715 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2718 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2722 for(i
= 0; i
< 256; i
++)
2724 if(cmap
->glyph_ids
[i
] == 0) continue;
2726 if(*first
== 256) *first
= i
;
2728 if(*first
== 256) return FALSE
;
2732 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2734 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2735 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2736 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2737 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2738 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2741 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2744 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2745 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2746 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2750 for(i
= 0; i
< seg_count
; i
++)
2753 cmap_format_4_seg seg
;
2755 get_seg4(cmap
, i
, &seg
);
2756 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2758 if(seg
.id_range_offset
== 0)
2759 index
= (seg
.id_delta
+ code
) & 0xffff;
2762 index
= seg
.id_range_offset
/ 2
2763 + code
- seg
.start_count
2766 /* some fonts have broken last segment */
2767 if ((char *)(glyph_ids
+ index
+ 1) < (char *)ptr
+ limit
)
2768 index
= GET_BE_WORD(glyph_ids
[index
]);
2771 trace("segment %04x/%04x index %04x points to nowhere\n",
2772 seg
.start_count
, seg
.end_count
, index
);
2775 if(index
) index
+= seg
.id_delta
;
2777 if(*first
== 0x10000)
2778 *last
= *first
= code
;
2784 if(*first
== 0x10000) return FALSE
;
2788 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2791 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2793 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2795 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2796 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2809 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2812 cmap_header
*header
;
2817 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2818 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2819 if(size
== GDI_ERROR
) return FALSE
;
2821 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2822 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2823 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2824 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2826 cmap
= get_cmap(header
, 3, 1);
2828 *cmap_type
= cmap_ms_unicode
;
2831 cmap
= get_cmap(header
, 3, 0);
2832 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2836 *cmap_type
= cmap_none
;
2840 format
= GET_BE_WORD(*(WORD
*)cmap
);
2844 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2847 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2850 trace("unhandled cmap format %d\n", format
);
2855 HeapFree(GetProcessHeap(), 0, header
);
2859 #define TT_PLATFORM_MICROSOFT 3
2860 #define TT_MS_ID_SYMBOL_CS 0
2861 #define TT_MS_ID_UNICODE_CS 1
2862 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2863 #define TT_NAME_ID_FONT_FAMILY 1
2864 #define TT_NAME_ID_FONT_SUBFAMILY 2
2865 #define TT_NAME_ID_UNIQUE_ID 3
2866 #define TT_NAME_ID_FULL_NAME 4
2868 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
2870 struct sfnt_name_header
2873 USHORT number_of_record
;
2874 USHORT storage_offset
;
2886 LONG size
, offset
, length
;
2892 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
2893 ok(size
!= GDI_ERROR
, "no name table found\n");
2894 if(size
== GDI_ERROR
) return FALSE
;
2896 data
= HeapAlloc(GetProcessHeap(), 0, size
);
2897 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
2898 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2900 header
= (void *)data
;
2901 header
->format
= GET_BE_WORD(header
->format
);
2902 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
2903 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
2904 if (header
->format
!= 0)
2906 trace("got format %u\n", header
->format
);
2909 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
2911 trace("number records out of range: %d\n", header
->number_of_record
);
2914 if (header
->storage_offset
>= size
)
2916 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
2920 entry
= (void *)&header
[1];
2921 for (i
= 0; i
< header
->number_of_record
; i
++)
2923 if (GET_BE_WORD(entry
[i
].platform_id
) != TT_PLATFORM_MICROSOFT
||
2924 (GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_UNICODE_CS
&& GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_SYMBOL_CS
) ||
2925 GET_BE_WORD(entry
[i
].language_id
) != language_id
||
2926 GET_BE_WORD(entry
[i
].name_id
) != name_id
)
2931 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[i
].offset
);
2932 length
= GET_BE_WORD(entry
[i
].length
);
2933 if (offset
+ length
> size
)
2935 trace("entry %d is out of range\n", i
);
2938 if (length
>= out_size
)
2940 trace("buffer too small for entry %d\n", i
);
2944 name
= (WCHAR
*)(data
+ offset
);
2945 for (c
= 0; c
< length
/ 2; c
++)
2946 out_buf
[c
] = GET_BE_WORD(name
[c
]);
2954 HeapFree(GetProcessHeap(), 0, data
);
2958 static void test_text_metrics(const LOGFONT
*lf
, const NEWTEXTMETRIC
*ntm
)
2961 HFONT hfont
, hfont_old
;
2965 const char *font_name
= lf
->lfFaceName
;
2966 DWORD cmap_first
= 0, cmap_last
= 0;
2967 UINT ascent
, descent
, cell_height
;
2968 cmap_type cmap_type
;
2969 BOOL sys_lang_non_english
;
2971 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
2974 SetLastError(0xdeadbeef);
2975 hfont
= CreateFontIndirectA(lf
);
2976 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2978 hfont_old
= SelectObject(hdc
, hfont
);
2980 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2981 if (size
== GDI_ERROR
)
2983 trace("OS/2 chunk was not found\n");
2986 if (size
> sizeof(tt_os2
))
2988 trace("got too large OS/2 chunk of size %u\n", size
);
2989 size
= sizeof(tt_os2
);
2992 memset(&tt_os2
, 0, sizeof(tt_os2
));
2993 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2994 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2996 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
2997 descent
= GET_BE_WORD(tt_os2
.usWinDescent
);
2998 cell_height
= ascent
+ descent
;
2999 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3000 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3002 SetLastError(0xdeadbeef);
3003 ret
= GetTextMetricsA(hdc
, &tmA
);
3004 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3006 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3008 skip("Unable to retrieve first and last glyphs from cmap\n");
3012 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3013 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3014 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3018 version
= GET_BE_WORD(tt_os2
.version
);
3020 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3021 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3022 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3023 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3025 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3026 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3027 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3029 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3034 case 1257: /* Baltic */
3035 expect_last_W
= 0xf8fd;
3038 expect_last_W
= 0xf0ff;
3040 expect_break_W
= 0x20;
3041 expect_default_W
= expect_break_W
- 1;
3042 expect_first_A
= 0x1e;
3043 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3047 expect_first_W
= cmap_first
;
3048 expect_last_W
= min(cmap_last
, os2_last_char
);
3049 if(os2_first_char
<= 1)
3050 expect_break_W
= os2_first_char
+ 2;
3051 else if(os2_first_char
> 0xff)
3052 expect_break_W
= 0x20;
3054 expect_break_W
= os2_first_char
;
3055 expect_default_W
= expect_break_W
- 1;
3056 expect_first_A
= expect_default_W
- 1;
3057 expect_last_A
= min(expect_last_W
, 0xff);
3059 expect_break_A
= expect_break_W
;
3060 expect_default_A
= expect_default_W
;
3062 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3063 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3064 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
3065 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3066 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3068 ok(tmA
.tmFirstChar
== expect_first_A
||
3069 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3070 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3071 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3072 ok(tmA
.tmLastChar
== expect_last_A
||
3073 tmA
.tmLastChar
== 0xff /* win9x */,
3074 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3076 skip("tmLastChar is DBCS lead byte\n");
3077 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3078 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3079 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3080 "A: tmDefaultChar for %s got %02x expected %02x\n",
3081 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3084 SetLastError(0xdeadbeef);
3085 ret
= GetTextMetricsW(hdc
, &tmW
);
3086 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3087 "GetTextMetricsW error %u\n", GetLastError());
3090 /* Wine uses the os2 first char */
3091 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3092 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3093 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3095 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3096 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3098 /* Wine uses the os2 last char */
3099 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3100 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3101 font_name
, tmW
.tmLastChar
, expect_last_W
);
3103 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3104 font_name
, tmW
.tmLastChar
, expect_last_W
);
3105 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3106 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3107 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3108 "W: tmDefaultChar for %s got %02x expected %02x\n",
3109 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3111 /* Test the aspect ratio while we have tmW */
3112 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3113 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3114 tmW
.tmDigitizedAspectX
, ret
);
3115 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3116 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3117 tmW
.tmDigitizedAspectX
, ret
);
3121 /* test FF_ values */
3122 switch(tt_os2
.panose
.bFamilyType
)
3126 case PAN_FAMILY_TEXT_DISPLAY
:
3127 case PAN_FAMILY_PICTORIAL
:
3129 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3130 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3132 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3135 switch(tt_os2
.panose
.bSerifStyle
)
3140 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3143 case PAN_SERIF_COVE
:
3144 case PAN_SERIF_OBTUSE_COVE
:
3145 case PAN_SERIF_SQUARE_COVE
:
3146 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3147 case PAN_SERIF_SQUARE
:
3148 case PAN_SERIF_THIN
:
3149 case PAN_SERIF_BONE
:
3150 case PAN_SERIF_EXAGGERATED
:
3151 case PAN_SERIF_TRIANGLE
:
3152 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3155 case PAN_SERIF_NORMAL_SANS
:
3156 case PAN_SERIF_OBTUSE_SANS
:
3157 case PAN_SERIF_PERP_SANS
:
3158 case PAN_SERIF_FLARED
:
3159 case PAN_SERIF_ROUNDED
:
3160 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3165 case PAN_FAMILY_SCRIPT
:
3166 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3169 case PAN_FAMILY_DECORATIVE
:
3170 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3174 test_negative_width(hdc
, lf
);
3177 SelectObject(hdc
, hfont_old
);
3178 DeleteObject(hfont
);
3183 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
3185 INT
*enumed
= (INT
*)lParam
;
3187 if (type
== TRUETYPE_FONTTYPE
)
3190 test_text_metrics(lf
, (const NEWTEXTMETRIC
*)ntm
);
3195 static void test_GetTextMetrics(void)
3201 /* Report only once */
3202 if(!pGetGlyphIndicesA
)
3203 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3207 memset(&lf
, 0, sizeof(lf
));
3208 lf
.lfCharSet
= DEFAULT_CHARSET
;
3210 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
3211 trace("Tested metrics of %d truetype fonts\n", enumed
);
3216 static void test_nonexistent_font(void)
3224 { "Times New Roman Baltic", 186 },
3225 { "Times New Roman CE", 238 },
3226 { "Times New Roman CYR", 204 },
3227 { "Times New Roman Greek", 161 },
3228 { "Times New Roman TUR", 162 }
3234 INT cs
, expected_cs
, i
;
3235 char buf
[LF_FACESIZE
];
3237 if (!is_truetype_font_installed("Arial") ||
3238 !is_truetype_font_installed("Times New Roman"))
3240 skip("Arial or Times New Roman not installed\n");
3244 expected_cs
= GetACP();
3245 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3247 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3250 expected_cs
= csi
.ciCharset
;
3251 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3255 memset(&lf
, 0, sizeof(lf
));
3257 lf
.lfWeight
= FW_REGULAR
;
3258 lf
.lfCharSet
= ANSI_CHARSET
;
3259 lf
.lfPitchAndFamily
= FF_SWISS
;
3260 strcpy(lf
.lfFaceName
, "Nonexistent font");
3261 hfont
= CreateFontIndirectA(&lf
);
3262 hfont
= SelectObject(hdc
, hfont
);
3263 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3264 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
3265 cs
= GetTextCharset(hdc
);
3266 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3267 DeleteObject(SelectObject(hdc
, hfont
));
3269 memset(&lf
, 0, sizeof(lf
));
3271 lf
.lfWeight
= FW_DONTCARE
;
3272 strcpy(lf
.lfFaceName
, "Nonexistent font");
3273 hfont
= CreateFontIndirectA(&lf
);
3274 hfont
= SelectObject(hdc
, hfont
);
3275 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3276 todo_wine
/* Wine uses Arial for all substitutions */
3277 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
3278 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
3279 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3281 cs
= GetTextCharset(hdc
);
3282 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
3283 DeleteObject(SelectObject(hdc
, hfont
));
3285 memset(&lf
, 0, sizeof(lf
));
3287 lf
.lfWeight
= FW_REGULAR
;
3288 strcpy(lf
.lfFaceName
, "Nonexistent font");
3289 hfont
= CreateFontIndirectA(&lf
);
3290 hfont
= SelectObject(hdc
, hfont
);
3291 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3292 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3293 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
3294 cs
= GetTextCharset(hdc
);
3295 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3296 DeleteObject(SelectObject(hdc
, hfont
));
3298 memset(&lf
, 0, sizeof(lf
));
3300 lf
.lfWeight
= FW_DONTCARE
;
3301 strcpy(lf
.lfFaceName
, "Times New Roman");
3302 hfont
= CreateFontIndirectA(&lf
);
3303 hfont
= SelectObject(hdc
, hfont
);
3304 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3305 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
3306 cs
= GetTextCharset(hdc
);
3307 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3308 DeleteObject(SelectObject(hdc
, hfont
));
3310 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
3312 memset(&lf
, 0, sizeof(lf
));
3314 lf
.lfWeight
= FW_REGULAR
;
3315 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3316 hfont
= CreateFontIndirectA(&lf
);
3317 hfont
= SelectObject(hdc
, hfont
);
3318 cs
= GetTextCharset(hdc
);
3319 if (font_subst
[i
].charset
== expected_cs
)
3321 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3322 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3323 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
3327 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
3328 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3329 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3330 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
3332 DeleteObject(SelectObject(hdc
, hfont
));
3334 memset(&lf
, 0, sizeof(lf
));
3336 lf
.lfWeight
= FW_DONTCARE
;
3337 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3338 hfont
= CreateFontIndirectA(&lf
);
3339 hfont
= SelectObject(hdc
, hfont
);
3340 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3341 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
3342 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
3343 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
3344 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3345 "got %s for font %s\n", buf
, font_subst
[i
].name
);
3346 cs
= GetTextCharset(hdc
);
3347 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3348 DeleteObject(SelectObject(hdc
, hfont
));
3354 static void test_GdiRealizationInfo(void)
3359 HFONT hfont
, hfont_old
;
3362 if(!pGdiRealizationInfo
)
3364 win_skip("GdiRealizationInfo not available\n");
3370 memset(info
, 0xcc, sizeof(info
));
3371 r
= pGdiRealizationInfo(hdc
, info
);
3372 ok(r
!= 0, "ret 0\n");
3373 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
3374 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3376 if (!is_truetype_font_installed("Arial"))
3378 skip("skipping GdiRealizationInfo with truetype font\n");
3382 memset(&lf
, 0, sizeof(lf
));
3383 strcpy(lf
.lfFaceName
, "Arial");
3385 lf
.lfWeight
= FW_NORMAL
;
3386 hfont
= CreateFontIndirectA(&lf
);
3387 hfont_old
= SelectObject(hdc
, hfont
);
3389 memset(info
, 0xcc, sizeof(info
));
3390 r
= pGdiRealizationInfo(hdc
, info
);
3391 ok(r
!= 0, "ret 0\n");
3392 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
3393 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3395 DeleteObject(SelectObject(hdc
, hfont_old
));
3401 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3402 the nul in the count of characters copied when the face name buffer is not
3403 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3404 always includes it. */
3405 static void test_GetTextFace(void)
3407 static const char faceA
[] = "Tahoma";
3408 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
3411 char bufA
[LF_FACESIZE
];
3412 WCHAR bufW
[LF_FACESIZE
];
3417 if(!is_font_installed("Tahoma"))
3419 skip("Tahoma is not installed so skipping this test\n");
3424 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
3425 f
= CreateFontIndirectA(&fA
);
3426 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
3429 g
= SelectObject(dc
, f
);
3430 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
3431 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
3432 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
3434 /* Play with the count arg. */
3436 n
= GetTextFaceA(dc
, 0, bufA
);
3437 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3438 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3441 n
= GetTextFaceA(dc
, 1, bufA
);
3442 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3443 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3445 bufA
[0] = 'x'; bufA
[1] = 'y';
3446 n
= GetTextFaceA(dc
, 2, bufA
);
3447 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
3448 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
3450 n
= GetTextFaceA(dc
, 0, NULL
);
3451 ok(n
== sizeof faceA
||
3452 broken(n
== 0), /* win98, winMe */
3453 "GetTextFaceA returned %d\n", n
);
3455 DeleteObject(SelectObject(dc
, g
));
3456 ReleaseDC(NULL
, dc
);
3459 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3460 SetLastError(0xdeadbeef);
3461 f
= CreateFontIndirectW(&fW
);
3462 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3464 win_skip("CreateFontIndirectW is not implemented\n");
3467 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3470 g
= SelectObject(dc
, f
);
3471 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3472 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3473 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3475 /* Play with the count arg. */
3477 n
= GetTextFaceW(dc
, 0, bufW
);
3478 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3479 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3482 n
= GetTextFaceW(dc
, 1, bufW
);
3483 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3484 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3486 bufW
[0] = 'x'; bufW
[1] = 'y';
3487 n
= GetTextFaceW(dc
, 2, bufW
);
3488 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
3489 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
3491 n
= GetTextFaceW(dc
, 0, NULL
);
3492 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3494 DeleteObject(SelectObject(dc
, g
));
3495 ReleaseDC(NULL
, dc
);
3498 static void test_orientation(void)
3500 static const char test_str
[11] = "Test String";
3503 HFONT hfont
, old_hfont
;
3506 if (!is_truetype_font_installed("Arial"))
3508 skip("Arial is not installed\n");
3512 hdc
= CreateCompatibleDC(0);
3513 memset(&lf
, 0, sizeof(lf
));
3514 lstrcpyA(lf
.lfFaceName
, "Arial");
3516 lf
.lfOrientation
= lf
.lfEscapement
= 900;
3517 hfont
= create_font("orientation", &lf
);
3518 old_hfont
= SelectObject(hdc
, hfont
);
3519 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
3520 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
3521 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
3522 SelectObject(hdc
, old_hfont
);
3523 DeleteObject(hfont
);
3527 static void test_oemcharset(void)
3531 HFONT hfont
, old_hfont
;
3534 hdc
= CreateCompatibleDC(0);
3535 ZeroMemory(&lf
, sizeof(lf
));
3537 lf
.lfCharSet
= OEM_CHARSET
;
3538 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
3539 lstrcpyA(lf
.lfFaceName
, "Terminal");
3540 hfont
= CreateFontIndirectA(&lf
);
3541 old_hfont
= SelectObject(hdc
, hfont
);
3542 charset
= GetTextCharset(hdc
);
3544 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
3545 hfont
= SelectObject(hdc
, old_hfont
);
3546 GetObjectA(hfont
, sizeof(clf
), &clf
);
3547 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
3548 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
3549 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
3550 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
3551 DeleteObject(hfont
);
3555 static void test_GetGlyphOutline(void)
3558 GLYPHMETRICS gm
, gm2
;
3560 HFONT hfont
, old_hfont
;
3569 {ANSI_CHARSET
, 0x30, 0x30},
3570 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
3571 {HANGEUL_CHARSET
, 0x8141, 0xac02},
3572 {JOHAB_CHARSET
, 0x8446, 0x3135},
3573 {GB2312_CHARSET
, 0x8141, 0x4e04},
3574 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
3578 if (!is_truetype_font_installed("Tahoma"))
3580 skip("Tahoma is not installed\n");
3584 hdc
= CreateCompatibleDC(0);
3585 memset(&lf
, 0, sizeof(lf
));
3587 lstrcpyA(lf
.lfFaceName
, "Tahoma");
3588 SetLastError(0xdeadbeef);
3589 hfont
= CreateFontIndirectA(&lf
);
3590 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
3591 old_hfont
= SelectObject(hdc
, hfont
);
3593 memset(&gm
, 0, sizeof(gm
));
3594 SetLastError(0xdeadbeef);
3595 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3596 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3598 memset(&gm
, 0, sizeof(gm
));
3599 SetLastError(0xdeadbeef);
3600 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3601 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
3602 ok(GetLastError() == 0xdeadbeef ||
3603 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
3604 "expected 0xdeadbeef, got %u\n", GetLastError());
3606 memset(&gm
, 0, sizeof(gm
));
3607 SetLastError(0xdeadbeef);
3608 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3609 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3610 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
3612 memset(&gm
, 0, sizeof(gm
));
3613 SetLastError(0xdeadbeef);
3614 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3615 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3617 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
3618 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3621 /* test for needed buffer size request on space char */
3622 memset(&gm
, 0, sizeof(gm
));
3623 SetLastError(0xdeadbeef);
3624 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3625 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3626 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3628 /* requesting buffer size for space char + error */
3629 memset(&gm
, 0, sizeof(gm
));
3630 SetLastError(0xdeadbeef);
3631 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3632 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3634 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3635 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3638 SelectObject(hdc
, old_hfont
);
3639 DeleteObject(hfont
);
3641 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
3643 lf
.lfFaceName
[0] = '\0';
3644 lf
.lfCharSet
= c
[i
].cs
;
3645 lf
.lfPitchAndFamily
= 0;
3646 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
3648 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
3652 old_hfont
= SelectObject(hdc
, hfont
);
3654 /* expected to ignore superfluous bytes (sigle-byte character) */
3655 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3656 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3657 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3659 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3660 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3661 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3663 /* expected to ignore superfluous bytes (double-byte character) */
3664 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3665 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3666 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3667 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3669 /* expected to match wide-char version results */
3670 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3671 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3673 hfont
= SelectObject(hdc
, old_hfont
);
3674 DeleteObject(hfont
);
3680 /* bug #9995: there is a limit to the character width that can be specified */
3681 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3687 int ave_width
, height
, width
, ratio
, scale
;
3689 if (!is_truetype_font_installed( fontname
)) {
3690 skip("%s is not installed\n", fontname
);
3693 hdc
= CreateCompatibleDC(0);
3694 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3695 /* select width = 0 */
3696 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3697 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3698 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3700 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3701 of
= SelectObject( hdc
, hf
);
3702 ret
= GetTextMetricsA( hdc
, &tm
);
3703 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3704 height
= tm
.tmHeight
;
3705 ave_width
= tm
.tmAveCharWidth
;
3706 SelectObject( hdc
, of
);
3709 trace("height %d, ave width %d\n", height
, ave_width
);
3711 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3713 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3714 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3715 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3716 ok(hf
!= 0, "CreateFont failed\n");
3717 of
= SelectObject(hdc
, hf
);
3718 ret
= GetTextMetrics(hdc
, &tm
);
3719 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3720 SelectObject(hdc
, of
);
3723 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3729 ratio
= width
/ height
;
3730 scale
= width
/ ave_width
;
3732 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3733 width
, height
, ratio
, width
, ave_width
, scale
);
3735 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3738 static void test_CreateFontIndirect(void)
3740 LOGFONTA lf
, getobj_lf
;
3743 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3745 memset(&lf
, 0, sizeof(lf
));
3746 lf
.lfCharSet
= ANSI_CHARSET
;
3747 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3750 lf
.lfQuality
= DEFAULT_QUALITY
;
3751 lf
.lfItalic
= FALSE
;
3752 lf
.lfWeight
= FW_DONTCARE
;
3754 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3756 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3757 hfont
= CreateFontIndirectA(&lf
);
3758 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3759 SetLastError(0xdeadbeef);
3760 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3761 ok(ret
, "GetObject failed: %d\n", GetLastError());
3762 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3763 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3764 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3765 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3766 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3767 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3768 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3769 DeleteObject(hfont
);
3773 static void test_CreateFontIndirectEx(void)
3775 ENUMLOGFONTEXDVA lfex
;
3778 if (!pCreateFontIndirectExA
)
3780 win_skip("CreateFontIndirectExA is not available\n");
3784 if (!is_truetype_font_installed("Arial"))
3786 skip("Arial is not installed\n");
3790 SetLastError(0xdeadbeef);
3791 hfont
= pCreateFontIndirectExA(NULL
);
3792 ok(hfont
== NULL
, "got %p\n", hfont
);
3793 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3795 memset(&lfex
, 0, sizeof(lfex
));
3796 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3797 hfont
= pCreateFontIndirectExA(&lfex
);
3798 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3800 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3801 DeleteObject(hfont
);
3804 static void free_font(void *font
)
3806 UnmapViewOfFile(font
);
3809 static void *load_font(const char *font_name
, DWORD
*font_size
)
3811 char file_name
[MAX_PATH
];
3812 HANDLE file
, mapping
;
3815 if (!GetWindowsDirectory(file_name
, sizeof(file_name
))) return NULL
;
3816 strcat(file_name
, "\\fonts\\");
3817 strcat(file_name
, font_name
);
3819 file
= CreateFile(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3820 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
3822 *font_size
= GetFileSize(file
, NULL
);
3824 mapping
= CreateFileMapping(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
3831 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
3834 CloseHandle(mapping
);
3838 static void test_AddFontMemResource(void)
3841 DWORD font_size
, num_fonts
;
3845 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
3847 win_skip("AddFontMemResourceEx is not available on this platform\n");
3851 font
= load_font("sserife.fon", &font_size
);
3854 skip("Unable to locate and load font sserife.fon\n");
3858 SetLastError(0xdeadbeef);
3859 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
3860 ok(!ret
, "AddFontMemResourceEx should fail\n");
3861 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3862 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3865 SetLastError(0xdeadbeef);
3866 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
3867 ok(!ret
, "AddFontMemResourceEx should fail\n");
3868 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3869 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3872 SetLastError(0xdeadbeef);
3873 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
3874 ok(!ret
, "AddFontMemResourceEx should fail\n");
3875 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3876 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3879 SetLastError(0xdeadbeef);
3880 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
3881 ok(!ret
, "AddFontMemResourceEx should fail\n");
3882 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3883 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3886 SetLastError(0xdeadbeef);
3887 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
3888 ok(!ret
, "AddFontMemResourceEx should fail\n");
3889 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3890 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3893 SetLastError(0xdeadbeef);
3894 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
3895 ok(!ret
, "AddFontMemResourceEx should fail\n");
3896 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3897 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3900 num_fonts
= 0xdeadbeef;
3901 SetLastError(0xdeadbeef);
3902 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
3903 ok(!ret
, "AddFontMemResourceEx should fail\n");
3904 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3905 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3907 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3909 if (0) /* hangs under windows 2000 */
3911 num_fonts
= 0xdeadbeef;
3912 SetLastError(0xdeadbeef);
3913 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
3914 ok(!ret
, "AddFontMemResourceEx should fail\n");
3915 ok(GetLastError() == 0xdeadbeef,
3916 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3918 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
3921 num_fonts
= 0xdeadbeef;
3922 SetLastError(0xdeadbeef);
3923 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
3924 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
3925 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
3926 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
3930 SetLastError(0xdeadbeef);
3931 bRet
= pRemoveFontMemResourceEx(ret
);
3932 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
3934 /* test invalid pointer to number of loaded fonts */
3935 font
= load_font("sserife.fon", &font_size
);
3936 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
3938 SetLastError(0xdeadbeef);
3939 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
3940 ok(!ret
, "AddFontMemResourceEx should fail\n");
3941 ok(GetLastError() == 0xdeadbeef,
3942 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
3945 SetLastError(0xdeadbeef);
3946 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
3947 ok(!ret
, "AddFontMemResourceEx should fail\n");
3948 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
3949 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
3955 static INT CALLBACK
enum_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3959 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3961 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3963 lf
= (LOGFONT
*)lparam
;
3968 static INT CALLBACK
enum_all_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3973 if (type
!= TRUETYPE_FONTTYPE
) return 1;
3975 lf
= (LOGFONT
*)lparam
;
3976 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
3979 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
3986 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
3991 static void test_EnumFonts(void)
3997 if (!is_truetype_font_installed("Arial"))
3999 skip("Arial is not installed\n");
4003 /* Windows uses localized font face names, so Arial Bold won't be found */
4004 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
4006 skip("User locale is not English, skipping the test\n");
4010 hdc
= CreateCompatibleDC(0);
4012 /* check that the enumproc's retval is returned */
4013 ret
= EnumFontFamilies(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
4014 ok(ret
== 0xcafe, "got %08x\n", ret
);
4016 ret
= EnumFontFamilies(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
4017 ok(!ret
, "font Arial is not enumerated\n");
4018 ret
= strcmp(lf
.lfFaceName
, "Arial");
4019 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4020 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4022 lstrcpy(lf
.lfFaceName
, "Arial");
4023 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4024 ok(!ret
, "font Arial is not enumerated\n");
4025 ret
= strcmp(lf
.lfFaceName
, "Arial");
4026 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4027 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4029 ret
= EnumFontFamilies(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4030 ok(!ret
, "font Arial Bold is not enumerated\n");
4031 ret
= strcmp(lf
.lfFaceName
, "Arial");
4032 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4033 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4035 lstrcpy(lf
.lfFaceName
, "Arial Bold");
4036 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4037 ok(ret
, "font Arial Bold should not be enumerated\n");
4039 ret
= EnumFontFamilies(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
4040 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
4041 ret
= strcmp(lf
.lfFaceName
, "Arial");
4042 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4043 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4045 lstrcpy(lf
.lfFaceName
, "Arial Bold Italic");
4046 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4047 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
4049 ret
= EnumFontFamilies(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4050 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4052 lstrcpy(lf
.lfFaceName
, "Arial Italic Bold");
4053 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4054 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4059 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
4061 const ENUMLOGFONT
*elf
= (const ENUMLOGFONT
*)lf
;
4062 const char *fullname
= (const char *)lParam
;
4064 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
4069 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
4074 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
4081 static void test_fullname(void)
4083 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4084 WCHAR bufW
[LF_FULLFACESIZE
];
4085 char bufA
[LF_FULLFACESIZE
];
4092 hdc
= CreateCompatibleDC(0);
4093 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4095 memset(&lf
, 0, sizeof(lf
));
4096 lf
.lfCharSet
= ANSI_CHARSET
;
4097 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4100 lf
.lfQuality
= DEFAULT_QUALITY
;
4101 lf
.lfItalic
= FALSE
;
4102 lf
.lfWeight
= FW_DONTCARE
;
4104 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
4106 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
4108 skip("%s is not installed\n", TestName
[i
]);
4112 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4113 hfont
= CreateFontIndirectA(&lf
);
4114 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4116 of
= SelectObject(hdc
, hfont
);
4119 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4120 ok(ret
, "face full name could not be read\n");
4121 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
4122 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
4123 SelectObject(hdc
, of
);
4124 DeleteObject(hfont
);
4129 static WCHAR
*prepend_at(WCHAR
*family
)
4134 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
4139 static void test_fullname2_helper(const char *Family
)
4141 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
4142 struct enum_fullname_data efnd
;
4149 DWORD otm_size
, ret
, buf_size
;
4150 OUTLINETEXTMETRICA
*otm
;
4151 BOOL want_vertical
, get_vertical
;
4152 want_vertical
= ( Family
[0] == '@' );
4154 hdc
= CreateCompatibleDC(0);
4155 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4157 memset(&lf
, 0, sizeof(lf
));
4158 lf
.lfCharSet
= DEFAULT_CHARSET
;
4159 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4162 lf
.lfQuality
= DEFAULT_QUALITY
;
4163 lf
.lfItalic
= FALSE
;
4164 lf
.lfWeight
= FW_DONTCARE
;
4165 lstrcpy(lf
.lfFaceName
, Family
);
4167 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4168 if (efnd
.total
== 0)
4169 skip("%s is not installed\n", lf
.lfFaceName
);
4171 for (i
= 0; i
< efnd
.total
; i
++)
4173 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
4174 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
4175 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
4177 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family
, FamilyName
, FaceName
, StyleName
);
4179 get_vertical
= ( FamilyName
[0] == '@' );
4180 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
4182 lstrcpyA(lf
.lfFaceName
, FaceName
);
4183 hfont
= CreateFontIndirectA(&lf
);
4184 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4186 of
= SelectObject(hdc
, hfont
);
4187 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
4188 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
4189 if (buf_size
== GDI_ERROR
) continue;
4191 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4192 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4194 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
4195 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
4196 memset(otm
, 0, otm_size
);
4197 ret
= GetOutlineTextMetrics(hdc
, otm_size
, otm
);
4198 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
4199 if (ret
== 0) continue;
4203 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4206 trace("no localized FONT_FAMILY found.\n");
4207 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4209 ok(ret
, "FAMILY (family name) could not be read\n");
4210 if (want_vertical
) bufW
= prepend_at(bufW
);
4211 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4212 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
4213 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
4214 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
4218 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
4221 trace("no localized FULL_NAME found.\n");
4222 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4224 ok(ret
, "FULL_NAME (face name) could not be read\n");
4225 if (want_vertical
) bufW
= prepend_at(bufW
);
4226 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4227 ok(!lstrcmpA(FaceName
, bufA
), "font face names don't match: returned %s, expect %s\n", FaceName
, bufA
);
4228 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
4229 ok(!lstrcmpA(FaceName
, otmStr
), "FaceName %s doesn't match otmpFaceName %s\n", FaceName
, otmStr
);
4233 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4236 trace("no localized FONT_SUBFAMILY found.\n");
4237 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4239 ok(ret
, "SUBFAMILY (style name) could not be read\n");
4240 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4241 ok(!lstrcmpA(StyleName
, bufA
), "style names don't match: returned %s, expect %s\n", StyleName
, bufA
);
4242 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
4243 ok(!lstrcmpA(StyleName
, otmStr
), "StyleName %s doesn't match otmpStyleName %s\n", StyleName
, otmStr
);
4247 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
4250 trace("no localized UNIQUE_ID found.\n");
4251 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4253 ok(ret
, "UNIQUE_ID (full name) could not be read\n");
4254 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4255 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
4256 ok(!lstrcmpA(otmStr
, bufA
), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr
, bufA
);
4258 SelectObject(hdc
, of
);
4259 DeleteObject(hfont
);
4261 HeapFree(GetProcessHeap(), 0, otm
);
4262 HeapFree(GetProcessHeap(), 0, bufW
);
4263 HeapFree(GetProcessHeap(), 0, bufA
);
4268 static void test_fullname2(void)
4270 test_fullname2_helper("Arial");
4271 test_fullname2_helper("DejaVu Sans");
4272 test_fullname2_helper("Lucida Sans");
4273 test_fullname2_helper("Tahoma");
4274 test_fullname2_helper("Webdings");
4275 test_fullname2_helper("Wingdings");
4276 test_fullname2_helper("SimSun");
4277 test_fullname2_helper("NSimSun");
4278 test_fullname2_helper("MingLiu");
4279 test_fullname2_helper("PMingLiu");
4280 test_fullname2_helper("WenQuanYi Micro Hei");
4281 test_fullname2_helper("MS UI Gothic");
4282 test_fullname2_helper("Ume UI Gothic");
4283 test_fullname2_helper("MS Gothic");
4284 test_fullname2_helper("Ume Gothic");
4285 test_fullname2_helper("MS PGothic");
4286 test_fullname2_helper("Ume P Gothic");
4287 test_fullname2_helper("Gulim");
4288 test_fullname2_helper("Batang");
4289 test_fullname2_helper("UnBatang");
4290 test_fullname2_helper("UnDotum");
4291 test_fullname2_helper("@SimSun");
4292 test_fullname2_helper("@NSimSun");
4293 test_fullname2_helper("@MingLiu");
4294 test_fullname2_helper("@PMingLiu");
4295 test_fullname2_helper("@WenQuanYi Micro Hei");
4296 test_fullname2_helper("@MS UI Gothic");
4297 test_fullname2_helper("@Ume UI Gothic");
4298 test_fullname2_helper("@MS Gothic");
4299 test_fullname2_helper("@Ume Gothic");
4300 test_fullname2_helper("@MS PGothic");
4301 test_fullname2_helper("@Ume P Gothic");
4302 test_fullname2_helper("@Gulim");
4303 test_fullname2_helper("@Batang");
4304 test_fullname2_helper("@UnBatang");
4305 test_fullname2_helper("@UnDotum");
4309 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
4311 char tmp_path
[MAX_PATH
];
4318 SetLastError(0xdeadbeef);
4319 rsrc
= FindResource(GetModuleHandle(0), fontname
, RT_RCDATA
);
4320 ok(rsrc
!= 0, "FindResource error %d\n", GetLastError());
4321 if (!rsrc
) return FALSE
;
4322 SetLastError(0xdeadbeef);
4323 rsrc_data
= LockResource(LoadResource(GetModuleHandle(0), rsrc
));
4324 ok(rsrc_data
!= 0, "LockResource error %d\n", GetLastError());
4325 if (!rsrc_data
) return FALSE
;
4326 SetLastError(0xdeadbeef);
4327 rsrc_size
= SizeofResource(GetModuleHandle(0), rsrc
);
4328 ok(rsrc_size
!= 0, "SizeofResource error %d\n", GetLastError());
4329 if (!rsrc_size
) return FALSE
;
4331 SetLastError(0xdeadbeef);
4332 ret
= GetTempPath(MAX_PATH
, tmp_path
);
4333 ok(ret
, "GetTempPath() error %d\n", GetLastError());
4334 SetLastError(0xdeadbeef);
4335 ret
= GetTempFileName(tmp_path
, "ttf", 0, tmp_name
);
4336 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
4338 SetLastError(0xdeadbeef);
4339 hfile
= CreateFile(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
4340 ok(hfile
!= INVALID_HANDLE_VALUE
, "CreateFile() error %d\n", GetLastError());
4341 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
4343 SetLastError(0xdeadbeef);
4344 ret
= WriteFile(hfile
, rsrc_data
, rsrc_size
, &rsrc_size
, NULL
);
4345 ok(ret
, "WriteFile() error %d\n", GetLastError());
4351 static void test_GetGlyphOutline_empty_contour(void)
4355 HFONT hfont
, hfont_prev
;
4356 TTPOLYGONHEADER
*header
;
4361 memset(&lf
, 0, sizeof(lf
));
4363 lstrcpyA(lf
.lfFaceName
, "wine_test");
4365 hfont
= CreateFontIndirectA(&lf
);
4366 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4370 hfont_prev
= SelectObject(hdc
, hfont
);
4371 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
4373 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4374 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
4376 header
= (TTPOLYGONHEADER
*)buf
;
4377 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
4378 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
4379 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
4380 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
4381 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
4382 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
4383 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
4384 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
4386 SelectObject(hdc
, hfont_prev
);
4387 DeleteObject(hfont
);
4388 ReleaseDC(NULL
, hdc
);
4391 static void test_CreateScalableFontResource(void)
4393 char ttf_name
[MAX_PATH
];
4394 char tmp_path
[MAX_PATH
];
4395 char fot_name
[MAX_PATH
];
4399 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
4401 win_skip("AddFontResourceExA is not available on this platform\n");
4405 if (!write_ttf_file("wine_test.ttf", ttf_name
))
4407 skip("Failed to create ttf file for testing\n");
4411 trace("created %s\n", ttf_name
);
4413 ret
= is_truetype_font_installed("wine_test");
4414 ok(!ret
, "font wine_test should not be enumerated\n");
4416 ret
= GetTempPath(MAX_PATH
, tmp_path
);
4417 ok(ret
, "GetTempPath() error %d\n", GetLastError());
4418 ret
= GetTempFileName(tmp_path
, "fot", 0, fot_name
);
4419 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
4421 ret
= GetFileAttributes(fot_name
);
4422 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
4424 SetLastError(0xdeadbeef);
4425 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
4426 ok(!ret
, "CreateScalableFontResource() should fail\n");
4427 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4429 SetLastError(0xdeadbeef);
4430 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, "");
4431 ok(!ret
, "CreateScalableFontResource() should fail\n");
4432 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4434 file_part
= strrchr(ttf_name
, '\\');
4435 SetLastError(0xdeadbeef);
4436 ret
= CreateScalableFontResource(0, fot_name
, file_part
, tmp_path
);
4437 ok(!ret
, "CreateScalableFontResource() should fail\n");
4438 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4440 SetLastError(0xdeadbeef);
4441 ret
= CreateScalableFontResource(0, fot_name
, "random file name", tmp_path
);
4442 ok(!ret
, "CreateScalableFontResource() should fail\n");
4443 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
4445 SetLastError(0xdeadbeef);
4446 ret
= CreateScalableFontResource(0, fot_name
, NULL
, ttf_name
);
4447 ok(!ret
, "CreateScalableFontResource() should fail\n");
4448 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
4450 ret
= DeleteFile(fot_name
);
4451 ok(ret
, "DeleteFile() error %d\n", GetLastError());
4453 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4455 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4457 /* test public font resource */
4458 SetLastError(0xdeadbeef);
4459 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
4460 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
4462 ret
= is_truetype_font_installed("wine_test");
4463 ok(!ret
, "font wine_test should not be enumerated\n");
4465 SetLastError(0xdeadbeef);
4466 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4467 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4469 ret
= is_truetype_font_installed("wine_test");
4470 ok(ret
, "font wine_test should be enumerated\n");
4472 test_GetGlyphOutline_empty_contour();
4474 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4476 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
4478 SetLastError(0xdeadbeef);
4479 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4480 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4482 ret
= is_truetype_font_installed("wine_test");
4484 ok(!ret
, "font wine_test should not be enumerated\n");
4486 /* FIXME: since RemoveFontResource is a stub correct testing is impossible */
4489 /* remove once RemoveFontResource is implemented */
4490 DeleteFile(fot_name
);
4491 DeleteFile(ttf_name
);
4495 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4496 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4498 DeleteFile(fot_name
);
4500 /* test hidden font resource */
4501 SetLastError(0xdeadbeef);
4502 ret
= CreateScalableFontResource(1, fot_name
, ttf_name
, NULL
);
4503 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
4505 ret
= is_truetype_font_installed("wine_test");
4506 ok(!ret
, "font wine_test should not be enumerated\n");
4508 SetLastError(0xdeadbeef);
4509 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4510 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4512 ret
= is_truetype_font_installed("wine_test");
4513 ok(!ret
, "font wine_test should not be enumerated\n");
4515 /* XP allows removing a private font added with 0 flags */
4516 SetLastError(0xdeadbeef);
4517 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4518 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4520 ret
= is_truetype_font_installed("wine_test");
4521 ok(!ret
, "font wine_test should not be enumerated\n");
4523 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4524 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4526 DeleteFile(fot_name
);
4527 DeleteFile(ttf_name
);
4530 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
4533 HFONT hfont
, hfont_prev
;
4537 static const WCHAR str
[] = { 0x2025 };
4539 *installed
= is_truetype_font_installed(name
);
4543 lf
.lfEscapement
= 0;
4544 lf
.lfOrientation
= 0;
4545 lf
.lfWeight
= FW_DONTCARE
;
4549 lf
.lfCharSet
= DEFAULT_CHARSET
;
4550 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
4551 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4552 lf
.lfQuality
= DEFAULT_QUALITY
;
4553 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
4554 strcpy(lf
.lfFaceName
, name
);
4556 hfont
= CreateFontIndirectA(&lf
);
4557 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
4561 hfont_prev
= SelectObject(hdc
, hfont
);
4562 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
4564 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
4565 ok(ret
, "GetTextFaceA failed\n");
4566 *selected
= !strcmp(facename
, name
);
4568 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
4569 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
4571 memset(gm
, 0, sizeof *gm
);
4573 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
4574 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
4576 SelectObject(hdc
, hfont_prev
);
4577 DeleteObject(hfont
);
4578 ReleaseDC(NULL
, hdc
);
4581 static void test_vertical_font(void)
4583 char ttf_name
[MAX_PATH
];
4585 BOOL ret
, installed
, selected
;
4589 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
4591 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4595 if (!write_ttf_file("vertical.ttf", ttf_name
))
4597 skip("Failed to create ttf file for testing\n");
4601 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
4602 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4604 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
4605 ok(installed
, "@WineTestVertical is not installed\n");
4606 ok(selected
, "@WineTestVertical is not selected\n");
4607 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
4608 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4609 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
4611 check_vertical_font("@@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
4612 ok(installed
, "@@WineTestVertical is not installed\n");
4613 ok(selected
, "@@WineTestVertical is not selected\n");
4614 ok(gm
.gmBlackBoxX
< gm
.gmBlackBoxY
,
4615 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4616 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
4618 ok(hgi
== vgi
, "different glyph h:%u v:%u\n", hgi
, vgi
);
4620 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
4621 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4623 DeleteFile(ttf_name
);
4626 static INT CALLBACK
has_vertical_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
,
4627 DWORD type
, LPARAM lParam
)
4629 if (lf
->lfFaceName
[0] == '@') {
4635 static void test_east_asian_font_selection(void)
4638 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
4639 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
4644 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
4648 char face_name
[LF_FACESIZE
];
4651 memset(&lf
, 0, sizeof lf
);
4652 lf
.lfFaceName
[0] = '\0';
4653 lf
.lfCharSet
= charset
[i
];
4655 if (EnumFontFamiliesEx(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
4657 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
4661 hfont
= CreateFontIndirectA(&lf
);
4662 hfont
= SelectObject(hdc
, hfont
);
4663 memset(face_name
, 0, sizeof face_name
);
4664 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
4665 ok(ret
&& face_name
[0] != '@',
4666 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
4667 DeleteObject(SelectObject(hdc
, hfont
));
4669 memset(&lf
, 0, sizeof lf
);
4670 strcpy(lf
.lfFaceName
, "@");
4671 lf
.lfCharSet
= charset
[i
];
4672 hfont
= CreateFontIndirectA(&lf
);
4673 hfont
= SelectObject(hdc
, hfont
);
4674 memset(face_name
, 0, sizeof face_name
);
4675 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
4676 ok(ret
&& face_name
[0] == '@',
4677 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
4678 DeleteObject(SelectObject(hdc
, hfont
));
4680 ReleaseDC(NULL
, hdc
);
4683 static int get_font_dpi(const LOGFONT
*lf
)
4685 HDC hdc
= CreateCompatibleDC(0);
4690 hfont
= CreateFontIndirect(lf
);
4691 ok(hfont
!= 0, "CreateFontIndirect failed\n");
4693 SelectObject(hdc
, hfont
);
4694 ret
= GetTextMetrics(hdc
, &tm
);
4695 ok(ret
, "GetTextMetrics failed\n");
4696 ret
= tm
.tmDigitizedAspectX
;
4699 DeleteObject(hfont
);
4704 static void test_stock_fonts(void)
4706 static const int font
[] =
4708 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
4709 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4711 static const struct test_data
4713 int charset
, weight
, height
, dpi
;
4714 const char face_name
[LF_FACESIZE
];
4717 { /* ANSI_FIXED_FONT */
4718 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 96, "Courier" },
4719 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 120, "Courier" },
4722 { /* ANSI_VAR_FONT */
4723 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 96, "MS Sans Serif" },
4724 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 120, "MS Sans Serif" },
4728 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 96, "System" },
4729 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 120, "System" },
4730 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 96, "System" },
4731 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 120, "System" },
4732 { DEFAULT_CHARSET
, FW_BOLD
, 16, 96, "System" },
4733 { DEFAULT_CHARSET
, FW_BOLD
, 20, 120, "System" },
4736 { /* DEVICE_DEFAULT_FONT */
4737 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 96, "System" },
4738 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 120, "System" },
4739 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 96, "System" },
4740 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 120, "System" },
4741 { DEFAULT_CHARSET
, FW_BOLD
, 16, 96, "System" },
4742 { DEFAULT_CHARSET
, FW_BOLD
, 20, 120, "System" },
4745 { /* DEFAULT_GUI_FONT */
4746 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 96, "?MS UI Gothic" },
4747 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 120, "?MS UI Gothic" },
4748 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 96, "?Gulim" },
4749 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 120, "?Gulim" },
4750 { GB2312_CHARSET
, FW_NORMAL
, -12, 96, "?SimHei" },
4751 { GB2312_CHARSET
, FW_NORMAL
, -15, 120, "?SimHei" },
4752 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 96, "?MingLiU" },
4753 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 120, "?MingLiU" },
4754 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 96, "MS Shell Dlg" },
4755 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 120, "MS Shell Dlg" },
4761 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
4767 hfont
= GetStockObject(font
[i
]);
4768 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
4770 ret
= GetObject(hfont
, sizeof(lf
), &lf
);
4771 if (ret
!= sizeof(lf
))
4774 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
4778 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
4780 if (lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
)
4785 ret
= get_font_dpi(&lf
);
4786 if (ret
!= td
[i
][j
].dpi
)
4788 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
4789 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
4793 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
4794 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
4795 if (td
[i
][j
].face_name
[0] == '?')
4797 /* Wine doesn't have this font, skip this case for now.
4798 Actually, the face name is localized on Windows and varies
4799 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
4800 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
4804 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
);
4818 test_outline_font();
4819 test_bitmap_font_metrics();
4820 test_GdiGetCharDimensions();
4821 test_GetCharABCWidths();
4822 test_text_extents();
4823 test_GetGlyphIndices();
4824 test_GetKerningPairs();
4825 test_GetOutlineTextMetrics();
4826 test_SetTextJustification();
4827 test_font_charset();
4828 test_GetFontUnicodeRanges();
4829 test_nonexistent_font();
4831 test_height_selection();
4832 test_AddFontMemResource();
4835 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
4836 * I'd like to avoid them in this test.
4838 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
4839 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
4840 if (is_truetype_font_installed("Arial Black") &&
4841 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
4843 test_EnumFontFamilies("", ANSI_CHARSET
);
4844 test_EnumFontFamilies("", SYMBOL_CHARSET
);
4845 test_EnumFontFamilies("", DEFAULT_CHARSET
);
4848 skip("Arial Black or Symbol/Wingdings is not installed\n");
4849 test_EnumFontFamiliesEx_default_charset();
4850 test_GetTextMetrics();
4851 test_GdiRealizationInfo();
4853 test_GetGlyphOutline();
4854 test_GetTextMetrics2("Tahoma", -11);
4855 test_GetTextMetrics2("Tahoma", -55);
4856 test_GetTextMetrics2("Tahoma", -110);
4857 test_GetTextMetrics2("Arial", -11);
4858 test_GetTextMetrics2("Arial", -55);
4859 test_GetTextMetrics2("Arial", -110);
4860 test_CreateFontIndirect();
4861 test_CreateFontIndirectEx();
4865 test_east_asian_font_selection();
4867 /* These tests should be last test until RemoveFontResource
4868 * is properly implemented.
4870 test_vertical_font();
4871 test_CreateScalableFontResource();