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_GdiGetCodePage(void)
2088 static const struct _matching_data
2090 UINT current_codepage
;
2093 UINT expected_codepage
;
2094 } matching_data
[] = {
2095 {1251, "Arial", ANSI_CHARSET
, 1252},
2096 {1251, "Tahoma", ANSI_CHARSET
, 1252},
2098 {1252, "Arial", ANSI_CHARSET
, 1252},
2099 {1252, "Tahoma", ANSI_CHARSET
, 1252},
2101 {1253, "Arial", ANSI_CHARSET
, 1252},
2102 {1253, "Tahoma", ANSI_CHARSET
, 1252},
2104 { 932, "Arial", ANSI_CHARSET
, 1252}, /* Japanese Windows returns 1252, not 932 */
2105 { 932, "Tahoma", ANSI_CHARSET
, 1252},
2106 { 932, "MS UI Gothic", ANSI_CHARSET
, 1252},
2108 { 936, "Arial", ANSI_CHARSET
, 936},
2109 { 936, "Tahoma", ANSI_CHARSET
, 936},
2110 { 936, "Simsun", ANSI_CHARSET
, 936},
2112 { 949, "Arial", ANSI_CHARSET
, 949},
2113 { 949, "Tahoma", ANSI_CHARSET
, 949},
2114 { 949, "Gulim", ANSI_CHARSET
, 949},
2116 { 950, "Arial", ANSI_CHARSET
, 950},
2117 { 950, "Tahoma", ANSI_CHARSET
, 950},
2118 { 950, "PMingLiU", ANSI_CHARSET
, 950},
2127 if (!pGdiGetCodePage
)
2129 skip("GdiGetCodePage not available on this platform\n");
2135 for (i
= 0; i
< sizeof(matching_data
) / sizeof(struct _matching_data
); i
++)
2137 /* only test data matched current locale codepage */
2138 if (matching_data
[i
].current_codepage
!= acp
)
2141 if (!is_font_installed(matching_data
[i
].lfFaceName
))
2143 skip("%s is not installed\n", matching_data
[i
].lfFaceName
);
2149 memset(&lf
, 0, sizeof(lf
));
2151 lf
.lfCharSet
= matching_data
[i
].lfCharSet
;
2152 lstrcpyA(lf
.lfFaceName
, matching_data
[i
].lfFaceName
);
2153 hfont
= CreateFontIndirectA(&lf
);
2154 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2156 hfont
= SelectObject(hdc
, hfont
);
2157 charset
= GetTextCharset(hdc
);
2158 codepage
= pGdiGetCodePage(hdc
);
2159 trace("acp=%d, lfFaceName=%s, lfCharSet=%d, GetTextCharset=%d, GdiGetCodePage=%d, expected codepage=%d\n",
2160 acp
, lf
.lfFaceName
, lf
.lfCharSet
, charset
, codepage
, matching_data
[i
].expected_codepage
);
2161 ok(codepage
== matching_data
[i
].expected_codepage
,
2162 "GdiGetCodePage should have returned %d, got %d\n", matching_data
[i
].expected_codepage
, codepage
);
2164 hfont
= SelectObject(hdc
, hfont
);
2165 DeleteObject(hfont
);
2166 ReleaseDC(NULL
, hdc
);
2170 static void test_GetFontUnicodeRanges(void)
2174 HFONT hfont
, hfont_old
;
2179 if (!pGetFontUnicodeRanges
)
2181 win_skip("GetFontUnicodeRanges not available before W2K\n");
2185 memset(&lf
, 0, sizeof(lf
));
2186 lstrcpyA(lf
.lfFaceName
, "Arial");
2187 hfont
= create_font("Arial", &lf
);
2190 hfont_old
= SelectObject(hdc
, hfont
);
2192 size
= pGetFontUnicodeRanges(NULL
, NULL
);
2193 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
2195 size
= pGetFontUnicodeRanges(hdc
, NULL
);
2196 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
2198 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
2200 size
= pGetFontUnicodeRanges(hdc
, gs
);
2201 ok(size
, "GetFontUnicodeRanges failed\n");
2203 if (0) /* Disabled to limit console spam */
2204 for (i
= 0; i
< gs
->cRanges
; i
++)
2205 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
2206 trace("found %u ranges\n", gs
->cRanges
);
2208 HeapFree(GetProcessHeap(), 0, gs
);
2210 SelectObject(hdc
, hfont_old
);
2211 DeleteObject(hfont
);
2212 ReleaseDC(NULL
, hdc
);
2215 #define MAX_ENUM_FONTS 4096
2217 struct enum_font_data
2220 LOGFONT lf
[MAX_ENUM_FONTS
];
2223 struct enum_fullname_data
2226 ENUMLOGFONT elf
[MAX_ENUM_FONTS
];
2229 struct enum_font_dataW
2232 LOGFONTW lf
[MAX_ENUM_FONTS
];
2235 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
2237 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2238 const NEWTEXTMETRIC
*ntm
= (const NEWTEXTMETRIC
*)tm
;
2240 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2241 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2243 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2245 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2247 if (0) /* Disabled to limit console spam */
2248 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
2249 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2250 if (efd
->total
< MAX_ENUM_FONTS
)
2251 efd
->lf
[efd
->total
++] = *lf
;
2253 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2258 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
2260 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
2261 const NEWTEXTMETRICW
*ntm
= (const NEWTEXTMETRICW
*)tm
;
2263 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
2264 ok(lf
->lfHeight
> 0 && lf
->lfHeight
< 200, "enumerated font height %d\n", lf
->lfHeight
);
2266 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2268 ok(ntm
->ntmCellHeight
+ ntm
->ntmCellHeight
/5 >= ntm
->ntmSizeEM
, "ntmCellHeight %d should be close to ntmSizeEM %d\n", ntm
->ntmCellHeight
, ntm
->ntmSizeEM
);
2270 if (0) /* Disabled to limit console spam */
2271 trace("enumed font %s, charset %d, height %d, weight %d, italic %d\n",
2272 wine_dbgstr_w(lf
->lfFaceName
), lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
2273 if (efd
->total
< MAX_ENUM_FONTS
)
2274 efd
->lf
[efd
->total
++] = *lf
;
2276 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2281 static void get_charset_stats(struct enum_font_data
*efd
,
2282 int *ansi_charset
, int *symbol_charset
,
2283 int *russian_charset
)
2288 *symbol_charset
= 0;
2289 *russian_charset
= 0;
2291 for (i
= 0; i
< efd
->total
; i
++)
2293 switch (efd
->lf
[i
].lfCharSet
)
2298 case SYMBOL_CHARSET
:
2299 (*symbol_charset
)++;
2301 case RUSSIAN_CHARSET
:
2302 (*russian_charset
)++;
2308 static void get_charset_statsW(struct enum_font_dataW
*efd
,
2309 int *ansi_charset
, int *symbol_charset
,
2310 int *russian_charset
)
2315 *symbol_charset
= 0;
2316 *russian_charset
= 0;
2318 for (i
= 0; i
< efd
->total
; i
++)
2320 switch (efd
->lf
[i
].lfCharSet
)
2325 case SYMBOL_CHARSET
:
2326 (*symbol_charset
)++;
2328 case RUSSIAN_CHARSET
:
2329 (*russian_charset
)++;
2335 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
2337 struct enum_font_data efd
;
2338 struct enum_font_dataW efdw
;
2341 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
2343 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
2345 if (*font_name
&& !is_truetype_font_installed(font_name
))
2347 skip("%s is not installed\n", font_name
);
2353 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
2354 * while EnumFontFamiliesEx doesn't.
2356 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
2359 * Use EnumFontFamiliesW since win98 crashes when the
2360 * second parameter is NULL using EnumFontFamilies
2363 SetLastError(0xdeadbeef);
2364 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
2365 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
2368 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2369 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2370 ansi_charset
, symbol_charset
, russian_charset
);
2371 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2372 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2373 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2374 ok(russian_charset
> 0 ||
2375 broken(russian_charset
== 0), /* NT4 */
2376 "NULL family should enumerate RUSSIAN_CHARSET\n");
2380 SetLastError(0xdeadbeef);
2381 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
2382 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
2385 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2386 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
2387 ansi_charset
, symbol_charset
, russian_charset
);
2388 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
2389 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
2390 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
2391 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
2396 SetLastError(0xdeadbeef);
2397 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
2398 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
2399 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2400 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
2401 ansi_charset
, symbol_charset
, russian_charset
,
2402 *font_name
? font_name
: "<empty>");
2404 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2406 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
2407 for (i
= 0; i
< efd
.total
; i
++)
2409 /* FIXME: remove completely once Wine is fixed */
2410 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
2413 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2416 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2417 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2418 font_name
, efd
.lf
[i
].lfFaceName
);
2421 memset(&lf
, 0, sizeof(lf
));
2422 lf
.lfCharSet
= ANSI_CHARSET
;
2423 lstrcpy(lf
.lfFaceName
, font_name
);
2425 SetLastError(0xdeadbeef);
2426 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2427 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2428 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2429 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
2430 ansi_charset
, symbol_charset
, russian_charset
,
2431 *font_name
? font_name
: "<empty>");
2432 if (font_charset
== SYMBOL_CHARSET
)
2435 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
2437 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
2441 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
2442 for (i
= 0; i
< efd
.total
; i
++)
2444 ok(efd
.lf
[i
].lfCharSet
== ANSI_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 /* DEFAULT_CHARSET should enumerate all available charsets */
2452 memset(&lf
, 0, sizeof(lf
));
2453 lf
.lfCharSet
= DEFAULT_CHARSET
;
2454 lstrcpy(lf
.lfFaceName
, font_name
);
2456 SetLastError(0xdeadbeef);
2457 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2458 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2459 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2460 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
2461 ansi_charset
, symbol_charset
, russian_charset
,
2462 *font_name
? font_name
: "<empty>");
2463 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
2464 for (i
= 0; i
< efd
.total
; i
++)
2467 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2468 font_name
, efd
.lf
[i
].lfFaceName
);
2472 switch (font_charset
)
2475 ok(ansi_charset
> 0,
2476 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2478 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
2479 ok(russian_charset
> 0,
2480 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2482 case SYMBOL_CHARSET
:
2484 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
2486 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2487 ok(!russian_charset
,
2488 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2490 case DEFAULT_CHARSET
:
2491 ok(ansi_charset
> 0,
2492 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
2493 ok(symbol_charset
> 0,
2494 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
2495 ok(russian_charset
> 0,
2496 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
2502 ok(ansi_charset
> 0,
2503 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2504 ok(symbol_charset
> 0,
2505 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2506 ok(russian_charset
> 0,
2507 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2510 memset(&lf
, 0, sizeof(lf
));
2511 lf
.lfCharSet
= SYMBOL_CHARSET
;
2512 lstrcpy(lf
.lfFaceName
, font_name
);
2514 SetLastError(0xdeadbeef);
2515 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2516 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2517 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2518 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2519 ansi_charset
, symbol_charset
, russian_charset
,
2520 *font_name
? font_name
: "<empty>");
2521 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2522 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2525 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2526 for (i
= 0; i
< efd
.total
; i
++)
2528 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2530 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2531 font_name
, efd
.lf
[i
].lfFaceName
);
2535 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2536 ok(symbol_charset
> 0,
2537 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2538 ok(!russian_charset
,
2539 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2545 static INT CALLBACK
enum_font_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2547 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
2549 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2551 if (efd
->total
< MAX_ENUM_FONTS
)
2552 efd
->lf
[efd
->total
++] = *lf
;
2554 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2559 static INT CALLBACK
enum_fullname_data_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2561 struct enum_fullname_data
*efnd
= (struct enum_fullname_data
*)lParam
;
2563 if (type
!= TRUETYPE_FONTTYPE
) return 1;
2565 if (efnd
->total
< MAX_ENUM_FONTS
)
2566 efnd
->elf
[efnd
->total
++] = *(ENUMLOGFONT
*)lf
;
2568 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
2573 static void test_EnumFontFamiliesEx_default_charset(void)
2575 struct enum_font_data efd
;
2576 LOGFONT gui_font
, enum_font
;
2580 ret
= GetObject(GetStockObject(DEFAULT_GUI_FONT
), sizeof(gui_font
), &gui_font
);
2581 ok(ret
, "GetObject failed.\n");
2588 memset(&enum_font
, 0, sizeof(enum_font
));
2589 lstrcpy(enum_font
.lfFaceName
, gui_font
.lfFaceName
);
2590 enum_font
.lfCharSet
= DEFAULT_CHARSET
;
2591 EnumFontFamiliesEx(hdc
, &enum_font
, enum_font_data_proc
, (LPARAM
)&efd
, 0);
2594 if (efd
.total
== 0) {
2595 skip("'%s' is not found or not a TrueType font.\n", gui_font
.lfFaceName
);
2598 trace("'%s' has %d charsets.\n", gui_font
.lfFaceName
, efd
.total
);
2600 ok(efd
.lf
[0].lfCharSet
== gui_font
.lfCharSet
|| broken(system_lang_id
== LANG_ARABIC
),
2601 "(%s) got charset %d expected %d\n",
2602 efd
.lf
[0].lfFaceName
, efd
.lf
[0].lfCharSet
, gui_font
.lfCharSet
);
2607 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2609 HFONT hfont
, hfont_prev
;
2611 GLYPHMETRICS gm1
, gm2
;
2615 if(!pGetGlyphIndicesA
)
2618 /* negative widths are handled just as positive ones */
2619 lf2
.lfWidth
= -lf
->lfWidth
;
2621 SetLastError(0xdeadbeef);
2622 hfont
= CreateFontIndirectA(lf
);
2623 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2624 check_font("original", lf
, hfont
);
2626 hfont_prev
= SelectObject(hdc
, hfont
);
2628 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2629 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2631 SelectObject(hdc
, hfont_prev
);
2632 DeleteObject(hfont
);
2633 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2637 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2638 memset(&gm1
, 0xab, sizeof(gm1
));
2639 SetLastError(0xdeadbeef);
2640 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2641 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2643 SelectObject(hdc
, hfont_prev
);
2644 DeleteObject(hfont
);
2646 SetLastError(0xdeadbeef);
2647 hfont
= CreateFontIndirectA(&lf2
);
2648 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2649 check_font("negative width", &lf2
, hfont
);
2651 hfont_prev
= SelectObject(hdc
, hfont
);
2653 memset(&gm2
, 0xbb, sizeof(gm2
));
2654 SetLastError(0xdeadbeef);
2655 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2656 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2658 SelectObject(hdc
, hfont_prev
);
2659 DeleteObject(hfont
);
2661 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2662 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2663 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2664 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2665 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2666 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2667 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2668 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2669 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2670 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2671 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2674 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2675 #include "pshpack2.h"
2679 SHORT xAvgCharWidth
;
2680 USHORT usWeightClass
;
2681 USHORT usWidthClass
;
2683 SHORT ySubscriptXSize
;
2684 SHORT ySubscriptYSize
;
2685 SHORT ySubscriptXOffset
;
2686 SHORT ySubscriptYOffset
;
2687 SHORT ySuperscriptXSize
;
2688 SHORT ySuperscriptYSize
;
2689 SHORT ySuperscriptXOffset
;
2690 SHORT ySuperscriptYOffset
;
2691 SHORT yStrikeoutSize
;
2692 SHORT yStrikeoutPosition
;
2695 ULONG ulUnicodeRange1
;
2696 ULONG ulUnicodeRange2
;
2697 ULONG ulUnicodeRange3
;
2698 ULONG ulUnicodeRange4
;
2701 USHORT usFirstCharIndex
;
2702 USHORT usLastCharIndex
;
2703 /* According to the Apple spec, original version didn't have the below fields,
2704 * version numbers were taken from the OpenType spec.
2706 /* version 0 (TrueType 1.5) */
2707 USHORT sTypoAscender
;
2708 USHORT sTypoDescender
;
2709 USHORT sTypoLineGap
;
2711 USHORT usWinDescent
;
2712 /* version 1 (TrueType 1.66) */
2713 ULONG ulCodePageRange1
;
2714 ULONG ulCodePageRange2
;
2715 /* version 2 (OpenType 1.2) */
2718 USHORT usDefaultChar
;
2720 USHORT usMaxContext
;
2722 #include "poppack.h"
2724 #ifdef WORDS_BIGENDIAN
2725 #define GET_BE_WORD(x) (x)
2726 #define GET_BE_DWORD(x) (x)
2728 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2729 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2732 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2733 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2734 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2735 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2736 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2737 #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e')
2750 } cmap_encoding_record
;
2758 BYTE glyph_ids
[256];
2768 USHORT search_range
;
2769 USHORT entry_selector
;
2772 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2775 USHORT start_count[seg_countx2 / 2];
2776 USHORT id_delta[seg_countx2 / 2];
2777 USHORT id_range_offset[seg_countx2 / 2];
2787 USHORT id_range_offset
;
2788 } cmap_format_4_seg
;
2790 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2792 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
||
2793 broken(PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
),
2794 "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2795 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2796 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2799 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2802 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2806 for(i
= 0; i
< 256; i
++)
2808 if(cmap
->glyph_ids
[i
] == 0) continue;
2810 if(*first
== 256) *first
= i
;
2812 if(*first
== 256) return FALSE
;
2816 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2818 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2819 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2820 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2821 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2822 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2825 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2828 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2829 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2830 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2834 for(i
= 0; i
< seg_count
; i
++)
2837 cmap_format_4_seg seg
;
2839 get_seg4(cmap
, i
, &seg
);
2840 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2842 if(seg
.id_range_offset
== 0)
2843 index
= (seg
.id_delta
+ code
) & 0xffff;
2846 index
= seg
.id_range_offset
/ 2
2847 + code
- seg
.start_count
2850 /* some fonts have broken last segment */
2851 if ((char *)(glyph_ids
+ index
+ 1) < (char *)ptr
+ limit
)
2852 index
= GET_BE_WORD(glyph_ids
[index
]);
2855 trace("segment %04x/%04x index %04x points to nowhere\n",
2856 seg
.start_count
, seg
.end_count
, index
);
2859 if(index
) index
+= seg
.id_delta
;
2861 if(*first
== 0x10000)
2862 *last
= *first
= code
;
2868 if(*first
== 0x10000) return FALSE
;
2872 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2875 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2877 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2879 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2880 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2893 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2896 cmap_header
*header
;
2901 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2902 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2903 if(size
== GDI_ERROR
) return FALSE
;
2905 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2906 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2907 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2908 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2910 cmap
= get_cmap(header
, 3, 1);
2912 *cmap_type
= cmap_ms_unicode
;
2915 cmap
= get_cmap(header
, 3, 0);
2916 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2920 *cmap_type
= cmap_none
;
2924 format
= GET_BE_WORD(*(WORD
*)cmap
);
2928 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2931 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2934 trace("unhandled cmap format %d\n", format
);
2939 HeapFree(GetProcessHeap(), 0, header
);
2943 #define TT_PLATFORM_MICROSOFT 3
2944 #define TT_MS_ID_SYMBOL_CS 0
2945 #define TT_MS_ID_UNICODE_CS 1
2946 #define TT_MS_LANGID_ENGLISH_UNITED_STATES 0x0409
2947 #define TT_NAME_ID_FONT_FAMILY 1
2948 #define TT_NAME_ID_FONT_SUBFAMILY 2
2949 #define TT_NAME_ID_UNIQUE_ID 3
2950 #define TT_NAME_ID_FULL_NAME 4
2952 static BOOL
get_ttf_nametable_entry(HDC hdc
, WORD name_id
, WCHAR
*out_buf
, SIZE_T out_size
, LCID language_id
)
2954 struct sfnt_name_header
2957 USHORT number_of_record
;
2958 USHORT storage_offset
;
2970 LONG size
, offset
, length
;
2976 size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
2977 ok(size
!= GDI_ERROR
, "no name table found\n");
2978 if(size
== GDI_ERROR
) return FALSE
;
2980 data
= HeapAlloc(GetProcessHeap(), 0, size
);
2981 ret
= GetFontData(hdc
, MS_NAME_TAG
, 0, data
, size
);
2982 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2984 header
= (void *)data
;
2985 header
->format
= GET_BE_WORD(header
->format
);
2986 header
->number_of_record
= GET_BE_WORD(header
->number_of_record
);
2987 header
->storage_offset
= GET_BE_WORD(header
->storage_offset
);
2988 if (header
->format
!= 0)
2990 trace("got format %u\n", header
->format
);
2993 if (header
->number_of_record
== 0 || sizeof(*header
) + header
->number_of_record
* sizeof(*entry
) > size
)
2995 trace("number records out of range: %d\n", header
->number_of_record
);
2998 if (header
->storage_offset
>= size
)
3000 trace("storage_offset %u > size %u\n", header
->storage_offset
, size
);
3004 entry
= (void *)&header
[1];
3005 for (i
= 0; i
< header
->number_of_record
; i
++)
3007 if (GET_BE_WORD(entry
[i
].platform_id
) != TT_PLATFORM_MICROSOFT
||
3008 (GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_UNICODE_CS
&& GET_BE_WORD(entry
[i
].encoding_id
) != TT_MS_ID_SYMBOL_CS
) ||
3009 GET_BE_WORD(entry
[i
].language_id
) != language_id
||
3010 GET_BE_WORD(entry
[i
].name_id
) != name_id
)
3015 offset
= header
->storage_offset
+ GET_BE_WORD(entry
[i
].offset
);
3016 length
= GET_BE_WORD(entry
[i
].length
);
3017 if (offset
+ length
> size
)
3019 trace("entry %d is out of range\n", i
);
3022 if (length
>= out_size
)
3024 trace("buffer too small for entry %d\n", i
);
3028 name
= (WCHAR
*)(data
+ offset
);
3029 for (c
= 0; c
< length
/ 2; c
++)
3030 out_buf
[c
] = GET_BE_WORD(name
[c
]);
3038 HeapFree(GetProcessHeap(), 0, data
);
3042 static void test_text_metrics(const LOGFONT
*lf
, const NEWTEXTMETRIC
*ntm
)
3045 HFONT hfont
, hfont_old
;
3049 const char *font_name
= lf
->lfFaceName
;
3050 DWORD cmap_first
= 0, cmap_last
= 0;
3051 UINT ascent
, descent
, cell_height
;
3052 cmap_type cmap_type
;
3053 BOOL sys_lang_non_english
;
3055 sys_lang_non_english
= PRIMARYLANGID(GetSystemDefaultLangID()) != LANG_ENGLISH
;
3058 SetLastError(0xdeadbeef);
3059 hfont
= CreateFontIndirectA(lf
);
3060 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
3062 hfont_old
= SelectObject(hdc
, hfont
);
3064 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
3065 if (size
== GDI_ERROR
)
3067 trace("OS/2 chunk was not found\n");
3070 if (size
> sizeof(tt_os2
))
3072 trace("got too large OS/2 chunk of size %u\n", size
);
3073 size
= sizeof(tt_os2
);
3076 memset(&tt_os2
, 0, sizeof(tt_os2
));
3077 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
3078 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
3080 ascent
= GET_BE_WORD(tt_os2
.usWinAscent
);
3081 descent
= GET_BE_WORD(tt_os2
.usWinDescent
);
3082 cell_height
= ascent
+ descent
;
3083 ok(ntm
->ntmCellHeight
== cell_height
, "%s: ntmCellHeight %u != %u, os2.usWinAscent/os2.usWinDescent %u/%u\n",
3084 font_name
, ntm
->ntmCellHeight
, cell_height
, ascent
, descent
);
3086 SetLastError(0xdeadbeef);
3087 ret
= GetTextMetricsA(hdc
, &tmA
);
3088 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3090 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
3092 skip("Unable to retrieve first and last glyphs from cmap\n");
3096 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
3097 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
3098 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
3102 version
= GET_BE_WORD(tt_os2
.version
);
3104 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
3105 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
3106 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
3107 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
3109 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
3110 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
3111 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
3113 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
3118 case 1257: /* Baltic */
3119 expect_last_W
= 0xf8fd;
3122 expect_last_W
= 0xf0ff;
3124 expect_break_W
= 0x20;
3125 expect_default_W
= expect_break_W
- 1;
3126 expect_first_A
= 0x1e;
3127 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
3131 expect_first_W
= cmap_first
;
3132 expect_last_W
= min(cmap_last
, os2_last_char
);
3133 if(os2_first_char
<= 1)
3134 expect_break_W
= os2_first_char
+ 2;
3135 else if(os2_first_char
> 0xff)
3136 expect_break_W
= 0x20;
3138 expect_break_W
= os2_first_char
;
3139 expect_default_W
= expect_break_W
- 1;
3140 expect_first_A
= expect_default_W
- 1;
3141 expect_last_A
= min(expect_last_W
, 0xff);
3143 expect_break_A
= expect_break_W
;
3144 expect_default_A
= expect_default_W
;
3146 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
3147 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
3148 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
3149 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3150 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3152 ok(tmA
.tmFirstChar
== expect_first_A
||
3153 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
3154 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
3155 if (pGdiGetCodePage
== NULL
|| ! IsDBCSLeadByteEx(pGdiGetCodePage(hdc
), tmA
.tmLastChar
))
3156 ok(tmA
.tmLastChar
== expect_last_A
||
3157 tmA
.tmLastChar
== 0xff /* win9x */,
3158 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
3160 skip("tmLastChar is DBCS lead byte\n");
3161 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
3162 font_name
, tmA
.tmBreakChar
, expect_break_A
);
3163 ok(tmA
.tmDefaultChar
== expect_default_A
|| broken(sys_lang_non_english
),
3164 "A: tmDefaultChar for %s got %02x expected %02x\n",
3165 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
3168 SetLastError(0xdeadbeef);
3169 ret
= GetTextMetricsW(hdc
, &tmW
);
3170 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
3171 "GetTextMetricsW error %u\n", GetLastError());
3174 /* Wine uses the os2 first char */
3175 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
3176 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3177 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3179 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
3180 font_name
, tmW
.tmFirstChar
, expect_first_W
);
3182 /* Wine uses the os2 last char */
3183 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
3184 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3185 font_name
, tmW
.tmLastChar
, expect_last_W
);
3187 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
3188 font_name
, tmW
.tmLastChar
, expect_last_W
);
3189 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
3190 font_name
, tmW
.tmBreakChar
, expect_break_W
);
3191 ok(tmW
.tmDefaultChar
== expect_default_W
|| broken(sys_lang_non_english
),
3192 "W: tmDefaultChar for %s got %02x expected %02x\n",
3193 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
3195 /* Test the aspect ratio while we have tmW */
3196 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
3197 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
3198 tmW
.tmDigitizedAspectX
, ret
);
3199 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
3200 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
3201 tmW
.tmDigitizedAspectX
, ret
);
3205 /* test FF_ values */
3206 switch(tt_os2
.panose
.bFamilyType
)
3210 case PAN_FAMILY_TEXT_DISPLAY
:
3211 case PAN_FAMILY_PICTORIAL
:
3213 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
3214 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
3216 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
3219 switch(tt_os2
.panose
.bSerifStyle
)
3224 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
3227 case PAN_SERIF_COVE
:
3228 case PAN_SERIF_OBTUSE_COVE
:
3229 case PAN_SERIF_SQUARE_COVE
:
3230 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
3231 case PAN_SERIF_SQUARE
:
3232 case PAN_SERIF_THIN
:
3233 case PAN_SERIF_BONE
:
3234 case PAN_SERIF_EXAGGERATED
:
3235 case PAN_SERIF_TRIANGLE
:
3236 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
3239 case PAN_SERIF_NORMAL_SANS
:
3240 case PAN_SERIF_OBTUSE_SANS
:
3241 case PAN_SERIF_PERP_SANS
:
3242 case PAN_SERIF_FLARED
:
3243 case PAN_SERIF_ROUNDED
:
3244 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
3249 case PAN_FAMILY_SCRIPT
:
3250 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
3253 case PAN_FAMILY_DECORATIVE
:
3254 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
3258 test_negative_width(hdc
, lf
);
3261 SelectObject(hdc
, hfont_old
);
3262 DeleteObject(hfont
);
3267 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
3269 INT
*enumed
= (INT
*)lParam
;
3271 if (type
== TRUETYPE_FONTTYPE
)
3274 test_text_metrics(lf
, (const NEWTEXTMETRIC
*)ntm
);
3279 static void test_GetTextMetrics(void)
3285 /* Report only once */
3286 if(!pGetGlyphIndicesA
)
3287 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
3291 memset(&lf
, 0, sizeof(lf
));
3292 lf
.lfCharSet
= DEFAULT_CHARSET
;
3294 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
3295 trace("Tested metrics of %d truetype fonts\n", enumed
);
3300 static void test_nonexistent_font(void)
3308 { "Times New Roman Baltic", 186 },
3309 { "Times New Roman CE", 238 },
3310 { "Times New Roman CYR", 204 },
3311 { "Times New Roman Greek", 161 },
3312 { "Times New Roman TUR", 162 }
3318 INT cs
, expected_cs
, i
;
3319 char buf
[LF_FACESIZE
];
3321 if (!is_truetype_font_installed("Arial") ||
3322 !is_truetype_font_installed("Times New Roman"))
3324 skip("Arial or Times New Roman not installed\n");
3328 expected_cs
= GetACP();
3329 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
3331 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
3334 expected_cs
= csi
.ciCharset
;
3335 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
3339 memset(&lf
, 0, sizeof(lf
));
3341 lf
.lfWeight
= FW_REGULAR
;
3342 lf
.lfCharSet
= ANSI_CHARSET
;
3343 lf
.lfPitchAndFamily
= FF_SWISS
;
3344 strcpy(lf
.lfFaceName
, "Nonexistent font");
3345 hfont
= CreateFontIndirectA(&lf
);
3346 hfont
= SelectObject(hdc
, hfont
);
3347 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3348 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
3349 cs
= GetTextCharset(hdc
);
3350 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3351 DeleteObject(SelectObject(hdc
, hfont
));
3353 memset(&lf
, 0, sizeof(lf
));
3355 lf
.lfWeight
= FW_DONTCARE
;
3356 strcpy(lf
.lfFaceName
, "Nonexistent font");
3357 hfont
= CreateFontIndirectA(&lf
);
3358 hfont
= SelectObject(hdc
, hfont
);
3359 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3360 todo_wine
/* Wine uses Arial for all substitutions */
3361 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
3362 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
3363 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3365 cs
= GetTextCharset(hdc
);
3366 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d\n", expected_cs
, cs
);
3367 DeleteObject(SelectObject(hdc
, hfont
));
3369 memset(&lf
, 0, sizeof(lf
));
3371 lf
.lfWeight
= FW_REGULAR
;
3372 strcpy(lf
.lfFaceName
, "Nonexistent font");
3373 hfont
= CreateFontIndirectA(&lf
);
3374 hfont
= SelectObject(hdc
, hfont
);
3375 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3376 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3377 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
3378 cs
= GetTextCharset(hdc
);
3379 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3380 DeleteObject(SelectObject(hdc
, hfont
));
3382 memset(&lf
, 0, sizeof(lf
));
3384 lf
.lfWeight
= FW_DONTCARE
;
3385 strcpy(lf
.lfFaceName
, "Times New Roman");
3386 hfont
= CreateFontIndirectA(&lf
);
3387 hfont
= SelectObject(hdc
, hfont
);
3388 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3389 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
3390 cs
= GetTextCharset(hdc
);
3391 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
3392 DeleteObject(SelectObject(hdc
, hfont
));
3394 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
3396 memset(&lf
, 0, sizeof(lf
));
3398 lf
.lfWeight
= FW_REGULAR
;
3399 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3400 hfont
= CreateFontIndirectA(&lf
);
3401 hfont
= SelectObject(hdc
, hfont
);
3402 cs
= GetTextCharset(hdc
);
3403 if (font_subst
[i
].charset
== expected_cs
)
3405 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3406 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3407 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
3411 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
3412 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3413 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
3414 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
3416 DeleteObject(SelectObject(hdc
, hfont
));
3418 memset(&lf
, 0, sizeof(lf
));
3420 lf
.lfWeight
= FW_DONTCARE
;
3421 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
3422 hfont
= CreateFontIndirectA(&lf
);
3423 hfont
= SelectObject(hdc
, hfont
);
3424 GetTextFaceA(hdc
, sizeof(buf
), buf
);
3425 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
3426 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
3427 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
3428 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
3429 "got %s for font %s\n", buf
, font_subst
[i
].name
);
3430 cs
= GetTextCharset(hdc
);
3431 ok(cs
== expected_cs
|| cs
== ANSI_CHARSET
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
3432 DeleteObject(SelectObject(hdc
, hfont
));
3438 static void test_GdiRealizationInfo(void)
3443 HFONT hfont
, hfont_old
;
3446 if(!pGdiRealizationInfo
)
3448 win_skip("GdiRealizationInfo not available\n");
3454 memset(info
, 0xcc, sizeof(info
));
3455 r
= pGdiRealizationInfo(hdc
, info
);
3456 ok(r
!= 0, "ret 0\n");
3457 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
3458 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3460 if (!is_truetype_font_installed("Arial"))
3462 skip("skipping GdiRealizationInfo with truetype font\n");
3466 memset(&lf
, 0, sizeof(lf
));
3467 strcpy(lf
.lfFaceName
, "Arial");
3469 lf
.lfWeight
= FW_NORMAL
;
3470 hfont
= CreateFontIndirectA(&lf
);
3471 hfont_old
= SelectObject(hdc
, hfont
);
3473 memset(info
, 0xcc, sizeof(info
));
3474 r
= pGdiRealizationInfo(hdc
, info
);
3475 ok(r
!= 0, "ret 0\n");
3476 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
3477 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
3479 DeleteObject(SelectObject(hdc
, hfont_old
));
3485 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
3486 the nul in the count of characters copied when the face name buffer is not
3487 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
3488 always includes it. */
3489 static void test_GetTextFace(void)
3491 static const char faceA
[] = "Tahoma";
3492 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
3495 char bufA
[LF_FACESIZE
];
3496 WCHAR bufW
[LF_FACESIZE
];
3501 if(!is_font_installed("Tahoma"))
3503 skip("Tahoma is not installed so skipping this test\n");
3508 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
3509 f
= CreateFontIndirectA(&fA
);
3510 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
3513 g
= SelectObject(dc
, f
);
3514 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
3515 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
3516 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
3518 /* Play with the count arg. */
3520 n
= GetTextFaceA(dc
, 0, bufA
);
3521 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3522 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3525 n
= GetTextFaceA(dc
, 1, bufA
);
3526 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
3527 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
3529 bufA
[0] = 'x'; bufA
[1] = 'y';
3530 n
= GetTextFaceA(dc
, 2, bufA
);
3531 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
3532 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
3534 n
= GetTextFaceA(dc
, 0, NULL
);
3535 ok(n
== sizeof faceA
||
3536 broken(n
== 0), /* win98, winMe */
3537 "GetTextFaceA returned %d\n", n
);
3539 DeleteObject(SelectObject(dc
, g
));
3540 ReleaseDC(NULL
, dc
);
3543 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
3544 SetLastError(0xdeadbeef);
3545 f
= CreateFontIndirectW(&fW
);
3546 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
3548 win_skip("CreateFontIndirectW is not implemented\n");
3551 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
3554 g
= SelectObject(dc
, f
);
3555 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
3556 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3557 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
3559 /* Play with the count arg. */
3561 n
= GetTextFaceW(dc
, 0, bufW
);
3562 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
3563 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3566 n
= GetTextFaceW(dc
, 1, bufW
);
3567 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
3568 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
3570 bufW
[0] = 'x'; bufW
[1] = 'y';
3571 n
= GetTextFaceW(dc
, 2, bufW
);
3572 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
3573 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
3575 n
= GetTextFaceW(dc
, 0, NULL
);
3576 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
3578 DeleteObject(SelectObject(dc
, g
));
3579 ReleaseDC(NULL
, dc
);
3582 static void test_orientation(void)
3584 static const char test_str
[11] = "Test String";
3587 HFONT hfont
, old_hfont
;
3590 if (!is_truetype_font_installed("Arial"))
3592 skip("Arial is not installed\n");
3596 hdc
= CreateCompatibleDC(0);
3597 memset(&lf
, 0, sizeof(lf
));
3598 lstrcpyA(lf
.lfFaceName
, "Arial");
3600 lf
.lfOrientation
= lf
.lfEscapement
= 900;
3601 hfont
= create_font("orientation", &lf
);
3602 old_hfont
= SelectObject(hdc
, hfont
);
3603 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
3604 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
3605 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
3606 SelectObject(hdc
, old_hfont
);
3607 DeleteObject(hfont
);
3611 static void test_oemcharset(void)
3615 HFONT hfont
, old_hfont
;
3618 hdc
= CreateCompatibleDC(0);
3619 ZeroMemory(&lf
, sizeof(lf
));
3621 lf
.lfCharSet
= OEM_CHARSET
;
3622 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
3623 lstrcpyA(lf
.lfFaceName
, "Terminal");
3624 hfont
= CreateFontIndirectA(&lf
);
3625 old_hfont
= SelectObject(hdc
, hfont
);
3626 charset
= GetTextCharset(hdc
);
3628 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
3629 hfont
= SelectObject(hdc
, old_hfont
);
3630 GetObjectA(hfont
, sizeof(clf
), &clf
);
3631 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
3632 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
3633 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
3634 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
3635 DeleteObject(hfont
);
3639 static int CALLBACK
create_fixed_pitch_font_proc(const LOGFONT
*lpelfe
,
3640 const TEXTMETRIC
*lpntme
,
3641 DWORD FontType
, LPARAM lParam
)
3643 const NEWTEXTMETRICEX
*lpntmex
= (const NEWTEXTMETRICEX
*)lpntme
;
3645 LOGFONT lf
= *lpelfe
;
3648 /* skip bitmap, proportional or vertical font */
3649 if ((FontType
& TRUETYPE_FONTTYPE
) == 0 ||
3650 (lf
.lfPitchAndFamily
& 0xf) != FIXED_PITCH
||
3651 lf
.lfFaceName
[0] == '@')
3654 /* skip linked font */
3655 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)lpelfe
->lfCharSet
, &csi
, TCI_SRCCHARSET
) ||
3656 (lpntmex
->ntmFontSig
.fsCsb
[0] & csi
.fs
.fsCsb
[0]) == 0)
3659 /* test with an odd height */
3662 hfont
= CreateFontIndirect(&lf
);
3665 *(HFONT
*)lParam
= hfont
;
3671 static void test_GetGlyphOutline(void)
3674 GLYPHMETRICS gm
, gm2
;
3676 HFONT hfont
, old_hfont
;
3685 {ANSI_CHARSET
, 0x30, 0x30},
3686 {SHIFTJIS_CHARSET
, 0x82a0, 0x3042},
3687 {HANGEUL_CHARSET
, 0x8141, 0xac02},
3688 {JOHAB_CHARSET
, 0x8446, 0x3135},
3689 {GB2312_CHARSET
, 0x8141, 0x4e04},
3690 {CHINESEBIG5_CHARSET
, 0xa142, 0x3001}
3694 if (!is_truetype_font_installed("Tahoma"))
3696 skip("Tahoma is not installed\n");
3700 hdc
= CreateCompatibleDC(0);
3701 memset(&lf
, 0, sizeof(lf
));
3703 lstrcpyA(lf
.lfFaceName
, "Tahoma");
3704 SetLastError(0xdeadbeef);
3705 hfont
= CreateFontIndirectA(&lf
);
3706 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
3707 old_hfont
= SelectObject(hdc
, hfont
);
3709 memset(&gm
, 0, sizeof(gm
));
3710 SetLastError(0xdeadbeef);
3711 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3712 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3714 memset(&gm
, 0, sizeof(gm
));
3715 SetLastError(0xdeadbeef);
3716 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3717 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
3718 ok(GetLastError() == 0xdeadbeef ||
3719 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
3720 "expected 0xdeadbeef, got %u\n", GetLastError());
3722 memset(&gm
, 0, sizeof(gm
));
3723 SetLastError(0xdeadbeef);
3724 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
3725 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3726 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
3728 memset(&gm
, 0, sizeof(gm
));
3729 SetLastError(0xdeadbeef);
3730 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
3731 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3733 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
3734 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3737 /* test for needed buffer size request on space char */
3738 memset(&gm
, 0, sizeof(gm
));
3739 SetLastError(0xdeadbeef);
3740 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3741 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3742 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3744 /* requesting buffer size for space char + error */
3745 memset(&gm
, 0, sizeof(gm
));
3746 SetLastError(0xdeadbeef);
3747 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3748 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3750 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3751 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3754 SelectObject(hdc
, old_hfont
);
3755 DeleteObject(hfont
);
3757 for (i
= 0; i
< sizeof c
/ sizeof c
[0]; ++i
)
3759 static const MAT2 rotate_mat
= {{0, 0}, {0, -1}, {0, 1}, {0, 0}};
3762 lf
.lfFaceName
[0] = '\0';
3763 lf
.lfCharSet
= c
[i
].cs
;
3764 lf
.lfPitchAndFamily
= 0;
3765 if (EnumFontFamiliesEx(hdc
, &lf
, create_font_proc
, (LPARAM
)&hfont
, 0))
3767 skip("TrueType font for charset %u is not installed\n", c
[i
].cs
);
3771 old_hfont
= SelectObject(hdc
, hfont
);
3773 /* expected to ignore superfluous bytes (sigle-byte character) */
3774 ret
= GetGlyphOutlineA(hdc
, 0x8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3775 ret2
= GetGlyphOutlineA(hdc
, 0x41, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3776 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3778 ret
= GetGlyphOutlineA(hdc
, 0xcc8041, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3779 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3780 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3782 /* expected to ignore superfluous bytes (double-byte character) */
3783 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_BITMAP
, &gm
, 0, NULL
, &mat
);
3784 ret2
= GetGlyphOutlineA(hdc
, c
[i
].a
| 0xdead0000, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3785 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0,
3786 "Expected to ignore superfluous bytes, got %d %d\n", ret
, ret2
);
3788 /* expected to match wide-char version results */
3789 ret2
= GetGlyphOutlineW(hdc
, c
[i
].w
, GGO_BITMAP
, &gm2
, 0, NULL
, &mat
);
3790 ok(ret
== ret2
&& memcmp(&gm
, &gm2
, sizeof gm
) == 0, "%d %d\n", ret
, ret2
);
3792 if (EnumFontFamiliesEx(hdc
, &lf
, create_fixed_pitch_font_proc
, (LPARAM
)&hfont
, 0))
3794 skip("Fixed-pitch TrueType font for charset %u is not available\n", c
[i
].cs
);
3797 DeleteObject(SelectObject(hdc
, hfont
));
3800 DeleteObject(SelectObject(hdc
, old_hfont
));
3804 ret
= GetObject(hfont
, sizeof lf
, &lf
);
3805 ok(ret
> 0, "GetObject error %u\n", GetLastError());
3807 ret
= GetTextMetrics(hdc
, &tm
);
3808 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3809 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3810 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3811 trace("Tests with height=%d,avg=%d,full=%d,face=%s,charset=%d\n",
3812 -lf
.lfHeight
, tm
.tmAveCharWidth
, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
3813 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
3814 "expected %d, got %d (%s:%d)\n",
3815 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
3817 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &rotate_mat
);
3818 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3819 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
3820 "expected %d, got %d (%s:%d)\n",
3821 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
3824 hfont
= CreateFontIndirect(&lf
);
3825 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
3826 DeleteObject(SelectObject(hdc
, hfont
));
3827 ret
= GetTextMetrics(hdc
, &tm
);
3828 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3829 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3830 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3831 ok(gm2
.gmCellIncX
== tm
.tmAveCharWidth
* 2 || broken(gm2
.gmCellIncX
== -lf
.lfHeight
),
3832 "expected %d, got %d (%s:%d)\n",
3833 tm
.tmAveCharWidth
* 2, gm2
.gmCellIncX
, lf
.lfFaceName
, lf
.lfCharSet
);
3835 lf
.lfItalic
= FALSE
;
3836 lf
.lfEscapement
= lf
.lfOrientation
= 2700;
3837 hfont
= CreateFontIndirect(&lf
);
3838 ok(hfont
!= NULL
, "CreateFontIndirect error %u\n", GetLastError());
3839 DeleteObject(SelectObject(hdc
, hfont
));
3840 ret
= GetGlyphOutlineA(hdc
, c
[i
].a
, GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
3841 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
3842 ok(gm2
.gmCellIncY
== -lf
.lfHeight
,
3843 "expected %d, got %d (%s:%d)\n",
3844 -lf
.lfHeight
, gm2
.gmCellIncY
, lf
.lfFaceName
, lf
.lfCharSet
);
3846 hfont
= SelectObject(hdc
, old_hfont
);
3847 DeleteObject(hfont
);
3853 /* bug #9995: there is a limit to the character width that can be specified */
3854 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3860 int ave_width
, height
, width
, ratio
, scale
;
3862 if (!is_truetype_font_installed( fontname
)) {
3863 skip("%s is not installed\n", fontname
);
3866 hdc
= CreateCompatibleDC(0);
3867 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3868 /* select width = 0 */
3869 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3870 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3871 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3873 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3874 of
= SelectObject( hdc
, hf
);
3875 ret
= GetTextMetricsA( hdc
, &tm
);
3876 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3877 height
= tm
.tmHeight
;
3878 ave_width
= tm
.tmAveCharWidth
;
3879 SelectObject( hdc
, of
);
3882 trace("height %d, ave width %d\n", height
, ave_width
);
3884 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3886 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3887 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3888 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3889 ok(hf
!= 0, "CreateFont failed\n");
3890 of
= SelectObject(hdc
, hf
);
3891 ret
= GetTextMetrics(hdc
, &tm
);
3892 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3893 SelectObject(hdc
, of
);
3896 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3902 ratio
= width
/ height
;
3903 scale
= width
/ ave_width
;
3905 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3906 width
, height
, ratio
, width
, ave_width
, scale
);
3908 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3911 static void test_CreateFontIndirect(void)
3913 LOGFONTA lf
, getobj_lf
;
3916 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3918 memset(&lf
, 0, sizeof(lf
));
3919 lf
.lfCharSet
= ANSI_CHARSET
;
3920 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3923 lf
.lfQuality
= DEFAULT_QUALITY
;
3924 lf
.lfItalic
= FALSE
;
3925 lf
.lfWeight
= FW_DONTCARE
;
3927 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3929 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3930 hfont
= CreateFontIndirectA(&lf
);
3931 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3932 SetLastError(0xdeadbeef);
3933 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3934 ok(ret
, "GetObject failed: %d\n", GetLastError());
3935 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3936 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3937 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3938 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3939 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3940 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3941 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3942 DeleteObject(hfont
);
3946 static void test_CreateFontIndirectEx(void)
3948 ENUMLOGFONTEXDVA lfex
;
3951 if (!pCreateFontIndirectExA
)
3953 win_skip("CreateFontIndirectExA is not available\n");
3957 if (!is_truetype_font_installed("Arial"))
3959 skip("Arial is not installed\n");
3963 SetLastError(0xdeadbeef);
3964 hfont
= pCreateFontIndirectExA(NULL
);
3965 ok(hfont
== NULL
, "got %p\n", hfont
);
3966 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3968 memset(&lfex
, 0, sizeof(lfex
));
3969 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3970 hfont
= pCreateFontIndirectExA(&lfex
);
3971 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3973 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3974 DeleteObject(hfont
);
3977 static void free_font(void *font
)
3979 UnmapViewOfFile(font
);
3982 static void *load_font(const char *font_name
, DWORD
*font_size
)
3984 char file_name
[MAX_PATH
];
3985 HANDLE file
, mapping
;
3988 if (!GetWindowsDirectory(file_name
, sizeof(file_name
))) return NULL
;
3989 strcat(file_name
, "\\fonts\\");
3990 strcat(file_name
, font_name
);
3992 file
= CreateFile(file_name
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, 0);
3993 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
3995 *font_size
= GetFileSize(file
, NULL
);
3997 mapping
= CreateFileMapping(file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4004 font
= MapViewOfFile(mapping
, FILE_MAP_READ
, 0, 0, 0);
4007 CloseHandle(mapping
);
4011 static void test_AddFontMemResource(void)
4014 DWORD font_size
, num_fonts
;
4018 if (!pAddFontMemResourceEx
|| !pRemoveFontMemResourceEx
)
4020 win_skip("AddFontMemResourceEx is not available on this platform\n");
4024 font
= load_font("sserife.fon", &font_size
);
4027 skip("Unable to locate and load font sserife.fon\n");
4031 SetLastError(0xdeadbeef);
4032 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, NULL
);
4033 ok(!ret
, "AddFontMemResourceEx should fail\n");
4034 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4035 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4038 SetLastError(0xdeadbeef);
4039 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, NULL
);
4040 ok(!ret
, "AddFontMemResourceEx should fail\n");
4041 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4042 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4045 SetLastError(0xdeadbeef);
4046 ret
= pAddFontMemResourceEx(NULL
, 0, NULL
, &num_fonts
);
4047 ok(!ret
, "AddFontMemResourceEx should fail\n");
4048 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4049 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4052 SetLastError(0xdeadbeef);
4053 ret
= pAddFontMemResourceEx(NULL
, 10, NULL
, &num_fonts
);
4054 ok(!ret
, "AddFontMemResourceEx should fail\n");
4055 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4056 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4059 SetLastError(0xdeadbeef);
4060 ret
= pAddFontMemResourceEx(font
, 0, NULL
, NULL
);
4061 ok(!ret
, "AddFontMemResourceEx should fail\n");
4062 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4063 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4066 SetLastError(0xdeadbeef);
4067 ret
= pAddFontMemResourceEx(font
, 10, NULL
, NULL
);
4068 ok(!ret
, "AddFontMemResourceEx should fail\n");
4069 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4070 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4073 num_fonts
= 0xdeadbeef;
4074 SetLastError(0xdeadbeef);
4075 ret
= pAddFontMemResourceEx(font
, 0, NULL
, &num_fonts
);
4076 ok(!ret
, "AddFontMemResourceEx should fail\n");
4077 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4078 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4080 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4082 if (0) /* hangs under windows 2000 */
4084 num_fonts
= 0xdeadbeef;
4085 SetLastError(0xdeadbeef);
4086 ret
= pAddFontMemResourceEx(font
, 10, NULL
, &num_fonts
);
4087 ok(!ret
, "AddFontMemResourceEx should fail\n");
4088 ok(GetLastError() == 0xdeadbeef,
4089 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4091 ok(num_fonts
== 0xdeadbeef, "number of loaded fonts should be 0xdeadbeef\n");
4094 num_fonts
= 0xdeadbeef;
4095 SetLastError(0xdeadbeef);
4096 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, &num_fonts
);
4097 ok(ret
!= 0, "AddFontMemResourceEx error %d\n", GetLastError());
4098 ok(num_fonts
!= 0xdeadbeef, "number of loaded fonts should not be 0xdeadbeef\n");
4099 ok(num_fonts
!= 0, "number of loaded fonts should not be 0\n");
4103 SetLastError(0xdeadbeef);
4104 bRet
= pRemoveFontMemResourceEx(ret
);
4105 ok(bRet
, "RemoveFontMemResourceEx error %d\n", GetLastError());
4107 /* test invalid pointer to number of loaded fonts */
4108 font
= load_font("sserife.fon", &font_size
);
4109 ok(font
!= NULL
, "Unable to locate and load font sserife.fon\n");
4111 SetLastError(0xdeadbeef);
4112 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, (void *)0xdeadbeef);
4113 ok(!ret
, "AddFontMemResourceEx should fail\n");
4114 ok(GetLastError() == 0xdeadbeef,
4115 "Expected GetLastError() to return 0xdeadbeef, got %u\n",
4118 SetLastError(0xdeadbeef);
4119 ret
= pAddFontMemResourceEx(font
, font_size
, NULL
, NULL
);
4120 ok(!ret
, "AddFontMemResourceEx should fail\n");
4121 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
4122 "Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
4128 static INT CALLBACK
enum_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
4132 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4134 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4136 lf
= (LOGFONT
*)lparam
;
4141 static INT CALLBACK
enum_all_fonts_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
4146 if (type
!= TRUETYPE_FONTTYPE
) return 1;
4148 lf
= (LOGFONT
*)lparam
;
4149 ret
= strcmp(lf
->lfFaceName
, elf
->lfFaceName
);
4152 ok(ntm
->tmWeight
== elf
->lfWeight
, "expected %d got %d\n", ntm
->tmWeight
, elf
->lfWeight
);
4159 static INT CALLBACK
enum_with_magic_retval_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lparam
)
4164 static void test_EnumFonts(void)
4170 if (!is_truetype_font_installed("Arial"))
4172 skip("Arial is not installed\n");
4176 /* Windows uses localized font face names, so Arial Bold won't be found */
4177 if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH
)
4179 skip("User locale is not English, skipping the test\n");
4183 hdc
= CreateCompatibleDC(0);
4185 /* check that the enumproc's retval is returned */
4186 ret
= EnumFontFamilies(hdc
, NULL
, enum_with_magic_retval_proc
, 0xcafe);
4187 ok(ret
== 0xcafe, "got %08x\n", ret
);
4189 ret
= EnumFontFamilies(hdc
, "Arial", enum_fonts_proc
, (LPARAM
)&lf
);
4190 ok(!ret
, "font Arial is not enumerated\n");
4191 ret
= strcmp(lf
.lfFaceName
, "Arial");
4192 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4193 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4195 lstrcpy(lf
.lfFaceName
, "Arial");
4196 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4197 ok(!ret
, "font Arial is not enumerated\n");
4198 ret
= strcmp(lf
.lfFaceName
, "Arial");
4199 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4200 ok(lf
.lfWeight
== FW_NORMAL
, "expected FW_NORMAL got %d\n", lf
.lfWeight
);
4202 ret
= EnumFontFamilies(hdc
, "Arial Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4203 ok(!ret
, "font Arial Bold is not enumerated\n");
4204 ret
= strcmp(lf
.lfFaceName
, "Arial");
4205 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4206 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4208 lstrcpy(lf
.lfFaceName
, "Arial Bold");
4209 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4210 ok(ret
, "font Arial Bold should not be enumerated\n");
4212 ret
= EnumFontFamilies(hdc
, "Arial Bold Italic", enum_fonts_proc
, (LPARAM
)&lf
);
4213 ok(!ret
, "font Arial Bold Italic is not enumerated\n");
4214 ret
= strcmp(lf
.lfFaceName
, "Arial");
4215 ok(!ret
, "expected Arial got %s\n", lf
.lfFaceName
);
4216 ok(lf
.lfWeight
== FW_BOLD
, "expected FW_BOLD got %d\n", lf
.lfWeight
);
4218 lstrcpy(lf
.lfFaceName
, "Arial Bold Italic");
4219 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4220 ok(ret
, "font Arial Bold Italic should not be enumerated\n");
4222 ret
= EnumFontFamilies(hdc
, "Arial Italic Bold", enum_fonts_proc
, (LPARAM
)&lf
);
4223 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4225 lstrcpy(lf
.lfFaceName
, "Arial Italic Bold");
4226 ret
= EnumFontFamilies(hdc
, NULL
, enum_all_fonts_proc
, (LPARAM
)&lf
);
4227 ok(ret
, "font Arial Italic Bold should not be enumerated\n");
4232 static INT CALLBACK
is_font_installed_fullname_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
4234 const ENUMLOGFONT
*elf
= (const ENUMLOGFONT
*)lf
;
4235 const char *fullname
= (const char *)lParam
;
4237 if (!strcmp((const char *)elf
->elfFullName
, fullname
)) return 0;
4242 static BOOL
is_font_installed_fullname(const char *family
, const char *fullname
)
4247 if(!EnumFontFamiliesA(hdc
, family
, is_font_installed_fullname_proc
, (LPARAM
)fullname
))
4254 static void test_fullname(void)
4256 static const char *TestName
[] = {"Lucida Sans Demibold Roman", "Lucida Sans Italic", "Lucida Sans Regular"};
4257 WCHAR bufW
[LF_FULLFACESIZE
];
4258 char bufA
[LF_FULLFACESIZE
];
4265 hdc
= CreateCompatibleDC(0);
4266 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4268 memset(&lf
, 0, sizeof(lf
));
4269 lf
.lfCharSet
= ANSI_CHARSET
;
4270 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4273 lf
.lfQuality
= DEFAULT_QUALITY
;
4274 lf
.lfItalic
= FALSE
;
4275 lf
.lfWeight
= FW_DONTCARE
;
4277 for (i
= 0; i
< sizeof(TestName
) / sizeof(TestName
[0]); i
++)
4279 if (!is_font_installed_fullname("Lucida Sans", TestName
[i
]))
4281 skip("%s is not installed\n", TestName
[i
]);
4285 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
4286 hfont
= CreateFontIndirectA(&lf
);
4287 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4289 of
= SelectObject(hdc
, hfont
);
4292 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, sizeof(bufW
), TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4293 ok(ret
, "face full name could not be read\n");
4294 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, sizeof(bufA
), NULL
, FALSE
);
4295 ok(!lstrcmpA(bufA
, TestName
[i
]), "font full names don't match: %s != %s\n", TestName
[i
], bufA
);
4296 SelectObject(hdc
, of
);
4297 DeleteObject(hfont
);
4302 static WCHAR
*prepend_at(WCHAR
*family
)
4307 memmove(family
+ 1, family
, (lstrlenW(family
) + 1) * sizeof(WCHAR
));
4312 static void test_fullname2_helper(const char *Family
)
4314 char *FamilyName
, *FaceName
, *StyleName
, *otmStr
;
4315 struct enum_fullname_data efnd
;
4322 DWORD otm_size
, ret
, buf_size
;
4323 OUTLINETEXTMETRICA
*otm
;
4324 BOOL want_vertical
, get_vertical
;
4325 want_vertical
= ( Family
[0] == '@' );
4327 hdc
= CreateCompatibleDC(0);
4328 ok(hdc
!= NULL
, "CreateCompatibleDC failed\n");
4330 memset(&lf
, 0, sizeof(lf
));
4331 lf
.lfCharSet
= DEFAULT_CHARSET
;
4332 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4335 lf
.lfQuality
= DEFAULT_QUALITY
;
4336 lf
.lfItalic
= FALSE
;
4337 lf
.lfWeight
= FW_DONTCARE
;
4338 lstrcpy(lf
.lfFaceName
, Family
);
4340 EnumFontFamiliesExA(hdc
, &lf
, enum_fullname_data_proc
, (LPARAM
)&efnd
, 0);
4341 if (efnd
.total
== 0)
4342 skip("%s is not installed\n", lf
.lfFaceName
);
4344 for (i
= 0; i
< efnd
.total
; i
++)
4346 FamilyName
= (char *)efnd
.elf
[i
].elfLogFont
.lfFaceName
;
4347 FaceName
= (char *)efnd
.elf
[i
].elfFullName
;
4348 StyleName
= (char *)efnd
.elf
[i
].elfStyle
;
4350 trace("Checking font %s:\nFamilyName: %s; FaceName: %s; StyleName: %s\n", Family
, FamilyName
, FaceName
, StyleName
);
4352 get_vertical
= ( FamilyName
[0] == '@' );
4353 ok(get_vertical
== want_vertical
, "Vertical flags don't match: %s %s\n", Family
, FamilyName
);
4355 lstrcpyA(lf
.lfFaceName
, FaceName
);
4356 hfont
= CreateFontIndirectA(&lf
);
4357 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
4359 of
= SelectObject(hdc
, hfont
);
4360 buf_size
= GetFontData(hdc
, MS_NAME_TAG
, 0, NULL
, 0);
4361 ok(buf_size
!= GDI_ERROR
, "no name table found\n");
4362 if (buf_size
== GDI_ERROR
) continue;
4364 bufW
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4365 bufA
= HeapAlloc(GetProcessHeap(), 0, buf_size
);
4367 otm_size
= GetOutlineTextMetricsA(hdc
, 0, NULL
);
4368 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
4369 memset(otm
, 0, otm_size
);
4370 ret
= GetOutlineTextMetrics(hdc
, otm_size
, otm
);
4371 ok(ret
!= 0, "GetOutlineTextMetrics fails!\n");
4372 if (ret
== 0) continue;
4376 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4379 trace("no localized FONT_FAMILY found.\n");
4380 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_FAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4382 ok(ret
, "FAMILY (family name) could not be read\n");
4383 if (want_vertical
) bufW
= prepend_at(bufW
);
4384 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4385 ok(!lstrcmpA(FamilyName
, bufA
), "font family names don't match: returned %s, expect %s\n", FamilyName
, bufA
);
4386 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFamilyName
;
4387 ok(!lstrcmpA(FamilyName
, otmStr
), "FamilyName %s doesn't match otmpFamilyName %s\n", FamilyName
, otmStr
);
4391 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, GetSystemDefaultLangID());
4394 trace("no localized FULL_NAME found.\n");
4395 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FULL_NAME
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4397 ok(ret
, "FULL_NAME (face name) could not be read\n");
4398 if (want_vertical
) bufW
= prepend_at(bufW
);
4399 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4400 ok(!lstrcmpA(FaceName
, bufA
), "font face names don't match: returned %s, expect %s\n", FaceName
, bufA
);
4401 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFaceName
;
4402 ok(!lstrcmpA(FaceName
, otmStr
), "FaceName %s doesn't match otmpFaceName %s\n", FaceName
, otmStr
);
4406 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, GetSystemDefaultLangID());
4409 trace("no localized FONT_SUBFAMILY found.\n");
4410 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_FONT_SUBFAMILY
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4412 ok(ret
, "SUBFAMILY (style name) could not be read\n");
4413 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4414 ok(!lstrcmpA(StyleName
, bufA
), "style names don't match: returned %s, expect %s\n", StyleName
, bufA
);
4415 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpStyleName
;
4416 ok(!lstrcmpA(StyleName
, otmStr
), "StyleName %s doesn't match otmpStyleName %s\n", StyleName
, otmStr
);
4420 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, GetSystemDefaultLangID());
4423 trace("no localized UNIQUE_ID found.\n");
4424 ret
= get_ttf_nametable_entry(hdc
, TT_NAME_ID_UNIQUE_ID
, bufW
, buf_size
, TT_MS_LANGID_ENGLISH_UNITED_STATES
);
4426 ok(ret
, "UNIQUE_ID (full name) could not be read\n");
4427 WideCharToMultiByte(CP_ACP
, 0, bufW
, -1, bufA
, buf_size
, NULL
, FALSE
);
4428 otmStr
= (LPSTR
)otm
+ (UINT_PTR
)otm
->otmpFullName
;
4429 ok(!lstrcmpA(otmStr
, bufA
), "UNIQUE ID (full name) doesn't match: returned %s, expect %s\n", otmStr
, bufA
);
4431 SelectObject(hdc
, of
);
4432 DeleteObject(hfont
);
4434 HeapFree(GetProcessHeap(), 0, otm
);
4435 HeapFree(GetProcessHeap(), 0, bufW
);
4436 HeapFree(GetProcessHeap(), 0, bufA
);
4441 static void test_fullname2(void)
4443 test_fullname2_helper("Arial");
4444 test_fullname2_helper("DejaVu Sans");
4445 test_fullname2_helper("Lucida Sans");
4446 test_fullname2_helper("Tahoma");
4447 test_fullname2_helper("Webdings");
4448 test_fullname2_helper("Wingdings");
4449 test_fullname2_helper("SimSun");
4450 test_fullname2_helper("NSimSun");
4451 test_fullname2_helper("MingLiu");
4452 test_fullname2_helper("PMingLiu");
4453 test_fullname2_helper("WenQuanYi Micro Hei");
4454 test_fullname2_helper("MS UI Gothic");
4455 test_fullname2_helper("Ume UI Gothic");
4456 test_fullname2_helper("MS Gothic");
4457 test_fullname2_helper("Ume Gothic");
4458 test_fullname2_helper("MS PGothic");
4459 test_fullname2_helper("Ume P Gothic");
4460 test_fullname2_helper("Gulim");
4461 test_fullname2_helper("Batang");
4462 test_fullname2_helper("UnBatang");
4463 test_fullname2_helper("UnDotum");
4464 test_fullname2_helper("@SimSun");
4465 test_fullname2_helper("@NSimSun");
4466 test_fullname2_helper("@MingLiu");
4467 test_fullname2_helper("@PMingLiu");
4468 test_fullname2_helper("@WenQuanYi Micro Hei");
4469 test_fullname2_helper("@MS UI Gothic");
4470 test_fullname2_helper("@Ume UI Gothic");
4471 test_fullname2_helper("@MS Gothic");
4472 test_fullname2_helper("@Ume Gothic");
4473 test_fullname2_helper("@MS PGothic");
4474 test_fullname2_helper("@Ume P Gothic");
4475 test_fullname2_helper("@Gulim");
4476 test_fullname2_helper("@Batang");
4477 test_fullname2_helper("@UnBatang");
4478 test_fullname2_helper("@UnDotum");
4482 static BOOL
write_ttf_file(const char *fontname
, char *tmp_name
)
4484 char tmp_path
[MAX_PATH
];
4491 SetLastError(0xdeadbeef);
4492 rsrc
= FindResource(GetModuleHandle(0), fontname
, RT_RCDATA
);
4493 ok(rsrc
!= 0, "FindResource error %d\n", GetLastError());
4494 if (!rsrc
) return FALSE
;
4495 SetLastError(0xdeadbeef);
4496 rsrc_data
= LockResource(LoadResource(GetModuleHandle(0), rsrc
));
4497 ok(rsrc_data
!= 0, "LockResource error %d\n", GetLastError());
4498 if (!rsrc_data
) return FALSE
;
4499 SetLastError(0xdeadbeef);
4500 rsrc_size
= SizeofResource(GetModuleHandle(0), rsrc
);
4501 ok(rsrc_size
!= 0, "SizeofResource error %d\n", GetLastError());
4502 if (!rsrc_size
) return FALSE
;
4504 SetLastError(0xdeadbeef);
4505 ret
= GetTempPath(MAX_PATH
, tmp_path
);
4506 ok(ret
, "GetTempPath() error %d\n", GetLastError());
4507 SetLastError(0xdeadbeef);
4508 ret
= GetTempFileName(tmp_path
, "ttf", 0, tmp_name
);
4509 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
4511 SetLastError(0xdeadbeef);
4512 hfile
= CreateFile(tmp_name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
4513 ok(hfile
!= INVALID_HANDLE_VALUE
, "CreateFile() error %d\n", GetLastError());
4514 if (hfile
== INVALID_HANDLE_VALUE
) return FALSE
;
4516 SetLastError(0xdeadbeef);
4517 ret
= WriteFile(hfile
, rsrc_data
, rsrc_size
, &rsrc_size
, NULL
);
4518 ok(ret
, "WriteFile() error %d\n", GetLastError());
4524 static void test_GetGlyphOutline_empty_contour(void)
4528 HFONT hfont
, hfont_prev
;
4529 TTPOLYGONHEADER
*header
;
4534 memset(&lf
, 0, sizeof(lf
));
4536 lstrcpyA(lf
.lfFaceName
, "wine_test");
4538 hfont
= CreateFontIndirectA(&lf
);
4539 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4543 hfont_prev
= SelectObject(hdc
, hfont
);
4544 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
4546 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
4547 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
4549 header
= (TTPOLYGONHEADER
*)buf
;
4550 ret
= GetGlyphOutlineW(hdc
, 0xa8, GGO_NATIVE
, &gm
, sizeof(buf
), buf
, &mat
);
4551 ok(ret
== 228, "GetGlyphOutline returned %d, expected 228\n", ret
);
4552 ok(header
->cb
== 36, "header->cb = %d, expected 36\n", header
->cb
);
4553 ok(header
->dwType
== TT_POLYGON_TYPE
, "header->dwType = %d, expected TT_POLYGON_TYPE\n", header
->dwType
);
4554 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
4555 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
4556 header
= (TTPOLYGONHEADER
*)((char*)header
+header
->cb
);
4557 ok(header
->cb
== 96, "header->cb = %d, expected 96\n", header
->cb
);
4559 SelectObject(hdc
, hfont_prev
);
4560 DeleteObject(hfont
);
4561 ReleaseDC(NULL
, hdc
);
4564 static void test_GetGlyphOutline_metric_clipping(void)
4568 HFONT hfont
, hfont_prev
;
4573 memset(&lf
, 0, sizeof(lf
));
4575 lstrcpyA(lf
.lfFaceName
, "wine_test");
4577 SetLastError(0xdeadbeef);
4578 hfont
= CreateFontIndirectA(&lf
);
4579 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
4583 hfont_prev
= SelectObject(hdc
, hfont
);
4584 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
4586 SetLastError(0xdeadbeef);
4587 ret
= GetTextMetrics(hdc
, &tm
);
4588 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
4590 GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4591 ok(gm
.gmptGlyphOrigin
.y
<= tm
.tmAscent
,
4592 "Glyph top(%d) exceeds ascent(%d)\n",
4593 gm
.gmptGlyphOrigin
.y
, tm
.tmAscent
);
4594 GetGlyphOutlineA(hdc
, 'D', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
4595 ok(gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
>= -tm
.tmDescent
,
4596 "Glyph bottom(%d) exceeds descent(%d)\n",
4597 gm
.gmptGlyphOrigin
.y
- gm
.gmBlackBoxY
, -tm
.tmDescent
);
4599 SelectObject(hdc
, hfont_prev
);
4600 DeleteObject(hfont
);
4601 ReleaseDC(NULL
, hdc
);
4604 static void test_CreateScalableFontResource(void)
4606 char ttf_name
[MAX_PATH
];
4607 char tmp_path
[MAX_PATH
];
4608 char fot_name
[MAX_PATH
];
4613 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
)
4615 win_skip("AddFontResourceExA is not available on this platform\n");
4619 if (!write_ttf_file("wine_test.ttf", ttf_name
))
4621 skip("Failed to create ttf file for testing\n");
4625 trace("created %s\n", ttf_name
);
4627 ret
= is_truetype_font_installed("wine_test");
4628 ok(!ret
, "font wine_test should not be enumerated\n");
4630 ret
= GetTempPath(MAX_PATH
, tmp_path
);
4631 ok(ret
, "GetTempPath() error %d\n", GetLastError());
4632 ret
= GetTempFileName(tmp_path
, "fot", 0, fot_name
);
4633 ok(ret
, "GetTempFileName() error %d\n", GetLastError());
4635 ret
= GetFileAttributes(fot_name
);
4636 ok(ret
!= INVALID_FILE_ATTRIBUTES
, "file %s does not exist\n", fot_name
);
4638 SetLastError(0xdeadbeef);
4639 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
4640 ok(!ret
, "CreateScalableFontResource() should fail\n");
4641 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4643 SetLastError(0xdeadbeef);
4644 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, "");
4645 ok(!ret
, "CreateScalableFontResource() should fail\n");
4646 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4648 file_part
= strrchr(ttf_name
, '\\');
4649 SetLastError(0xdeadbeef);
4650 ret
= CreateScalableFontResource(0, fot_name
, file_part
, tmp_path
);
4651 ok(!ret
, "CreateScalableFontResource() should fail\n");
4652 ok(GetLastError() == ERROR_FILE_EXISTS
, "not expected error %d\n", GetLastError());
4654 SetLastError(0xdeadbeef);
4655 ret
= CreateScalableFontResource(0, fot_name
, "random file name", tmp_path
);
4656 ok(!ret
, "CreateScalableFontResource() should fail\n");
4657 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
4659 SetLastError(0xdeadbeef);
4660 ret
= CreateScalableFontResource(0, fot_name
, NULL
, ttf_name
);
4661 ok(!ret
, "CreateScalableFontResource() should fail\n");
4662 ok(GetLastError() == ERROR_INVALID_PARAMETER
, "not expected error %d\n", GetLastError());
4664 ret
= DeleteFile(fot_name
);
4665 ok(ret
, "DeleteFile() error %d\n", GetLastError());
4667 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4668 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4670 /* test public font resource */
4671 SetLastError(0xdeadbeef);
4672 ret
= CreateScalableFontResource(0, fot_name
, ttf_name
, NULL
);
4673 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
4675 ret
= is_truetype_font_installed("wine_test");
4676 ok(!ret
, "font wine_test should not be enumerated\n");
4678 SetLastError(0xdeadbeef);
4679 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4680 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4682 ret
= is_truetype_font_installed("wine_test");
4683 ok(ret
, "font wine_test should be enumerated\n");
4685 test_GetGlyphOutline_empty_contour();
4686 test_GetGlyphOutline_metric_clipping();
4688 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4689 ok(!ret
, "RemoveFontResourceEx() with not matching flags should fail\n");
4691 SetLastError(0xdeadbeef);
4692 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4693 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4695 ret
= is_truetype_font_installed("wine_test");
4696 ok(!ret
, "font wine_test should not be enumerated\n");
4698 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4699 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4701 /* test refcounting */
4702 for (i
= 0; i
< 5; i
++)
4704 SetLastError(0xdeadbeef);
4705 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4706 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4708 for (i
= 0; i
< 5; i
++)
4710 SetLastError(0xdeadbeef);
4711 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4712 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4714 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4715 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4717 DeleteFile(fot_name
);
4719 /* test hidden font resource */
4720 SetLastError(0xdeadbeef);
4721 ret
= CreateScalableFontResource(1, fot_name
, ttf_name
, NULL
);
4722 ok(ret
, "CreateScalableFontResource() error %d\n", GetLastError());
4724 ret
= is_truetype_font_installed("wine_test");
4725 ok(!ret
, "font wine_test should not be enumerated\n");
4727 SetLastError(0xdeadbeef);
4728 ret
= pAddFontResourceExA(fot_name
, 0, 0);
4729 ok(ret
, "AddFontResourceEx() error %d\n", GetLastError());
4731 ret
= is_truetype_font_installed("wine_test");
4733 ok(!ret
, "font wine_test should not be enumerated\n");
4735 /* XP allows removing a private font added with 0 flags */
4736 SetLastError(0xdeadbeef);
4737 ret
= pRemoveFontResourceExA(fot_name
, FR_PRIVATE
, 0);
4738 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4740 ret
= is_truetype_font_installed("wine_test");
4741 ok(!ret
, "font wine_test should not be enumerated\n");
4743 ret
= pRemoveFontResourceExA(fot_name
, 0, 0);
4744 ok(!ret
, "RemoveFontResourceEx() should fail\n");
4746 DeleteFile(fot_name
);
4747 DeleteFile(ttf_name
);
4750 static void check_vertical_font(const char *name
, BOOL
*installed
, BOOL
*selected
, GLYPHMETRICS
*gm
, WORD
*gi
)
4753 HFONT hfont
, hfont_prev
;
4757 static const WCHAR str
[] = { 0x2025 };
4759 *installed
= is_truetype_font_installed(name
);
4763 lf
.lfEscapement
= 0;
4764 lf
.lfOrientation
= 0;
4765 lf
.lfWeight
= FW_DONTCARE
;
4769 lf
.lfCharSet
= DEFAULT_CHARSET
;
4770 lf
.lfOutPrecision
= OUT_TT_ONLY_PRECIS
;
4771 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
4772 lf
.lfQuality
= DEFAULT_QUALITY
;
4773 lf
.lfPitchAndFamily
= DEFAULT_PITCH
| FF_DONTCARE
;
4774 strcpy(lf
.lfFaceName
, name
);
4776 hfont
= CreateFontIndirectA(&lf
);
4777 ok(hfont
!= NULL
, "CreateFontIndirectA failed\n");
4781 hfont_prev
= SelectObject(hdc
, hfont
);
4782 ok(hfont_prev
!= NULL
, "SelectObject failed\n");
4784 ret
= GetTextFaceA(hdc
, sizeof facename
, facename
);
4785 ok(ret
, "GetTextFaceA failed\n");
4786 *selected
= !strcmp(facename
, name
);
4788 ret
= GetGlyphOutlineW(hdc
, 0x2025, GGO_METRICS
, gm
, 0, NULL
, &mat
);
4789 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW failed\n");
4791 memset(gm
, 0, sizeof *gm
);
4793 ret
= pGetGlyphIndicesW(hdc
, str
, 1, gi
, 0);
4794 ok(ret
!= GDI_ERROR
, "GetGlyphIndicesW failed\n");
4796 SelectObject(hdc
, hfont_prev
);
4797 DeleteObject(hfont
);
4798 ReleaseDC(NULL
, hdc
);
4801 static void test_vertical_font(void)
4803 char ttf_name
[MAX_PATH
];
4805 BOOL ret
, installed
, selected
;
4809 if (!pAddFontResourceExA
|| !pRemoveFontResourceExA
|| !pGetGlyphIndicesW
)
4811 win_skip("AddFontResourceExA or GetGlyphIndicesW is not available on this platform\n");
4815 if (!write_ttf_file("vertical.ttf", ttf_name
))
4817 skip("Failed to create ttf file for testing\n");
4821 num
= pAddFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
4822 ok(num
== 2, "AddFontResourceExA should add 2 fonts from vertical.ttf\n");
4824 check_vertical_font("@WineTestVertical", &installed
, &selected
, &gm
, &hgi
);
4825 ok(installed
, "@WineTestVertical is not installed\n");
4826 ok(selected
, "@WineTestVertical is not selected\n");
4827 ok(gm
.gmBlackBoxX
> gm
.gmBlackBoxY
,
4828 "gmBlackBoxX(%u) should be greater than gmBlackBoxY(%u) if horizontal\n",
4829 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
4831 check_vertical_font("@@WineTestVertical", &installed
, &selected
, &gm
, &vgi
);
4832 ok(installed
, "@@WineTestVertical is not installed\n");
4833 ok(selected
, "@@WineTestVertical is not selected\n");
4834 ok(gm
.gmBlackBoxX
< gm
.gmBlackBoxY
,
4835 "gmBlackBoxX(%u) should be less than gmBlackBoxY(%u) if vertical\n",
4836 gm
.gmBlackBoxX
, gm
.gmBlackBoxY
);
4838 ok(hgi
== vgi
, "different glyph h:%u v:%u\n", hgi
, vgi
);
4840 ret
= pRemoveFontResourceExA(ttf_name
, FR_PRIVATE
, 0);
4841 ok(ret
, "RemoveFontResourceEx() error %d\n", GetLastError());
4843 DeleteFile(ttf_name
);
4846 static INT CALLBACK
has_vertical_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
,
4847 DWORD type
, LPARAM lParam
)
4849 if (lf
->lfFaceName
[0] == '@') {
4855 static void test_east_asian_font_selection(void)
4858 UINT charset
[] = { SHIFTJIS_CHARSET
, HANGEUL_CHARSET
, JOHAB_CHARSET
,
4859 GB2312_CHARSET
, CHINESEBIG5_CHARSET
};
4864 for (i
= 0; i
< sizeof(charset
)/sizeof(charset
[0]); i
++)
4868 char face_name
[LF_FACESIZE
];
4871 memset(&lf
, 0, sizeof lf
);
4872 lf
.lfFaceName
[0] = '\0';
4873 lf
.lfCharSet
= charset
[i
];
4875 if (EnumFontFamiliesEx(hdc
, &lf
, has_vertical_font_proc
, 0, 0))
4877 skip("Vertical font for charset %u is not installed\n", charset
[i
]);
4881 hfont
= CreateFontIndirectA(&lf
);
4882 hfont
= SelectObject(hdc
, hfont
);
4883 memset(face_name
, 0, sizeof face_name
);
4884 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
4885 ok(ret
&& face_name
[0] != '@',
4886 "expected non-vertical face for charset %u, got %s\n", charset
[i
], face_name
);
4887 DeleteObject(SelectObject(hdc
, hfont
));
4889 memset(&lf
, 0, sizeof lf
);
4890 strcpy(lf
.lfFaceName
, "@");
4891 lf
.lfCharSet
= charset
[i
];
4892 hfont
= CreateFontIndirectA(&lf
);
4893 hfont
= SelectObject(hdc
, hfont
);
4894 memset(face_name
, 0, sizeof face_name
);
4895 ret
= GetTextFaceA(hdc
, sizeof face_name
, face_name
);
4896 ok(ret
&& face_name
[0] == '@',
4897 "expected vertical face for charset %u, got %s\n", charset
[i
], face_name
);
4898 DeleteObject(SelectObject(hdc
, hfont
));
4900 ReleaseDC(NULL
, hdc
);
4903 static int get_font_dpi(const LOGFONT
*lf
)
4905 HDC hdc
= CreateCompatibleDC(0);
4910 hfont
= CreateFontIndirect(lf
);
4911 ok(hfont
!= 0, "CreateFontIndirect failed\n");
4913 SelectObject(hdc
, hfont
);
4914 ret
= GetTextMetrics(hdc
, &tm
);
4915 ok(ret
, "GetTextMetrics failed\n");
4916 ret
= tm
.tmDigitizedAspectX
;
4919 DeleteObject(hfont
);
4924 static void test_stock_fonts(void)
4926 static const int font
[] =
4928 ANSI_FIXED_FONT
, ANSI_VAR_FONT
, SYSTEM_FONT
, DEVICE_DEFAULT_FONT
, DEFAULT_GUI_FONT
4929 /* SYSTEM_FIXED_FONT, OEM_FIXED_FONT */
4931 static const struct test_data
4933 int charset
, weight
, height
, dpi
;
4934 const char face_name
[LF_FACESIZE
];
4937 { /* ANSI_FIXED_FONT */
4938 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 96, "Courier" },
4939 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 120, "Courier" },
4942 { /* ANSI_VAR_FONT */
4943 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 96, "MS Sans Serif" },
4944 { DEFAULT_CHARSET
, FW_NORMAL
, 12, 120, "MS Sans Serif" },
4948 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 96, "System" },
4949 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 120, "System" },
4950 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 96, "System" },
4951 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 120, "System" },
4952 { DEFAULT_CHARSET
, FW_BOLD
, 16, 96, "System" },
4953 { DEFAULT_CHARSET
, FW_BOLD
, 20, 120, "System" },
4956 { /* DEVICE_DEFAULT_FONT */
4957 { SHIFTJIS_CHARSET
, FW_NORMAL
, 18, 96, "System" },
4958 { SHIFTJIS_CHARSET
, FW_NORMAL
, 22, 120, "System" },
4959 { HANGEUL_CHARSET
, FW_NORMAL
, 16, 96, "System" },
4960 { HANGEUL_CHARSET
, FW_NORMAL
, 20, 120, "System" },
4961 { DEFAULT_CHARSET
, FW_BOLD
, 16, 96, "System" },
4962 { DEFAULT_CHARSET
, FW_BOLD
, 20, 120, "System" },
4965 { /* DEFAULT_GUI_FONT */
4966 { SHIFTJIS_CHARSET
, FW_NORMAL
, -12, 96, "?MS UI Gothic" },
4967 { SHIFTJIS_CHARSET
, FW_NORMAL
, -15, 120, "?MS UI Gothic" },
4968 { HANGEUL_CHARSET
, FW_NORMAL
, -12, 96, "?Gulim" },
4969 { HANGEUL_CHARSET
, FW_NORMAL
, -15, 120, "?Gulim" },
4970 { GB2312_CHARSET
, FW_NORMAL
, -12, 96, "?SimHei" },
4971 { GB2312_CHARSET
, FW_NORMAL
, -15, 120, "?SimHei" },
4972 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -12, 96, "?MingLiU" },
4973 { CHINESEBIG5_CHARSET
, FW_NORMAL
, -15, 120, "?MingLiU" },
4974 { DEFAULT_CHARSET
, FW_NORMAL
, -11, 96, "MS Shell Dlg" },
4975 { DEFAULT_CHARSET
, FW_NORMAL
, -13, 120, "MS Shell Dlg" },
4981 for (i
= 0; i
< sizeof(font
)/sizeof(font
[0]); i
++)
4987 hfont
= GetStockObject(font
[i
]);
4988 ok(hfont
!= 0, "%d: GetStockObject(%d) failed\n", i
, font
[i
]);
4990 ret
= GetObject(hfont
, sizeof(lf
), &lf
);
4991 if (ret
!= sizeof(lf
))
4994 win_skip("%d: GetObject returned %d instead of sizeof(LOGFONT)\n", i
, ret
);
4998 for (j
= 0; td
[i
][j
].face_name
[0] != 0; j
++)
5000 if (lf
.lfCharSet
!= td
[i
][j
].charset
&& td
[i
][j
].charset
!= DEFAULT_CHARSET
)
5005 ret
= get_font_dpi(&lf
);
5006 if (ret
!= td
[i
][j
].dpi
)
5008 trace("%d(%d): font %s %d dpi doesn't match test data %d\n",
5009 i
, j
, lf
.lfFaceName
, ret
, td
[i
][j
].dpi
);
5013 ok(td
[i
][j
].weight
== lf
.lfWeight
, "%d(%d): expected lfWeight %d, got %d\n", i
, j
, td
[i
][j
].weight
, lf
.lfWeight
);
5014 ok(td
[i
][j
].height
== lf
.lfHeight
, "%d(%d): expected lfHeight %d, got %d\n", i
, j
, td
[i
][j
].height
, lf
.lfHeight
);
5015 if (td
[i
][j
].face_name
[0] == '?')
5017 /* Wine doesn't have this font, skip this case for now.
5018 Actually, the face name is localized on Windows and varies
5019 dpending on Windows versions (e.g. Japanese NT4 vs win2k). */
5020 trace("%d(%d): default gui font is %s\n", i
, j
, lf
.lfFaceName
);
5024 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
);
5031 static void test_max_height(void)
5035 HFONT hfont
, hfont_old
;
5036 TEXTMETRICA tm1
, tm
;
5038 LONG invalid_height
[] = { -65536, -123456, 123456 };
5041 memset(&tm1
, 0, sizeof(tm1
));
5042 memset(&lf
, 0, sizeof(lf
));
5043 strcpy(lf
.lfFaceName
, "Tahoma");
5048 /* get 1 ppem value */
5049 hfont
= CreateFontIndirect(&lf
);
5050 hfont_old
= SelectObject(hdc
, hfont
);
5051 r
= GetTextMetrics(hdc
, &tm1
);
5052 ok(r
, "GetTextMetrics failed\n");
5053 ok(tm1
.tmHeight
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5054 ok(tm1
.tmAveCharWidth
> 0, "expected a positive value, got %d\n", tm1
.tmHeight
);
5055 DeleteObject(SelectObject(hdc
, hfont_old
));
5057 /* test the largest value */
5058 lf
.lfHeight
= -((1 << 16) - 1);
5059 hfont
= CreateFontIndirect(&lf
);
5060 hfont_old
= SelectObject(hdc
, hfont
);
5061 memset(&tm
, 0, sizeof(tm
));
5062 r
= GetTextMetrics(hdc
, &tm
);
5063 ok(r
, "GetTextMetrics failed\n");
5064 ok(tm
.tmHeight
> tm1
.tmHeight
,
5065 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5066 ok(tm
.tmAveCharWidth
> tm1
.tmAveCharWidth
,
5067 "expected greater than 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5068 DeleteObject(SelectObject(hdc
, hfont_old
));
5070 /* test an invalid value */
5071 for (i
= 0; i
< sizeof(invalid_height
)/sizeof(invalid_height
[0]); i
++) {
5072 lf
.lfHeight
= invalid_height
[i
];
5073 hfont
= CreateFontIndirect(&lf
);
5074 hfont_old
= SelectObject(hdc
, hfont
);
5075 memset(&tm
, 0, sizeof(tm
));
5076 r
= GetTextMetrics(hdc
, &tm
);
5077 ok(r
, "GetTextMetrics failed\n");
5078 ok(tm
.tmHeight
== tm1
.tmHeight
,
5079 "expected 1 ppem value (%d), got %d\n", tm1
.tmHeight
, tm
.tmHeight
);
5080 ok(tm
.tmAveCharWidth
== tm1
.tmAveCharWidth
,
5081 "expected 1 ppem value (%d), got %d\n", tm1
.tmAveCharWidth
, tm
.tmAveCharWidth
);
5082 DeleteObject(SelectObject(hdc
, hfont_old
));
5085 ReleaseDC(NULL
, hdc
);
5096 test_outline_font();
5097 test_bitmap_font_metrics();
5098 test_GdiGetCharDimensions();
5099 test_GetCharABCWidths();
5100 test_text_extents();
5101 test_GetGlyphIndices();
5102 test_GetKerningPairs();
5103 test_GetOutlineTextMetrics();
5104 test_SetTextJustification();
5105 test_font_charset();
5106 test_GdiGetCodePage();
5107 test_GetFontUnicodeRanges();
5108 test_nonexistent_font();
5110 test_height_selection();
5111 test_AddFontMemResource();
5114 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
5115 * I'd like to avoid them in this test.
5117 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
5118 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
5119 if (is_truetype_font_installed("Arial Black") &&
5120 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
5122 test_EnumFontFamilies("", ANSI_CHARSET
);
5123 test_EnumFontFamilies("", SYMBOL_CHARSET
);
5124 test_EnumFontFamilies("", DEFAULT_CHARSET
);
5127 skip("Arial Black or Symbol/Wingdings is not installed\n");
5128 test_EnumFontFamiliesEx_default_charset();
5129 test_GetTextMetrics();
5130 test_GdiRealizationInfo();
5132 test_GetGlyphOutline();
5133 test_GetTextMetrics2("Tahoma", -11);
5134 test_GetTextMetrics2("Tahoma", -55);
5135 test_GetTextMetrics2("Tahoma", -110);
5136 test_GetTextMetrics2("Arial", -11);
5137 test_GetTextMetrics2("Arial", -55);
5138 test_GetTextMetrics2("Arial", -110);
5139 test_CreateFontIndirect();
5140 test_CreateFontIndirectEx();
5144 test_east_asian_font_selection();
5147 /* These tests should be last test until RemoveFontResource
5148 * is properly implemented.
5150 test_vertical_font();
5151 test_CreateScalableFontResource();