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 LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
40 BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
41 BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
42 DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
43 DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
44 DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
45 BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
46 HFONT (WINAPI
*pCreateFontIndirectExA
)(const ENUMLOGFONTEXDV
*);
48 static HMODULE hgdi32
= 0;
50 static void init(void)
52 hgdi32
= GetModuleHandleA("gdi32.dll");
54 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
55 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
56 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
57 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
58 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
59 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
60 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
61 pCreateFontIndirectExA
= (void *)GetProcAddress(hgdi32
, "CreateFontIndirectExA");
64 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
66 if (type
!= TRUETYPE_FONTTYPE
) return 1;
71 static BOOL
is_truetype_font_installed(const char *name
)
76 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
83 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
88 static BOOL
is_font_installed(const char *name
)
93 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
100 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
108 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
109 /* NT4 tries to be clever and only returns the minimum length */
110 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
112 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
113 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
114 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
115 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
116 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
117 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
118 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
119 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
120 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
121 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
122 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
123 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
124 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
125 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
126 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
127 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
128 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
129 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
130 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
131 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
132 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
133 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
134 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
135 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
136 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
137 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
138 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
139 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
142 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
144 HFONT hfont
= CreateFontIndirectA(lf
);
145 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
147 check_font(test
, lf
, hfont
);
151 static void test_logfont(void)
156 memset(&lf
, 0, sizeof lf
);
158 lf
.lfCharSet
= ANSI_CHARSET
;
159 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
160 lf
.lfWeight
= FW_DONTCARE
;
163 lf
.lfQuality
= DEFAULT_QUALITY
;
165 lstrcpyA(lf
.lfFaceName
, "Arial");
166 hfont
= create_font("Arial", &lf
);
169 memset(&lf
, 'A', sizeof(lf
));
170 hfont
= CreateFontIndirectA(&lf
);
171 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
173 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
174 check_font("AAA...", &lf
, hfont
);
178 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
180 if (type
& RASTER_FONTTYPE
)
182 LOGFONT
*lf
= (LOGFONT
*)lParam
;
184 return 0; /* stop enumeration */
187 return 1; /* continue enumeration */
190 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
192 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
193 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
194 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
195 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
196 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
197 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
198 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
199 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
200 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
201 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
202 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
203 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
204 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
205 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
206 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
207 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
208 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
209 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
210 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
211 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
214 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
215 LONG lfWidth
, const char *test_str
,
216 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
217 const SIZE
*size_orig
, INT width_of_A_orig
,
218 INT scale_x
, INT scale_y
)
221 OUTLINETEXTMETRIC otm
;
224 INT width_of_A
, cx
, cy
;
230 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
232 GetObjectA(hfont
, sizeof(lf
), &lf
);
234 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
236 otm
.otmSize
= sizeof(otm
) / 2;
237 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
238 ok(ret
== sizeof(otm
)/2 /* XP */ ||
239 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
241 memset(&otm
, 0x1, sizeof(otm
));
242 otm
.otmSize
= sizeof(otm
);
243 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
244 ok(ret
== sizeof(otm
) /* XP */ ||
245 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
247 memset(&tm
, 0x2, sizeof(tm
));
248 ret
= GetTextMetricsA(hdc
, &tm
);
249 ok(ret
, "GetTextMetricsA failed\n");
250 /* the structure size is aligned */
251 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
253 ok(0, "tm != otm\n");
254 compare_tm(&tm
, &otm
.otmTextMetrics
);
257 tm
= otm
.otmTextMetrics
;
258 if (0) /* these metrics are scaled too, but with rounding errors */
260 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
261 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
263 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
264 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
265 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
266 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
267 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
268 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
272 ret
= GetTextMetricsA(hdc
, &tm
);
273 ok(ret
, "GetTextMetricsA failed\n");
276 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
277 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
278 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
279 lfHeight
, scale_x
, scale_y
, cx
, cy
);
280 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
281 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
282 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
283 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
284 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
286 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
290 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
293 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
295 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
297 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
298 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
300 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
302 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
);
305 /* Test how GDI scales bitmap font metrics */
306 static void test_bitmap_font(void)
308 static const char test_str
[11] = "Test String";
311 HFONT hfont
, old_hfont
;
314 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
316 skip("ROS-HACK: Skipping bitmap font tests!\n");
321 /* "System" has only 1 pixel size defined, otherwise the test breaks */
322 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
326 trace("no bitmap fonts were found, skipping the test\n");
330 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
332 height_orig
= bitmap_lf
.lfHeight
;
333 lfWidth
= bitmap_lf
.lfWidth
;
335 hfont
= create_font("bitmap", &bitmap_lf
);
336 old_hfont
= SelectObject(hdc
, hfont
);
337 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
338 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
339 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
340 SelectObject(hdc
, old_hfont
);
343 bitmap_lf
.lfHeight
= 0;
344 bitmap_lf
.lfWidth
= 4;
345 hfont
= create_font("bitmap", &bitmap_lf
);
346 old_hfont
= SelectObject(hdc
, hfont
);
347 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
348 SelectObject(hdc
, old_hfont
);
351 bitmap_lf
.lfHeight
= height_orig
;
352 bitmap_lf
.lfWidth
= lfWidth
;
354 /* test fractional scaling */
355 for (i
= 1; i
<= height_orig
* 6; i
++)
359 bitmap_lf
.lfHeight
= i
;
360 hfont
= create_font("fractional", &bitmap_lf
);
361 scale
= (i
+ height_orig
- 1) / height_orig
;
362 nearest_height
= scale
* height_orig
;
363 /* Only jump to the next height if the difference <= 25% original height */
364 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
365 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
366 so we'll not test this particular height. */
367 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
368 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
369 old_hfont
= SelectObject(hdc
, hfont
);
370 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
371 SelectObject(hdc
, old_hfont
);
375 /* test integer scaling 3x2 */
376 bitmap_lf
.lfHeight
= height_orig
* 2;
377 bitmap_lf
.lfWidth
*= 3;
378 hfont
= create_font("3x2", &bitmap_lf
);
379 old_hfont
= SelectObject(hdc
, hfont
);
380 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
381 SelectObject(hdc
, old_hfont
);
384 /* test integer scaling 3x3 */
385 bitmap_lf
.lfHeight
= height_orig
* 3;
386 bitmap_lf
.lfWidth
= 0;
387 hfont
= create_font("3x3", &bitmap_lf
);
388 old_hfont
= SelectObject(hdc
, hfont
);
389 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
390 SelectObject(hdc
, old_hfont
);
396 /* Test how GDI scales outline font metrics */
397 static void test_outline_font(void)
399 static const char test_str
[11] = "Test String";
402 HFONT hfont
, old_hfont
, old_hfont_2
;
403 OUTLINETEXTMETRICA otm
;
405 INT width_orig
, height_orig
, lfWidth
;
408 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
409 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
413 if (!is_truetype_font_installed("Arial"))
415 skip("Arial is not installed\n");
419 hdc
= CreateCompatibleDC(0);
421 memset(&lf
, 0, sizeof(lf
));
422 strcpy(lf
.lfFaceName
, "Arial");
424 hfont
= create_font("outline", &lf
);
425 old_hfont
= SelectObject(hdc
, hfont
);
426 otm
.otmSize
= sizeof(otm
);
427 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
428 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
429 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
431 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
432 SelectObject(hdc
, old_hfont
);
435 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
436 lf
.lfHeight
= otm
.otmEMSquare
;
437 lf
.lfHeight
= -lf
.lfHeight
;
438 hfont
= create_font("outline", &lf
);
439 old_hfont
= SelectObject(hdc
, hfont
);
440 otm
.otmSize
= sizeof(otm
);
441 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
442 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
443 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
444 SelectObject(hdc
, old_hfont
);
447 height_orig
= otm
.otmTextMetrics
.tmHeight
;
448 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
450 /* test integer scaling 3x2 */
451 lf
.lfHeight
= height_orig
* 2;
452 lf
.lfWidth
= lfWidth
* 3;
453 hfont
= create_font("3x2", &lf
);
454 old_hfont
= SelectObject(hdc
, hfont
);
455 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
456 SelectObject(hdc
, old_hfont
);
459 /* test integer scaling 3x3 */
460 lf
.lfHeight
= height_orig
* 3;
461 lf
.lfWidth
= lfWidth
* 3;
462 hfont
= create_font("3x3", &lf
);
463 old_hfont
= SelectObject(hdc
, hfont
);
464 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
465 SelectObject(hdc
, old_hfont
);
468 /* test integer scaling 1x1 */
469 lf
.lfHeight
= height_orig
* 1;
470 lf
.lfWidth
= lfWidth
* 1;
471 hfont
= create_font("1x1", &lf
);
472 old_hfont
= SelectObject(hdc
, hfont
);
473 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
474 SelectObject(hdc
, old_hfont
);
477 /* test integer scaling 1x1 */
478 lf
.lfHeight
= height_orig
;
480 hfont
= create_font("1x1", &lf
);
481 old_hfont
= SelectObject(hdc
, hfont
);
482 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
484 /* with an identity matrix */
485 memset(&gm
, 0, sizeof(gm
));
486 SetLastError(0xdeadbeef);
487 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
488 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
489 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
490 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
491 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
492 /* with a custom matrix */
493 memset(&gm
, 0, sizeof(gm
));
494 SetLastError(0xdeadbeef);
495 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
496 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
497 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
498 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
499 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
501 /* Test that changing the DC transformation affects only the font
502 * selected on this DC and doesn't affect the same font selected on
505 hdc_2
= CreateCompatibleDC(0);
506 old_hfont_2
= SelectObject(hdc_2
, hfont
);
507 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
509 SetMapMode(hdc
, MM_ANISOTROPIC
);
511 /* font metrics on another DC should be unchanged */
512 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
514 /* test restrictions of compatibility mode GM_COMPATIBLE */
515 /* part 1: rescaling only X should not change font scaling on screen.
516 So compressing the X axis by 2 is not done, and this
517 appears as X scaling of 2 that no one requested. */
518 SetWindowExtEx(hdc
, 100, 100, NULL
);
519 SetViewportExtEx(hdc
, 50, 100, NULL
);
520 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
521 /* font metrics on another DC should be unchanged */
522 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
524 /* part 2: rescaling only Y should change font scaling.
525 As also X is scaled by a factor of 2, but this is not
526 requested by the DC transformation, we get a scaling factor
527 of 2 in the X coordinate. */
528 SetViewportExtEx(hdc
, 100, 200, NULL
);
529 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
530 /* font metrics on another DC should be unchanged */
531 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
533 /* restore scaling */
534 SetMapMode(hdc
, MM_TEXT
);
536 /* font metrics on another DC should be unchanged */
537 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
539 SelectObject(hdc_2
, old_hfont_2
);
542 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
544 SelectObject(hdc
, old_hfont
);
547 skip("GM_ADVANCED is not supported on this platform\n");
558 SetLastError(0xdeadbeef);
559 ret
= SetWorldTransform(hdc
, &xform
);
560 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
562 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
564 /* with an identity matrix */
565 memset(&gm
, 0, sizeof(gm
));
566 SetLastError(0xdeadbeef);
567 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
568 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
569 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
570 pt
.x
= width_orig
; pt
.y
= 0;
572 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
573 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
574 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
575 /* with a custom matrix */
576 memset(&gm
, 0, sizeof(gm
));
577 SetLastError(0xdeadbeef);
578 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
579 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
580 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
581 pt
.x
= width_orig
; pt
.y
= 0;
583 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
584 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
585 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
587 SetLastError(0xdeadbeef);
588 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
589 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
591 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
593 /* with an identity matrix */
594 memset(&gm
, 0, sizeof(gm
));
595 SetLastError(0xdeadbeef);
596 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
597 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
598 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
599 pt
.x
= width_orig
; pt
.y
= 0;
601 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
602 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
603 /* with a custom matrix */
604 memset(&gm
, 0, sizeof(gm
));
605 SetLastError(0xdeadbeef);
606 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
607 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
608 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
609 pt
.x
= width_orig
; pt
.y
= 0;
611 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
612 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
614 SetLastError(0xdeadbeef);
615 ret
= SetMapMode(hdc
, MM_TEXT
);
616 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
618 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
620 /* with an identity matrix */
621 memset(&gm
, 0, sizeof(gm
));
622 SetLastError(0xdeadbeef);
623 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
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(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
629 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
630 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
631 /* with a custom matrix */
632 memset(&gm
, 0, sizeof(gm
));
633 SetLastError(0xdeadbeef);
634 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
635 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
636 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
637 pt
.x
= width_orig
; pt
.y
= 0;
639 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
640 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
641 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
643 SelectObject(hdc
, old_hfont
);
648 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
650 LOGFONT
*lf
= (LOGFONT
*)lParam
;
652 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
655 return 0; /* stop enumeration */
657 return 1; /* continue enumeration */
660 static void test_bitmap_font_metrics(void)
662 static const struct font_data
664 const char face_name
[LF_FACESIZE
];
665 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
666 int ave_char_width
, max_char_width
, dpi
;
670 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
671 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
672 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1
| FS_CYRILLIC
},
673 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2
},
674 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1
},
675 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2
},
676 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC
},
677 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1
},
678 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2
},
679 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC
},
680 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
682 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
683 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_LATIN2
},
684 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC
},
685 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
686 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1
| FS_LATIN2
},
687 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC
},
688 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
689 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
691 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
692 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
693 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
694 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
},
695 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2
| FS_CYRILLIC
},
696 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1
| FS_LATIN2
},
697 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC
},
698 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1
| FS_LATIN2
},
699 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC
},
700 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1
},
701 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2
},
702 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC
},
703 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1
},
704 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2
},
705 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC
},
706 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1
| FS_LATIN2
},
707 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC
},
709 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1
| FS_CYRILLIC
},
710 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2
},
711 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_CYRILLIC
},
712 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2
},
713 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1
| FS_CYRILLIC
},
714 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2
},
715 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1
| FS_LATIN2
},
716 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC
},
717 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1
| FS_LATIN2
},
718 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC
},
719 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
721 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
722 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
723 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
725 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
726 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
727 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
729 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
},
730 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2
| FS_CYRILLIC
},
732 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
733 * require a new system.sfd for that font
735 { "System", FW_BOLD
, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN
},
737 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1
},
738 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2
| FS_CYRILLIC
},
740 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1
},
741 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
742 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN
},
743 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1
},
744 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
745 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN
},
746 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1
},
747 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
748 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN
},
749 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1
},
750 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
751 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN
},
752 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
753 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
754 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN
},
755 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
756 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN
},
758 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1
| FS_JISJAPAN
},
759 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
760 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1
| FS_JISJAPAN
},
761 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
762 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1
| FS_JISJAPAN
},
763 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
764 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
765 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC
},
766 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
767 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC
},
768 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
769 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC
},
771 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
},
772 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC
},
773 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN
},
775 /* The 120dpi version still has its dpi marked as 96 */
776 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
778 /* FIXME: add "Terminal" */
782 HFONT hfont
, old_hfont
;
786 hdc
= CreateCompatibleDC(0);
789 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
793 memset(&lf
, 0, sizeof(lf
));
795 lf
.lfHeight
= fd
[i
].height
;
796 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
798 for(bit
= 0; bit
< 32; bit
++)
805 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
806 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
808 lf
.lfCharSet
= csi
.ciCharset
;
809 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
812 hfont
= create_font(lf
.lfFaceName
, &lf
);
813 old_hfont
= SelectObject(hdc
, hfont
);
814 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %d\n", GetLastError());
815 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
817 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
818 ok(tm
.tmWeight
== fd
[i
].weight
, "%s(%d): tm.tmWeight %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmWeight
, fd
[i
].weight
);
819 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
);
820 ok(tm
.tmAscent
== fd
[i
].ascent
, "%s(%d): tm.tmAscent %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmAscent
, fd
[i
].ascent
);
821 ok(tm
.tmDescent
== fd
[i
].descent
, "%s(%d): tm.tmDescent %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmDescent
, fd
[i
].descent
);
822 ok(tm
.tmInternalLeading
== fd
[i
].int_leading
, "%s(%d): tm.tmInternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmInternalLeading
, fd
[i
].int_leading
);
823 ok(tm
.tmExternalLeading
== fd
[i
].ext_leading
, "%s(%d): tm.tmExternalLeading %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmExternalLeading
, fd
[i
].ext_leading
);
824 ok(tm
.tmAveCharWidth
== fd
[i
].ave_char_width
, "%s(%d): tm.tmAveCharWidth %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmAveCharWidth
, fd
[i
].ave_char_width
);
826 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
827 that make the max width bigger */
828 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
829 ok(tm
.tmMaxCharWidth
== fd
[i
].max_char_width
, "%s(%d): tm.tmMaxCharWidth %d != %d\n", fd
[i
].face_name
, fd
[i
].height
, tm
.tmMaxCharWidth
, fd
[i
].max_char_width
);
831 SelectObject(hdc
, old_hfont
);
839 static void test_GdiGetCharDimensions(void)
845 LONG avgwidth
, height
;
846 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
848 if (!pGdiGetCharDimensions
)
850 win_skip("GdiGetCharDimensions not available on this platform\n");
854 hdc
= CreateCompatibleDC(NULL
);
856 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
857 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
859 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
860 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
861 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
863 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
864 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
866 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
867 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
870 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
871 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
872 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
877 static void test_GetCharABCWidths(void)
879 static const WCHAR str
[] = {'a',0};
888 if (!pGetCharABCWidthsW
|| !pGetCharABCWidthsI
)
890 win_skip("GetCharABCWidthsW/I not available on this platform\n");
894 memset(&lf
, 0, sizeof(lf
));
895 strcpy(lf
.lfFaceName
, "System");
898 hfont
= CreateFontIndirectA(&lf
);
900 hfont
= SelectObject(hdc
, hfont
);
902 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
903 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
905 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
906 ok(!ret
, "GetCharABCWidthsI should have failed\n");
908 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
909 ok(!ret
, "GetCharABCWidthsI should have failed\n");
911 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
912 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
914 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
915 ok(!ret
, "GetCharABCWidthsW should have failed\n");
917 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
918 ok(!ret
, "GetCharABCWidthsW should have failed\n");
920 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
921 ok(!ret
, "GetCharABCWidthsW should have failed\n");
923 hfont
= SelectObject(hdc
, hfont
);
925 ReleaseDC(NULL
, hdc
);
928 static void test_text_extents(void)
930 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
932 INT i
, len
, fit1
, fit2
;
940 memset(&lf
, 0, sizeof(lf
));
941 strcpy(lf
.lfFaceName
, "Arial");
944 hfont
= CreateFontIndirectA(&lf
);
946 hfont
= SelectObject(hdc
, hfont
);
947 GetTextMetricsA(hdc
, &tm
);
948 GetTextExtentPointA(hdc
, "o", 1, &sz
);
949 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
951 SetLastError(0xdeadbeef);
952 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
953 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
955 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
956 hfont
= SelectObject(hdc
, hfont
);
963 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
964 extents
[0] = 1; /* So that the increasing sequence test will fail
965 if the extents array is untouched. */
966 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
967 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
969 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
970 /* Because of the '\n' in the string GetTextExtentExPoint and
971 GetTextExtentPoint return different widths under Win2k, but
972 under WinXP they return the same width. So we don't test that
975 for (i
= 1; i
< len
; ++i
)
976 ok(extents
[i
-1] <= extents
[i
],
977 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
979 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
980 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
981 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
982 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
983 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
984 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
985 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
986 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
987 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
988 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
989 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
990 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
991 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
992 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
993 HeapFree(GetProcessHeap(), 0, extents
);
995 hfont
= SelectObject(hdc
, hfont
);
997 ReleaseDC(NULL
, hdc
);
1000 static void test_GetGlyphIndices(void)
1007 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1008 WORD glyphs
[(sizeof(testtext
)/2)-1];
1012 if (!pGetGlyphIndicesW
) {
1013 win_skip("GetGlyphIndicesW not available on platform\n");
1019 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1020 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1021 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1022 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1023 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1025 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1026 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1027 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1028 textm
.tmDefaultChar
, glyphs
[4]);
1030 if(!is_font_installed("Tahoma"))
1032 skip("Tahoma is not installed so skipping this test\n");
1035 memset(&lf
, 0, sizeof(lf
));
1036 strcpy(lf
.lfFaceName
, "Tahoma");
1039 hfont
= CreateFontIndirectA(&lf
);
1040 hOldFont
= SelectObject(hdc
, hfont
);
1041 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1042 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1043 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1044 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1045 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1047 testtext
[0] = textm
.tmDefaultChar
;
1048 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1049 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1050 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1051 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1052 DeleteObject(SelectObject(hdc
, hOldFont
));
1055 static void test_GetKerningPairs(void)
1057 static const struct kerning_data
1059 const char face_name
[LF_FACESIZE
];
1061 /* some interesting fields from OUTLINETEXTMETRIC */
1062 LONG tmHeight
, tmAscent
, tmDescent
;
1067 UINT otmsCapEmHeight
;
1072 UINT otmusMinimumPPEM
;
1073 /* small subset of kerning pairs to test */
1074 DWORD total_kern_pairs
;
1075 const KERNINGPAIR kern_pair
[26];
1078 {"Arial", 12, 12, 9, 3,
1079 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1082 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1083 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1084 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1085 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1086 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1087 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1088 {933,970,+1},{933,972,-1}
1091 {"Arial", -34, 39, 32, 7,
1092 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1095 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1096 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1097 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1098 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1099 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1100 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1101 {933,970,+2},{933,972,-3}
1104 { "Arial", 120, 120, 97, 23,
1105 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1108 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1109 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1110 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1111 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1112 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1113 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1114 {933,970,+6},{933,972,-10}
1117 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1118 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1119 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1122 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1123 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1124 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1125 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1126 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1127 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1128 {933,970,+54},{933,972,-83}
1134 HFONT hfont
, hfont_old
;
1135 KERNINGPAIR
*kern_pair
;
1137 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1141 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1142 * which may render this test unusable, so we're trying to avoid that.
1144 SetLastError(0xdeadbeef);
1145 GetKerningPairsW(hdc
, 0, NULL
);
1146 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1148 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1153 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1155 OUTLINETEXTMETRICW otm
;
1157 if (!is_font_installed(kd
[i
].face_name
))
1159 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1163 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1165 memset(&lf
, 0, sizeof(lf
));
1166 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1167 lf
.lfHeight
= kd
[i
].height
;
1168 hfont
= CreateFontIndirect(&lf
);
1171 hfont_old
= SelectObject(hdc
, hfont
);
1173 SetLastError(0xdeadbeef);
1174 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1175 ok(GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
) == sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1177 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
), "expected %d, got %d\n",
1178 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1179 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
), "expected %d, got %d\n",
1180 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1181 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1182 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1184 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1185 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1186 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1187 kd
[i
].otmAscent
, otm
.otmAscent
);
1188 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1189 kd
[i
].otmDescent
, otm
.otmDescent
);
1190 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1191 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1192 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1193 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1194 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1195 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1197 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1198 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1199 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1200 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1201 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1202 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1203 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1204 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1205 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1208 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1209 trace("total_kern_pairs %u\n", total_kern_pairs
);
1210 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1212 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1213 SetLastError(0xdeadbeef);
1214 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1215 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1216 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1217 ok(ret
== 0, "got %lu, expected 0\n", ret
);
1220 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1221 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1223 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1224 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1226 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1227 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1231 for (n
= 0; n
< ret
; n
++)
1235 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1236 trace("{'%c','%c',%d},\n",
1237 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1239 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1241 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1242 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1244 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1245 "pair %d:%d got %d, expected %d\n",
1246 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1247 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1253 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1254 matches
, kd
[i
].total_kern_pairs
);
1256 HeapFree(GetProcessHeap(), 0, kern_pair
);
1258 SelectObject(hdc
, hfont_old
);
1259 DeleteObject(hfont
);
1265 static void test_height_selection(void)
1267 static const struct font_data
1269 const char face_name
[LF_FACESIZE
];
1270 int requested_height
;
1271 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1274 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96 },
1275 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96 },
1276 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96 },
1277 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96 },
1278 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96 },
1279 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96 },
1280 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96 },
1281 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96 },
1282 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96 },
1283 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96 }
1287 HFONT hfont
, old_hfont
;
1291 hdc
= CreateCompatibleDC(0);
1294 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
1296 if (!is_truetype_font_installed(fd
[i
].face_name
))
1298 skip("%s is not installed\n", fd
[i
].face_name
);
1302 memset(&lf
, 0, sizeof(lf
));
1303 lf
.lfHeight
= fd
[i
].requested_height
;
1304 lf
.lfWeight
= fd
[i
].weight
;
1305 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1307 hfont
= CreateFontIndirect(&lf
);
1310 old_hfont
= SelectObject(hdc
, hfont
);
1311 ret
= GetTextMetrics(hdc
, &tm
);
1312 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1313 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1315 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1316 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
);
1317 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
);
1318 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
);
1319 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
);
1320 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1321 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
);
1323 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
);
1326 SelectObject(hdc
, old_hfont
);
1327 DeleteObject(hfont
);
1333 static void test_GetOutlineTextMetrics(void)
1335 OUTLINETEXTMETRIC
*otm
;
1337 HFONT hfont
, hfont_old
;
1339 DWORD ret
, otm_size
;
1342 if (!is_font_installed("Arial"))
1344 skip("Arial is not installed\n");
1350 memset(&lf
, 0, sizeof(lf
));
1351 strcpy(lf
.lfFaceName
, "Arial");
1353 lf
.lfWeight
= FW_NORMAL
;
1354 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1355 lf
.lfQuality
= PROOF_QUALITY
;
1356 hfont
= CreateFontIndirect(&lf
);
1359 hfont_old
= SelectObject(hdc
, hfont
);
1360 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1361 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1363 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1365 memset(otm
, 0xAA, otm_size
);
1366 SetLastError(0xdeadbeef);
1367 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1368 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1369 ok(ret
== 1 /* Win9x */ ||
1370 ret
== otm
->otmSize
/* XP*/,
1371 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1372 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1374 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1375 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1376 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1377 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1380 memset(otm
, 0xAA, otm_size
);
1381 SetLastError(0xdeadbeef);
1382 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1383 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1384 ok(ret
== 1 /* Win9x */ ||
1385 ret
== otm
->otmSize
/* XP*/,
1386 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1387 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1389 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1390 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1391 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1392 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1395 /* ask about truncated data */
1396 memset(otm
, 0xAA, otm_size
);
1397 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1398 SetLastError(0xdeadbeef);
1399 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1400 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1401 ok(ret
== 1 /* Win9x */ ||
1402 ret
== otm
->otmSize
/* XP*/,
1403 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1404 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1406 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1407 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1408 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1410 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1412 HeapFree(GetProcessHeap(), 0, otm
);
1414 SelectObject(hdc
, hfont_old
);
1415 DeleteObject(hfont
);
1420 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1424 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
1425 areaWidth
= clientArea
->right
- clientArea
->left
,
1427 BOOL lastExtent
= FALSE
;
1428 PSTR pFirstChar
, pLastChar
;
1434 int GetTextExtentExPointWWidth
;
1437 GetTextMetricsA(hdc
, &tm
);
1438 y
= clientArea
->top
;
1441 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1447 /* if not at the end of the string, ... */
1448 if (*str
== '\0') break;
1449 /* ... add the next word to the current extent */
1450 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1452 SetTextJustification(hdc
, 0, 0);
1453 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1454 } while ((int) size
.cx
< areaWidth
);
1456 /* ignore trailing break chars */
1458 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1464 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1466 SetTextJustification(hdc
, 0, 0);
1467 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1469 /* do not justify the last extent */
1470 if (*str
!= '\0' && breakCount
> 0)
1472 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1473 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1474 justifiedWidth
= size
.cx
;
1476 else lastExtent
= TRUE
;
1478 /* catch errors and report them */
1479 if (!lastExtent
&& (justifiedWidth
!= areaWidth
))
1481 memset(error
[nErrors
].extent
, 0, 100);
1482 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
1483 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
1489 } while (*str
&& y
< clientArea
->bottom
);
1491 for (e
= 0; e
< nErrors
; e
++)
1493 /* The width returned by GetTextExtentPoint32() is exactly the same
1494 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1495 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1496 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1497 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1501 static void test_SetTextJustification(void)
1508 static char testText
[] =
1509 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1510 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1511 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1512 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1513 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1514 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1515 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1517 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1518 GetClientRect( hwnd
, &clientArea
);
1519 hdc
= GetDC( hwnd
);
1521 memset(&lf
, 0, sizeof lf
);
1522 lf
.lfCharSet
= ANSI_CHARSET
;
1523 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1524 lf
.lfWeight
= FW_DONTCARE
;
1526 lf
.lfQuality
= DEFAULT_QUALITY
;
1527 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1528 hfont
= create_font("Times New Roman", &lf
);
1529 SelectObject(hdc
, hfont
);
1531 testJustification(hdc
, testText
, &clientArea
);
1533 DeleteObject(hfont
);
1534 ReleaseDC(hwnd
, hdc
);
1535 DestroyWindow(hwnd
);
1538 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1542 HFONT hfont
, hfont_old
;
1549 assert(count
<= 128);
1551 memset(&lf
, 0, sizeof(lf
));
1553 lf
.lfCharSet
= charset
;
1555 lstrcpyA(lf
.lfFaceName
, "Arial");
1556 SetLastError(0xdeadbeef);
1557 hfont
= CreateFontIndirectA(&lf
);
1558 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1561 hfont_old
= SelectObject(hdc
, hfont
);
1563 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1564 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1566 SetLastError(0xdeadbeef);
1567 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1568 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1570 if (charset
== SYMBOL_CHARSET
)
1572 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1573 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1577 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1578 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1581 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1583 trace("Can't find codepage for charset %d\n", cs
);
1587 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1592 WCHAR unicode_buf
[128];
1594 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1596 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1598 SetLastError(0xdeadbeef);
1599 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1600 ok(ret
== count
, "GetGlyphIndicesW error %u\n", GetLastError());
1606 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1608 SetLastError(0xdeadbeef);
1609 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1610 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1613 SelectObject(hdc
, hfont_old
);
1614 DeleteObject(hfont
);
1621 static void test_font_charset(void)
1623 static struct charset_data
1627 WORD font_idxA
[128], font_idxW
[128];
1630 { ANSI_CHARSET
, 1252 },
1631 { RUSSIAN_CHARSET
, 1251 },
1632 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1636 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1638 win_skip("Skipping the font charset test on a Win9x platform\n");
1642 if (!is_font_installed("Arial"))
1644 skip("Arial is not installed\n");
1648 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1650 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1652 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1654 skip("Symbol or Wingdings is not installed\n");
1658 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
);
1659 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
);
1660 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1663 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1666 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1667 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1670 skip("Symbol or Wingdings is not installed\n");
1673 static void test_GetFontUnicodeRanges(void)
1677 HFONT hfont
, hfont_old
;
1681 if (!pGetFontUnicodeRanges
)
1683 win_skip("GetFontUnicodeRanges not available before W2K\n");
1687 memset(&lf
, 0, sizeof(lf
));
1688 lstrcpyA(lf
.lfFaceName
, "Arial");
1689 hfont
= create_font("Arial", &lf
);
1692 hfont_old
= SelectObject(hdc
, hfont
);
1694 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1695 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1697 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1698 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1700 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1702 size
= pGetFontUnicodeRanges(hdc
, gs
);
1703 ok(size
, "GetFontUnicodeRanges failed\n");
1705 for (i
= 0; i
< gs
->cRanges
; i
++)
1706 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1708 trace("found %u ranges\n", gs
->cRanges
);
1710 HeapFree(GetProcessHeap(), 0, gs
);
1712 SelectObject(hdc
, hfont_old
);
1713 DeleteObject(hfont
);
1714 ReleaseDC(NULL
, hdc
);
1717 #define MAX_ENUM_FONTS 4096
1719 struct enum_font_data
1722 LOGFONT lf
[MAX_ENUM_FONTS
];
1725 struct enum_font_dataW
1728 LOGFONTW lf
[MAX_ENUM_FONTS
];
1731 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1733 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1735 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1737 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1739 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1740 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1742 if (efd
->total
< MAX_ENUM_FONTS
)
1743 efd
->lf
[efd
->total
++] = *lf
;
1745 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1750 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
1752 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
1754 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1756 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1758 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1759 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1761 if (efd
->total
< MAX_ENUM_FONTS
)
1762 efd
->lf
[efd
->total
++] = *lf
;
1764 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1769 static void get_charset_stats(struct enum_font_data
*efd
,
1770 int *ansi_charset
, int *symbol_charset
,
1771 int *russian_charset
)
1776 *symbol_charset
= 0;
1777 *russian_charset
= 0;
1779 for (i
= 0; i
< efd
->total
; i
++)
1781 switch (efd
->lf
[i
].lfCharSet
)
1786 case SYMBOL_CHARSET
:
1787 (*symbol_charset
)++;
1789 case RUSSIAN_CHARSET
:
1790 (*russian_charset
)++;
1796 static void get_charset_statsW(struct enum_font_dataW
*efd
,
1797 int *ansi_charset
, int *symbol_charset
,
1798 int *russian_charset
)
1803 *symbol_charset
= 0;
1804 *russian_charset
= 0;
1806 for (i
= 0; i
< efd
->total
; i
++)
1808 switch (efd
->lf
[i
].lfCharSet
)
1813 case SYMBOL_CHARSET
:
1814 (*symbol_charset
)++;
1816 case RUSSIAN_CHARSET
:
1817 (*russian_charset
)++;
1823 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1825 struct enum_font_data efd
;
1826 struct enum_font_dataW efdw
;
1829 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1831 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1833 if (*font_name
&& !is_truetype_font_installed(font_name
))
1835 skip("%s is not installed\n", font_name
);
1841 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1842 * while EnumFontFamiliesEx doesn't.
1844 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1847 * Use EnumFontFamiliesW since win98 crashes when the
1848 * second parameter is NULL using EnumFontFamilies
1851 SetLastError(0xdeadbeef);
1852 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
1853 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
1856 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1857 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1858 ansi_charset
, symbol_charset
, russian_charset
);
1859 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
1860 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1861 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1862 ok(russian_charset
> 0 ||
1863 broken(russian_charset
== 0), /* NT4 */
1864 "NULL family should enumerate RUSSIAN_CHARSET\n");
1868 SetLastError(0xdeadbeef);
1869 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
1870 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
1873 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1874 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1875 ansi_charset
, symbol_charset
, russian_charset
);
1876 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
1877 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1878 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1879 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1884 SetLastError(0xdeadbeef);
1885 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
1886 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1887 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1888 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1889 ansi_charset
, symbol_charset
, russian_charset
,
1890 *font_name
? font_name
: "<empty>");
1892 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1894 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
1895 for (i
= 0; i
< efd
.total
; i
++)
1897 /* FIXME: remove completely once Wine is fixed */
1898 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
1901 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1904 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1905 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1906 font_name
, efd
.lf
[i
].lfFaceName
);
1909 memset(&lf
, 0, sizeof(lf
));
1910 lf
.lfCharSet
= ANSI_CHARSET
;
1911 lstrcpy(lf
.lfFaceName
, font_name
);
1913 SetLastError(0xdeadbeef);
1914 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1915 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1916 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1917 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1918 ansi_charset
, symbol_charset
, russian_charset
,
1919 *font_name
? font_name
: "<empty>");
1920 if (font_charset
== SYMBOL_CHARSET
)
1923 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
1925 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1929 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
1930 for (i
= 0; i
< efd
.total
; i
++)
1932 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1934 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1935 font_name
, efd
.lf
[i
].lfFaceName
);
1939 /* DEFAULT_CHARSET should enumerate all available charsets */
1940 memset(&lf
, 0, sizeof(lf
));
1941 lf
.lfCharSet
= DEFAULT_CHARSET
;
1942 lstrcpy(lf
.lfFaceName
, font_name
);
1944 SetLastError(0xdeadbeef);
1945 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1946 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1947 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1948 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1949 ansi_charset
, symbol_charset
, russian_charset
,
1950 *font_name
? font_name
: "<empty>");
1951 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
1952 for (i
= 0; i
< efd
.total
; i
++)
1955 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1956 font_name
, efd
.lf
[i
].lfFaceName
);
1960 switch (font_charset
)
1963 ok(ansi_charset
> 0,
1964 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1966 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
1967 ok(russian_charset
> 0,
1968 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1970 case SYMBOL_CHARSET
:
1972 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
1974 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1975 ok(!russian_charset
,
1976 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1978 case DEFAULT_CHARSET
:
1979 ok(ansi_charset
> 0,
1980 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1981 ok(symbol_charset
> 0,
1982 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1983 ok(russian_charset
> 0,
1984 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1990 ok(ansi_charset
> 0,
1991 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1992 ok(symbol_charset
> 0,
1993 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1994 ok(russian_charset
> 0,
1995 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1998 memset(&lf
, 0, sizeof(lf
));
1999 lf
.lfCharSet
= SYMBOL_CHARSET
;
2000 lstrcpy(lf
.lfFaceName
, font_name
);
2002 SetLastError(0xdeadbeef);
2003 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2004 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2005 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2006 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2007 ansi_charset
, symbol_charset
, russian_charset
,
2008 *font_name
? font_name
: "<empty>");
2009 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2010 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2013 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2014 for (i
= 0; i
< efd
.total
; i
++)
2016 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2018 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2019 font_name
, efd
.lf
[i
].lfFaceName
);
2023 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2024 ok(symbol_charset
> 0,
2025 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2026 ok(!russian_charset
,
2027 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2033 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2035 HFONT hfont
, hfont_prev
;
2037 GLYPHMETRICS gm1
, gm2
;
2040 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
2042 if(!pGetGlyphIndicesA
)
2045 /* negative widths are handled just as positive ones */
2046 lf2
.lfWidth
= -lf
->lfWidth
;
2048 SetLastError(0xdeadbeef);
2049 hfont
= CreateFontIndirectA(lf
);
2050 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2051 check_font("original", lf
, hfont
);
2053 hfont_prev
= SelectObject(hdc
, hfont
);
2055 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2056 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2058 SelectObject(hdc
, hfont_prev
);
2059 DeleteObject(hfont
);
2060 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2064 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2065 memset(&gm1
, 0xab, sizeof(gm1
));
2066 SetLastError(0xdeadbeef);
2067 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2068 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2070 SelectObject(hdc
, hfont_prev
);
2071 DeleteObject(hfont
);
2073 SetLastError(0xdeadbeef);
2074 hfont
= CreateFontIndirectA(&lf2
);
2075 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2076 check_font("negative width", &lf2
, hfont
);
2078 hfont_prev
= SelectObject(hdc
, hfont
);
2080 memset(&gm2
, 0xbb, sizeof(gm2
));
2081 SetLastError(0xdeadbeef);
2082 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2083 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2085 SelectObject(hdc
, hfont_prev
);
2086 DeleteObject(hfont
);
2088 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2089 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2090 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2091 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2092 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2093 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2094 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2095 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2096 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2097 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2098 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2101 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2102 #include "pshpack2.h"
2106 SHORT xAvgCharWidth
;
2107 USHORT usWeightClass
;
2108 USHORT usWidthClass
;
2110 SHORT ySubscriptXSize
;
2111 SHORT ySubscriptYSize
;
2112 SHORT ySubscriptXOffset
;
2113 SHORT ySubscriptYOffset
;
2114 SHORT ySuperscriptXSize
;
2115 SHORT ySuperscriptYSize
;
2116 SHORT ySuperscriptXOffset
;
2117 SHORT ySuperscriptYOffset
;
2118 SHORT yStrikeoutSize
;
2119 SHORT yStrikeoutPosition
;
2122 ULONG ulUnicodeRange1
;
2123 ULONG ulUnicodeRange2
;
2124 ULONG ulUnicodeRange3
;
2125 ULONG ulUnicodeRange4
;
2128 USHORT usFirstCharIndex
;
2129 USHORT usLastCharIndex
;
2130 /* According to the Apple spec, original version didn't have the below fields,
2131 * version numbers were taked from the OpenType spec.
2133 /* version 0 (TrueType 1.5) */
2134 USHORT sTypoAscender
;
2135 USHORT sTypoDescender
;
2136 USHORT sTypoLineGap
;
2138 USHORT usWinDescent
;
2139 /* version 1 (TrueType 1.66) */
2140 ULONG ulCodePageRange1
;
2141 ULONG ulCodePageRange2
;
2142 /* version 2 (OpenType 1.2) */
2145 USHORT usDefaultChar
;
2147 USHORT usMaxContext
;
2149 #include "poppack.h"
2151 #ifdef WORDS_BIGENDIAN
2152 #define GET_BE_WORD(x) (x)
2153 #define GET_BE_DWORD(x) (x)
2155 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2156 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2159 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2160 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2161 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2162 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2163 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2176 } cmap_encoding_record
;
2184 BYTE glyph_ids
[256];
2194 USHORT search_range
;
2195 USHORT entry_selector
;
2198 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2201 USHORT start_count[seg_countx2 / 2];
2202 USHORT id_delta[seg_countx2 / 2];
2203 USHORT id_range_offset[seg_countx2 / 2];
2213 USHORT id_range_offset
;
2214 } cmap_format_4_seg
;
2216 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2218 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2219 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2220 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2223 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2226 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2230 for(i
= 0; i
< 256; i
++)
2232 if(cmap
->glyph_ids
[i
] == 0) continue;
2234 if(*first
== 256) *first
= i
;
2236 if(*first
== 256) return FALSE
;
2240 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2242 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2243 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2244 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2245 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2246 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2249 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2252 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2253 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2254 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2258 for(i
= 0; i
< seg_count
; i
++)
2261 cmap_format_4_seg seg
;
2263 get_seg4(cmap
, i
, &seg
);
2264 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2266 if(seg
.id_range_offset
== 0)
2267 index
= (seg
.id_delta
+ code
) & 0xffff;
2270 index
= seg
.id_range_offset
/ 2
2271 + code
- seg
.start_count
2274 /* some fonts have broken last segment */
2275 if ((char *)(glyph_ids
+ index
+ sizeof(*glyph_ids
)) < (char *)ptr
+ limit
)
2276 index
= GET_BE_WORD(glyph_ids
[index
]);
2279 trace("segment %04x/%04x index %04x points to nowhere\n",
2280 seg
.start_count
, seg
.end_count
, index
);
2283 if(index
) index
+= seg
.id_delta
;
2285 if(*first
== 0x10000)
2286 *last
= *first
= code
;
2292 if(*first
== 0x10000) return FALSE
;
2296 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2299 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2301 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2303 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2304 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2317 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2320 cmap_header
*header
;
2325 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2326 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2327 if(size
== GDI_ERROR
) return FALSE
;
2329 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2330 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2331 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2332 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2334 cmap
= get_cmap(header
, 3, 1);
2336 *cmap_type
= cmap_ms_unicode
;
2339 cmap
= get_cmap(header
, 3, 0);
2340 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2344 *cmap_type
= cmap_none
;
2348 format
= GET_BE_WORD(*(WORD
*)cmap
);
2352 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2355 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2358 trace("unhandled cmap format %d\n", format
);
2363 HeapFree(GetProcessHeap(), 0, header
);
2367 static void test_text_metrics(const LOGFONTA
*lf
)
2370 HFONT hfont
, hfont_old
;
2374 const char *font_name
= lf
->lfFaceName
;
2375 DWORD cmap_first
= 0, cmap_last
= 0;
2376 cmap_type cmap_type
;
2380 SetLastError(0xdeadbeef);
2381 hfont
= CreateFontIndirectA(lf
);
2382 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2384 hfont_old
= SelectObject(hdc
, hfont
);
2386 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2387 if (size
== GDI_ERROR
)
2389 trace("OS/2 chunk was not found\n");
2392 if (size
> sizeof(tt_os2
))
2394 trace("got too large OS/2 chunk of size %u\n", size
);
2395 size
= sizeof(tt_os2
);
2398 memset(&tt_os2
, 0, sizeof(tt_os2
));
2399 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2400 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2402 SetLastError(0xdeadbeef);
2403 ret
= GetTextMetricsA(hdc
, &tmA
);
2404 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2406 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
2408 skip("Unable to retrieve first and last glyphs from cmap\n");
2412 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
2413 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
2414 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
2418 version
= GET_BE_WORD(tt_os2
.version
);
2420 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2421 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2422 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2423 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2425 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2426 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
2427 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
2429 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
2434 case 1257: /* Baltic */
2435 expect_last_W
= 0xf8fd;
2438 expect_last_W
= 0xf0ff;
2440 expect_break_W
= 0x20;
2441 expect_default_W
= expect_break_W
- 1;
2442 expect_first_A
= 0x1e;
2443 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
2447 expect_first_W
= cmap_first
;
2448 expect_last_W
= min(cmap_last
, os2_last_char
);
2449 if(os2_first_char
<= 1)
2450 expect_break_W
= os2_first_char
+ 2;
2451 else if(os2_first_char
> 0xff)
2452 expect_break_W
= 0x20;
2454 expect_break_W
= os2_first_char
;
2455 expect_default_W
= expect_break_W
- 1;
2456 expect_first_A
= expect_default_W
- 1;
2457 expect_last_A
= min(expect_last_W
, 0xff);
2459 expect_break_A
= expect_break_W
;
2460 expect_default_A
= expect_default_W
;
2462 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2463 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
2464 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
2465 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2466 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2468 ok(tmA
.tmFirstChar
== expect_first_A
||
2469 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2470 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2471 ok(tmA
.tmLastChar
== expect_last_A
||
2472 tmA
.tmLastChar
== 0xff /* win9x */,
2473 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
2474 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
2475 font_name
, tmA
.tmBreakChar
, expect_break_A
);
2476 ok(tmA
.tmDefaultChar
== expect_default_A
, "A: tmDefaultChar for %s got %02x expected %02x\n",
2477 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
2480 SetLastError(0xdeadbeef);
2481 ret
= GetTextMetricsW(hdc
, &tmW
);
2482 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2483 "GetTextMetricsW error %u\n", GetLastError());
2486 /* Wine uses the os2 first char */
2487 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
2488 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2489 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2491 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2492 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2494 /* Wine uses the os2 last char */
2495 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
2496 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2497 font_name
, tmW
.tmLastChar
, expect_last_W
);
2499 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2500 font_name
, tmW
.tmLastChar
, expect_last_W
);
2501 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
2502 font_name
, tmW
.tmBreakChar
, expect_break_W
);
2503 ok(tmW
.tmDefaultChar
== expect_default_W
, "W: tmDefaultChar for %s got %02x expected %02x\n",
2504 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
2506 /* Test the aspect ratio while we have tmW */
2507 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2508 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2509 tmW
.tmDigitizedAspectX
, ret
);
2510 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2511 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2512 tmW
.tmDigitizedAspectX
, ret
);
2516 /* test FF_ values */
2517 switch(tt_os2
.panose
.bFamilyType
)
2521 case PAN_FAMILY_TEXT_DISPLAY
:
2522 case PAN_FAMILY_PICTORIAL
:
2524 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
2525 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
2527 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
2530 switch(tt_os2
.panose
.bSerifStyle
)
2535 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
2538 case PAN_SERIF_COVE
:
2539 case PAN_SERIF_OBTUSE_COVE
:
2540 case PAN_SERIF_SQUARE_COVE
:
2541 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
2542 case PAN_SERIF_SQUARE
:
2543 case PAN_SERIF_THIN
:
2544 case PAN_SERIF_BONE
:
2545 case PAN_SERIF_EXAGGERATED
:
2546 case PAN_SERIF_TRIANGLE
:
2547 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
2550 case PAN_SERIF_NORMAL_SANS
:
2551 case PAN_SERIF_OBTUSE_SANS
:
2552 case PAN_SERIF_PERP_SANS
:
2553 case PAN_SERIF_FLARED
:
2554 case PAN_SERIF_ROUNDED
:
2555 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
2560 case PAN_FAMILY_SCRIPT
:
2561 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
2564 case PAN_FAMILY_DECORATIVE
:
2565 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
2569 test_negative_width(hdc
, lf
);
2572 SelectObject(hdc
, hfont_old
);
2573 DeleteObject(hfont
);
2578 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2580 INT
*enumed
= (INT
*)lParam
;
2582 if (type
== TRUETYPE_FONTTYPE
)
2585 test_text_metrics(lf
);
2590 static void test_GetTextMetrics(void)
2596 /* Report only once */
2597 if(!pGetGlyphIndicesA
)
2598 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2602 memset(&lf
, 0, sizeof(lf
));
2603 lf
.lfCharSet
= DEFAULT_CHARSET
;
2605 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2606 trace("Tested metrics of %d truetype fonts\n", enumed
);
2611 static void test_nonexistent_font(void)
2619 { "Times New Roman Baltic", 186 },
2620 { "Times New Roman CE", 238 },
2621 { "Times New Roman CYR", 204 },
2622 { "Times New Roman Greek", 161 },
2623 { "Times New Roman TUR", 162 }
2629 INT cs
, expected_cs
, i
;
2630 char buf
[LF_FACESIZE
];
2632 if (!is_truetype_font_installed("Arial") ||
2633 !is_truetype_font_installed("Times New Roman"))
2635 skip("Arial or Times New Roman not installed\n");
2639 expected_cs
= GetACP();
2640 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
2642 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
2645 expected_cs
= csi
.ciCharset
;
2646 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
2650 memset(&lf
, 0, sizeof(lf
));
2652 lf
.lfWeight
= FW_REGULAR
;
2653 lf
.lfCharSet
= ANSI_CHARSET
;
2654 lf
.lfPitchAndFamily
= FF_SWISS
;
2655 strcpy(lf
.lfFaceName
, "Nonexistent font");
2656 hfont
= CreateFontIndirectA(&lf
);
2657 hfont
= SelectObject(hdc
, hfont
);
2658 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2659 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
2660 cs
= GetTextCharset(hdc
);
2661 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2662 DeleteObject(SelectObject(hdc
, hfont
));
2664 memset(&lf
, 0, sizeof(lf
));
2666 lf
.lfWeight
= FW_DONTCARE
;
2667 strcpy(lf
.lfFaceName
, "Nonexistent font");
2668 hfont
= CreateFontIndirectA(&lf
);
2669 hfont
= SelectObject(hdc
, hfont
);
2670 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2671 todo_wine
/* Wine uses Arial for all substitutions */
2672 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
2673 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
2674 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2676 cs
= GetTextCharset(hdc
);
2677 ok(cs
== expected_cs
, "expected %d, got %d\n", expected_cs
, cs
);
2678 DeleteObject(SelectObject(hdc
, hfont
));
2680 memset(&lf
, 0, sizeof(lf
));
2682 lf
.lfWeight
= FW_REGULAR
;
2683 strcpy(lf
.lfFaceName
, "Nonexistent font");
2684 hfont
= CreateFontIndirectA(&lf
);
2685 hfont
= SelectObject(hdc
, hfont
);
2686 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2687 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2688 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
2689 cs
= GetTextCharset(hdc
);
2690 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2691 DeleteObject(SelectObject(hdc
, hfont
));
2693 memset(&lf
, 0, sizeof(lf
));
2695 lf
.lfWeight
= FW_DONTCARE
;
2696 strcpy(lf
.lfFaceName
, "Times New Roman");
2697 hfont
= CreateFontIndirectA(&lf
);
2698 hfont
= SelectObject(hdc
, hfont
);
2699 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2700 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
2701 cs
= GetTextCharset(hdc
);
2702 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2703 DeleteObject(SelectObject(hdc
, hfont
));
2705 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
2707 memset(&lf
, 0, sizeof(lf
));
2709 lf
.lfWeight
= FW_REGULAR
;
2710 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2711 hfont
= CreateFontIndirectA(&lf
);
2712 hfont
= SelectObject(hdc
, hfont
);
2713 cs
= GetTextCharset(hdc
);
2714 if (font_subst
[i
].charset
== expected_cs
)
2716 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2717 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2718 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
2722 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
2723 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2724 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2725 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
2727 DeleteObject(SelectObject(hdc
, hfont
));
2729 memset(&lf
, 0, sizeof(lf
));
2731 lf
.lfWeight
= FW_DONTCARE
;
2732 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2733 hfont
= CreateFontIndirectA(&lf
);
2734 hfont
= SelectObject(hdc
, hfont
);
2735 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2736 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
2737 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
2738 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
2739 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2740 "got %s for font %s\n", buf
, font_subst
[i
].name
);
2741 cs
= GetTextCharset(hdc
);
2742 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2743 DeleteObject(SelectObject(hdc
, hfont
));
2749 static void test_GdiRealizationInfo(void)
2754 HFONT hfont
, hfont_old
;
2757 if(!pGdiRealizationInfo
)
2759 win_skip("GdiRealizationInfo not available\n");
2765 memset(info
, 0xcc, sizeof(info
));
2766 r
= pGdiRealizationInfo(hdc
, info
);
2767 ok(r
!= 0, "ret 0\n");
2768 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
2769 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2771 if (!is_truetype_font_installed("Arial"))
2773 skip("skipping GdiRealizationInfo with truetype font\n");
2777 memset(&lf
, 0, sizeof(lf
));
2778 strcpy(lf
.lfFaceName
, "Arial");
2780 lf
.lfWeight
= FW_NORMAL
;
2781 hfont
= CreateFontIndirectA(&lf
);
2782 hfont_old
= SelectObject(hdc
, hfont
);
2784 memset(info
, 0xcc, sizeof(info
));
2785 r
= pGdiRealizationInfo(hdc
, info
);
2786 ok(r
!= 0, "ret 0\n");
2787 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
2788 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2790 DeleteObject(SelectObject(hdc
, hfont_old
));
2796 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2797 the nul in the count of characters copied when the face name buffer is not
2798 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2799 always includes it. */
2800 static void test_GetTextFace(void)
2802 static const char faceA
[] = "Tahoma";
2803 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
2806 char bufA
[LF_FACESIZE
];
2807 WCHAR bufW
[LF_FACESIZE
];
2812 if(!is_font_installed("Tahoma"))
2814 skip("Tahoma is not installed so skipping this test\n");
2819 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
2820 f
= CreateFontIndirectA(&fA
);
2821 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
2824 g
= SelectObject(dc
, f
);
2825 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
2826 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
2827 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
2829 /* Play with the count arg. */
2831 n
= GetTextFaceA(dc
, 0, bufA
);
2832 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2833 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2836 n
= GetTextFaceA(dc
, 1, bufA
);
2837 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2838 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2840 bufA
[0] = 'x'; bufA
[1] = 'y';
2841 n
= GetTextFaceA(dc
, 2, bufA
);
2842 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
2843 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
2845 n
= GetTextFaceA(dc
, 0, NULL
);
2846 ok(n
== sizeof faceA
||
2847 broken(n
== 0), /* win98, winMe */
2848 "GetTextFaceA returned %d\n", n
);
2850 DeleteObject(SelectObject(dc
, g
));
2851 ReleaseDC(NULL
, dc
);
2854 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
2855 SetLastError(0xdeadbeef);
2856 f
= CreateFontIndirectW(&fW
);
2857 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2859 win_skip("CreateFontIndirectW is not implemented\n");
2862 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
2865 g
= SelectObject(dc
, f
);
2866 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
2867 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2868 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
2870 /* Play with the count arg. */
2872 n
= GetTextFaceW(dc
, 0, bufW
);
2873 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
2874 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2877 n
= GetTextFaceW(dc
, 1, bufW
);
2878 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
2879 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2881 bufW
[0] = 'x'; bufW
[1] = 'y';
2882 n
= GetTextFaceW(dc
, 2, bufW
);
2883 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
2884 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
2886 n
= GetTextFaceW(dc
, 0, NULL
);
2887 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2889 DeleteObject(SelectObject(dc
, g
));
2890 ReleaseDC(NULL
, dc
);
2893 static void test_orientation(void)
2895 static const char test_str
[11] = "Test String";
2898 HFONT hfont
, old_hfont
;
2901 if (!is_truetype_font_installed("Arial"))
2903 skip("Arial is not installed\n");
2907 hdc
= CreateCompatibleDC(0);
2908 memset(&lf
, 0, sizeof(lf
));
2909 lstrcpyA(lf
.lfFaceName
, "Arial");
2911 lf
.lfOrientation
= lf
.lfEscapement
= 900;
2912 hfont
= create_font("orientation", &lf
);
2913 old_hfont
= SelectObject(hdc
, hfont
);
2914 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
2915 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
2916 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
2917 SelectObject(hdc
, old_hfont
);
2918 DeleteObject(hfont
);
2922 static void test_oemcharset(void)
2926 HFONT hfont
, old_hfont
;
2929 hdc
= CreateCompatibleDC(0);
2930 ZeroMemory(&lf
, sizeof(lf
));
2932 lf
.lfCharSet
= OEM_CHARSET
;
2933 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
2934 lstrcpyA(lf
.lfFaceName
, "Terminal");
2935 hfont
= CreateFontIndirectA(&lf
);
2936 old_hfont
= SelectObject(hdc
, hfont
);
2937 charset
= GetTextCharset(hdc
);
2939 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
2940 hfont
= SelectObject(hdc
, old_hfont
);
2941 GetObjectA(hfont
, sizeof(clf
), &clf
);
2942 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
2943 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
2944 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
2945 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
2946 DeleteObject(hfont
);
2950 static void test_GetGlyphOutline(void)
2952 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
2956 HFONT hfont
, old_hfont
;
2959 if (!is_truetype_font_installed("Tahoma"))
2961 skip("Tahoma is not installed\n");
2965 hdc
= CreateCompatibleDC(0);
2966 memset(&lf
, 0, sizeof(lf
));
2968 lstrcpyA(lf
.lfFaceName
, "Tahoma");
2969 SetLastError(0xdeadbeef);
2970 hfont
= CreateFontIndirectA(&lf
);
2971 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2972 old_hfont
= SelectObject(hdc
, hfont
);
2974 memset(&gm
, 0, sizeof(gm
));
2975 SetLastError(0xdeadbeef);
2976 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2977 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
2979 memset(&gm
, 0, sizeof(gm
));
2980 SetLastError(0xdeadbeef);
2981 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2982 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
2983 ok(GetLastError() == 0xdeadbeef ||
2984 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
2985 "expected 0xdeadbeef, got %u\n", GetLastError());
2987 memset(&gm
, 0, sizeof(gm
));
2988 SetLastError(0xdeadbeef);
2989 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2990 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2991 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
2993 memset(&gm
, 0, sizeof(gm
));
2994 SetLastError(0xdeadbeef);
2995 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2996 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2998 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
2999 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3002 /* test for needed buffer size request on space char */
3003 memset(&gm
, 0, sizeof(gm
));
3004 SetLastError(0xdeadbeef);
3005 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3006 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3007 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3009 /* requesting buffer size for space char + error */
3010 memset(&gm
, 0, sizeof(gm
));
3011 SetLastError(0xdeadbeef);
3012 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3013 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3015 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3016 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3019 SelectObject(hdc
, old_hfont
);
3020 DeleteObject(hfont
);
3024 /* bug #9995: there is a limit to the character width that can be specified */
3025 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3031 int ave_width
, height
, width
, ratio
, scale
;
3033 if (!is_truetype_font_installed( fontname
)) {
3034 skip("%s is not installed\n", fontname
);
3037 hdc
= CreateCompatibleDC(0);
3038 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3039 /* select width = 0 */
3040 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3041 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3042 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3044 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3045 of
= SelectObject( hdc
, hf
);
3046 ret
= GetTextMetricsA( hdc
, &tm
);
3047 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3048 height
= tm
.tmHeight
;
3049 ave_width
= tm
.tmAveCharWidth
;
3050 SelectObject( hdc
, of
);
3053 trace("height %d, ave width %d\n", height
, ave_width
);
3055 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3057 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3058 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3059 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3060 ok(hf
!= 0, "CreateFont failed\n");
3061 of
= SelectObject(hdc
, hf
);
3062 ret
= GetTextMetrics(hdc
, &tm
);
3063 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3064 SelectObject(hdc
, of
);
3067 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3073 ratio
= width
/ height
;
3074 scale
= width
/ ave_width
;
3076 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3077 width
, height
, ratio
, width
, ave_width
, scale
);
3079 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3082 static void test_CreateFontIndirect(void)
3084 LOGFONTA lf
, getobj_lf
;
3087 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3089 memset(&lf
, 0, sizeof(lf
));
3090 lf
.lfCharSet
= ANSI_CHARSET
;
3091 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3094 lf
.lfQuality
= DEFAULT_QUALITY
;
3095 lf
.lfItalic
= FALSE
;
3096 lf
.lfWeight
= FW_DONTCARE
;
3098 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3100 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3101 hfont
= CreateFontIndirectA(&lf
);
3102 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3103 SetLastError(0xdeadbeef);
3104 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3105 ok(ret
, "GetObject failed: %d\n", GetLastError());
3106 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3107 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3108 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3109 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3110 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3111 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3112 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3113 DeleteObject(hfont
);
3117 static void test_CreateFontIndirectEx(void)
3119 ENUMLOGFONTEXDVA lfex
;
3122 if (!pCreateFontIndirectExA
)
3124 win_skip("CreateFontIndirectExA is not available\n");
3128 if (!is_truetype_font_installed("Arial"))
3130 skip("Arial is not installed\n");
3134 SetLastError(0xdeadbeef);
3135 hfont
= pCreateFontIndirectExA(NULL
);
3136 ok(hfont
== NULL
, "got %p\n", hfont
);
3137 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3139 memset(&lfex
, 0, sizeof(lfex
));
3140 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3141 hfont
= pCreateFontIndirectExA(&lfex
);
3142 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3144 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3145 DeleteObject(hfont
);
3154 test_outline_font();
3155 test_bitmap_font_metrics();
3156 test_GdiGetCharDimensions();
3157 test_GetCharABCWidths();
3158 test_text_extents();
3159 test_GetGlyphIndices();
3160 test_GetKerningPairs();
3161 test_GetOutlineTextMetrics();
3162 test_SetTextJustification();
3163 test_font_charset();
3164 test_GetFontUnicodeRanges();
3165 test_nonexistent_font();
3167 test_height_selection();
3169 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3170 * I'd like to avoid them in this test.
3172 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
3173 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
3174 if (is_truetype_font_installed("Arial Black") &&
3175 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3177 test_EnumFontFamilies("", ANSI_CHARSET
);
3178 test_EnumFontFamilies("", SYMBOL_CHARSET
);
3179 test_EnumFontFamilies("", DEFAULT_CHARSET
);
3182 skip("Arial Black or Symbol/Wingdings is not installed\n");
3183 test_GetTextMetrics();
3184 test_GdiRealizationInfo();
3186 test_GetGlyphOutline();
3187 test_GetTextMetrics2("Tahoma", -11);
3188 test_GetTextMetrics2("Tahoma", -55);
3189 test_GetTextMetrics2("Tahoma", -110);
3190 test_GetTextMetrics2("Arial", -11);
3191 test_GetTextMetrics2("Arial", -55);
3192 test_GetTextMetrics2("Arial", -110);
3193 test_CreateFontIndirect();
3194 test_CreateFontIndirectEx();