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
;
318 /* "System" has only 1 pixel size defined, otherwise the test breaks */
319 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
323 trace("no bitmap fonts were found, skipping the test\n");
327 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
329 height_orig
= bitmap_lf
.lfHeight
;
330 lfWidth
= bitmap_lf
.lfWidth
;
332 hfont
= create_font("bitmap", &bitmap_lf
);
333 old_hfont
= SelectObject(hdc
, hfont
);
334 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
335 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
336 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
337 SelectObject(hdc
, old_hfont
);
340 bitmap_lf
.lfHeight
= 0;
341 bitmap_lf
.lfWidth
= 4;
342 hfont
= create_font("bitmap", &bitmap_lf
);
343 old_hfont
= SelectObject(hdc
, hfont
);
344 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
345 SelectObject(hdc
, old_hfont
);
348 bitmap_lf
.lfHeight
= height_orig
;
349 bitmap_lf
.lfWidth
= lfWidth
;
351 /* test fractional scaling */
352 for (i
= 1; i
<= height_orig
* 6; i
++)
356 bitmap_lf
.lfHeight
= i
;
357 hfont
= create_font("fractional", &bitmap_lf
);
358 scale
= (i
+ height_orig
- 1) / height_orig
;
359 nearest_height
= scale
* height_orig
;
360 /* Only jump to the next height if the difference <= 25% original height */
361 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
362 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
363 so we'll not test this particular height. */
364 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
365 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
366 old_hfont
= SelectObject(hdc
, hfont
);
367 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
368 SelectObject(hdc
, old_hfont
);
372 /* test integer scaling 3x2 */
373 bitmap_lf
.lfHeight
= height_orig
* 2;
374 bitmap_lf
.lfWidth
*= 3;
375 hfont
= create_font("3x2", &bitmap_lf
);
376 old_hfont
= SelectObject(hdc
, hfont
);
377 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
378 SelectObject(hdc
, old_hfont
);
381 /* test integer scaling 3x3 */
382 bitmap_lf
.lfHeight
= height_orig
* 3;
383 bitmap_lf
.lfWidth
= 0;
384 hfont
= create_font("3x3", &bitmap_lf
);
385 old_hfont
= SelectObject(hdc
, hfont
);
386 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
387 SelectObject(hdc
, old_hfont
);
393 /* Test how GDI scales outline font metrics */
394 static void test_outline_font(void)
396 static const char test_str
[11] = "Test String";
399 HFONT hfont
, old_hfont
, old_hfont_2
;
400 OUTLINETEXTMETRICA otm
;
402 INT width_orig
, height_orig
, lfWidth
;
405 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
406 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
410 if (!is_truetype_font_installed("Arial"))
412 skip("Arial is not installed\n");
416 hdc
= CreateCompatibleDC(0);
418 memset(&lf
, 0, sizeof(lf
));
419 strcpy(lf
.lfFaceName
, "Arial");
421 hfont
= create_font("outline", &lf
);
422 old_hfont
= SelectObject(hdc
, hfont
);
423 otm
.otmSize
= sizeof(otm
);
424 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
425 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
426 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
428 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
429 SelectObject(hdc
, old_hfont
);
432 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
433 lf
.lfHeight
= otm
.otmEMSquare
;
434 lf
.lfHeight
= -lf
.lfHeight
;
435 hfont
= create_font("outline", &lf
);
436 old_hfont
= SelectObject(hdc
, hfont
);
437 otm
.otmSize
= sizeof(otm
);
438 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
439 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
440 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
441 SelectObject(hdc
, old_hfont
);
444 height_orig
= otm
.otmTextMetrics
.tmHeight
;
445 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
447 /* test integer scaling 3x2 */
448 lf
.lfHeight
= height_orig
* 2;
449 lf
.lfWidth
= lfWidth
* 3;
450 hfont
= create_font("3x2", &lf
);
451 old_hfont
= SelectObject(hdc
, hfont
);
452 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
453 SelectObject(hdc
, old_hfont
);
456 /* test integer scaling 3x3 */
457 lf
.lfHeight
= height_orig
* 3;
458 lf
.lfWidth
= lfWidth
* 3;
459 hfont
= create_font("3x3", &lf
);
460 old_hfont
= SelectObject(hdc
, hfont
);
461 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
462 SelectObject(hdc
, old_hfont
);
465 /* test integer scaling 1x1 */
466 lf
.lfHeight
= height_orig
* 1;
467 lf
.lfWidth
= lfWidth
* 1;
468 hfont
= create_font("1x1", &lf
);
469 old_hfont
= SelectObject(hdc
, hfont
);
470 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
471 SelectObject(hdc
, old_hfont
);
474 /* test integer scaling 1x1 */
475 lf
.lfHeight
= height_orig
;
477 hfont
= create_font("1x1", &lf
);
478 old_hfont
= SelectObject(hdc
, hfont
);
479 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
481 /* with an identity matrix */
482 memset(&gm
, 0, sizeof(gm
));
483 SetLastError(0xdeadbeef);
484 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
485 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
486 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
487 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
488 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
489 /* with a custom matrix */
490 memset(&gm
, 0, sizeof(gm
));
491 SetLastError(0xdeadbeef);
492 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
493 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
494 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
495 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
496 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
498 /* Test that changing the DC transformation affects only the font
499 * selected on this DC and doesn't affect the same font selected on
502 hdc_2
= CreateCompatibleDC(0);
503 old_hfont_2
= SelectObject(hdc_2
, hfont
);
504 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
506 SetMapMode(hdc
, MM_ANISOTROPIC
);
508 /* font metrics on another DC should be unchanged */
509 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
511 /* test restrictions of compatibility mode GM_COMPATIBLE */
512 /* part 1: rescaling only X should not change font scaling on screen.
513 So compressing the X axis by 2 is not done, and this
514 appears as X scaling of 2 that no one requested. */
515 SetWindowExtEx(hdc
, 100, 100, NULL
);
516 SetViewportExtEx(hdc
, 50, 100, NULL
);
517 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
518 /* font metrics on another DC should be unchanged */
519 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
521 /* part 2: rescaling only Y should change font scaling.
522 As also X is scaled by a factor of 2, but this is not
523 requested by the DC transformation, we get a scaling factor
524 of 2 in the X coordinate. */
525 SetViewportExtEx(hdc
, 100, 200, NULL
);
526 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
527 /* font metrics on another DC should be unchanged */
528 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
530 /* restore scaling */
531 SetMapMode(hdc
, MM_TEXT
);
533 /* font metrics on another DC should be unchanged */
534 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
536 SelectObject(hdc_2
, old_hfont_2
);
539 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
541 SelectObject(hdc
, old_hfont
);
544 skip("GM_ADVANCED is not supported on this platform\n");
555 SetLastError(0xdeadbeef);
556 ret
= SetWorldTransform(hdc
, &xform
);
557 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
559 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
561 /* with an identity matrix */
562 memset(&gm
, 0, sizeof(gm
));
563 SetLastError(0xdeadbeef);
564 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
565 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
566 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
567 pt
.x
= width_orig
; pt
.y
= 0;
569 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
570 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
571 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
572 /* with a custom matrix */
573 memset(&gm
, 0, sizeof(gm
));
574 SetLastError(0xdeadbeef);
575 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
576 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
577 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
578 pt
.x
= width_orig
; pt
.y
= 0;
580 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
581 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
582 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
584 SetLastError(0xdeadbeef);
585 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
586 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
588 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
590 /* with an identity matrix */
591 memset(&gm
, 0, sizeof(gm
));
592 SetLastError(0xdeadbeef);
593 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
594 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
595 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
596 pt
.x
= width_orig
; pt
.y
= 0;
598 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
599 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
600 /* with a custom matrix */
601 memset(&gm
, 0, sizeof(gm
));
602 SetLastError(0xdeadbeef);
603 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
604 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
605 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
606 pt
.x
= width_orig
; pt
.y
= 0;
608 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
609 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
611 SetLastError(0xdeadbeef);
612 ret
= SetMapMode(hdc
, MM_TEXT
);
613 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
615 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
617 /* with an identity matrix */
618 memset(&gm
, 0, sizeof(gm
));
619 SetLastError(0xdeadbeef);
620 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
621 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
622 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
623 pt
.x
= width_orig
; pt
.y
= 0;
625 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
626 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
627 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
628 /* with a custom matrix */
629 memset(&gm
, 0, sizeof(gm
));
630 SetLastError(0xdeadbeef);
631 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
632 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
633 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
634 pt
.x
= width_orig
; pt
.y
= 0;
636 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
637 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
638 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
640 SelectObject(hdc
, old_hfont
);
645 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
647 LOGFONT
*lf
= (LOGFONT
*)lParam
;
649 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
652 return 0; /* stop enumeration */
654 return 1; /* continue enumeration */
657 static void test_bitmap_font_metrics(void)
659 static const struct font_data
661 const char face_name
[LF_FACESIZE
];
662 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
663 int ave_char_width
, max_char_width
, dpi
;
667 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
668 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
669 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1
| FS_CYRILLIC
},
670 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2
},
671 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1
},
672 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2
},
673 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC
},
674 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1
},
675 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2
},
676 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC
},
677 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
679 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
680 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_LATIN2
},
681 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC
},
682 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
683 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1
| FS_LATIN2
},
684 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC
},
685 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
686 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
688 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
689 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
690 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
691 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
},
692 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2
| FS_CYRILLIC
},
693 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1
| FS_LATIN2
},
694 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC
},
695 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1
| FS_LATIN2
},
696 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC
},
697 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1
},
698 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2
},
699 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC
},
700 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1
},
701 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2
},
702 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC
},
703 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1
| FS_LATIN2
},
704 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC
},
706 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1
| FS_CYRILLIC
},
707 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2
},
708 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_CYRILLIC
},
709 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2
},
710 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1
| FS_CYRILLIC
},
711 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2
},
712 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1
| FS_LATIN2
},
713 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC
},
714 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1
| FS_LATIN2
},
715 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC
},
716 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
718 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
719 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
720 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
722 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
723 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
724 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
726 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
},
727 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2
| FS_CYRILLIC
},
729 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
730 * require a new system.sfd for that font
732 { "System", FW_BOLD
, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN
},
734 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1
},
735 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2
| FS_CYRILLIC
},
737 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1
},
738 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
739 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN
},
740 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1
},
741 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
742 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN
},
743 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1
},
744 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
745 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN
},
746 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1
},
747 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
748 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN
},
749 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
750 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
751 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN
},
752 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
753 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN
},
755 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1
| FS_JISJAPAN
},
756 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
757 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1
| FS_JISJAPAN
},
758 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
759 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1
| FS_JISJAPAN
},
760 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
761 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
762 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC
},
763 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
764 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC
},
765 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
766 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC
},
768 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
},
769 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC
},
770 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN
},
772 /* The 120dpi version still has its dpi marked as 96 */
773 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
775 /* FIXME: add "Terminal" */
779 HFONT hfont
, old_hfont
;
783 hdc
= CreateCompatibleDC(0);
786 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
790 memset(&lf
, 0, sizeof(lf
));
792 lf
.lfHeight
= fd
[i
].height
;
793 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
795 for(bit
= 0; bit
< 32; bit
++)
802 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
803 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
805 lf
.lfCharSet
= csi
.ciCharset
;
806 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
809 hfont
= create_font(lf
.lfFaceName
, &lf
);
810 old_hfont
= SelectObject(hdc
, hfont
);
811 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %d\n", GetLastError());
812 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
814 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
815 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
);
816 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
);
817 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
);
818 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
);
819 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
);
820 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
);
821 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
);
823 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
824 that make the max width bigger */
825 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
826 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
);
828 SelectObject(hdc
, old_hfont
);
836 static void test_GdiGetCharDimensions(void)
842 LONG avgwidth
, height
;
843 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
845 if (!pGdiGetCharDimensions
)
847 win_skip("GdiGetCharDimensions not available on this platform\n");
851 hdc
= CreateCompatibleDC(NULL
);
853 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
854 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
856 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
857 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
858 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
860 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
861 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
863 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
864 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
867 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
868 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
869 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
874 static void test_GetCharABCWidths(void)
876 static const WCHAR str
[] = {'a',0};
885 if (!pGetCharABCWidthsW
|| !pGetCharABCWidthsI
)
887 win_skip("GetCharABCWidthsW/I not available on this platform\n");
891 memset(&lf
, 0, sizeof(lf
));
892 strcpy(lf
.lfFaceName
, "System");
895 hfont
= CreateFontIndirectA(&lf
);
897 hfont
= SelectObject(hdc
, hfont
);
899 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
900 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
902 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
903 ok(!ret
, "GetCharABCWidthsI should have failed\n");
905 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
906 ok(!ret
, "GetCharABCWidthsI should have failed\n");
908 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
909 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
911 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
912 ok(!ret
, "GetCharABCWidthsW should have failed\n");
914 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
915 ok(!ret
, "GetCharABCWidthsW should have failed\n");
917 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
918 ok(!ret
, "GetCharABCWidthsW should have failed\n");
920 hfont
= SelectObject(hdc
, hfont
);
922 ReleaseDC(NULL
, hdc
);
925 static void test_text_extents(void)
927 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
929 INT i
, len
, fit1
, fit2
;
937 memset(&lf
, 0, sizeof(lf
));
938 strcpy(lf
.lfFaceName
, "Arial");
941 hfont
= CreateFontIndirectA(&lf
);
943 hfont
= SelectObject(hdc
, hfont
);
944 GetTextMetricsA(hdc
, &tm
);
945 GetTextExtentPointA(hdc
, "o", 1, &sz
);
946 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
948 SetLastError(0xdeadbeef);
949 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
950 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
952 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
953 hfont
= SelectObject(hdc
, hfont
);
960 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
961 extents
[0] = 1; /* So that the increasing sequence test will fail
962 if the extents array is untouched. */
963 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
964 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
966 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
967 /* Because of the '\n' in the string GetTextExtentExPoint and
968 GetTextExtentPoint return different widths under Win2k, but
969 under WinXP they return the same width. So we don't test that
972 for (i
= 1; i
< len
; ++i
)
973 ok(extents
[i
-1] <= extents
[i
],
974 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
976 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
977 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
978 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
979 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
980 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
981 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
982 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
983 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
984 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
985 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
986 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
987 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
988 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
989 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
990 HeapFree(GetProcessHeap(), 0, extents
);
992 hfont
= SelectObject(hdc
, hfont
);
994 ReleaseDC(NULL
, hdc
);
997 static void test_GetGlyphIndices(void)
1004 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1005 WORD glyphs
[(sizeof(testtext
)/2)-1];
1009 if (!pGetGlyphIndicesW
) {
1010 win_skip("GetGlyphIndicesW not available on platform\n");
1016 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1017 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1018 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1019 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1020 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1022 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1023 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1024 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1025 textm
.tmDefaultChar
, glyphs
[4]);
1027 if(!is_font_installed("Tahoma"))
1029 skip("Tahoma is not installed so skipping this test\n");
1032 memset(&lf
, 0, sizeof(lf
));
1033 strcpy(lf
.lfFaceName
, "Tahoma");
1036 hfont
= CreateFontIndirectA(&lf
);
1037 hOldFont
= SelectObject(hdc
, hfont
);
1038 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1039 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1040 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1041 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1042 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1044 testtext
[0] = textm
.tmDefaultChar
;
1045 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1046 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1047 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1048 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1049 DeleteObject(SelectObject(hdc
, hOldFont
));
1052 static void test_GetKerningPairs(void)
1054 static const struct kerning_data
1056 const char face_name
[LF_FACESIZE
];
1058 /* some interesting fields from OUTLINETEXTMETRIC */
1059 LONG tmHeight
, tmAscent
, tmDescent
;
1064 UINT otmsCapEmHeight
;
1069 UINT otmusMinimumPPEM
;
1070 /* small subset of kerning pairs to test */
1071 DWORD total_kern_pairs
;
1072 const KERNINGPAIR kern_pair
[26];
1075 {"Arial", 12, 12, 9, 3,
1076 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1079 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1080 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1081 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1082 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1083 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1084 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1085 {933,970,+1},{933,972,-1}
1088 {"Arial", -34, 39, 32, 7,
1089 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1092 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1093 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1094 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1095 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1096 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1097 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1098 {933,970,+2},{933,972,-3}
1101 { "Arial", 120, 120, 97, 23,
1102 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1105 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1106 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1107 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1108 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1109 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1110 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1111 {933,970,+6},{933,972,-10}
1114 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1115 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1116 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1119 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1120 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1121 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1122 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1123 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1124 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1125 {933,970,+54},{933,972,-83}
1131 HFONT hfont
, hfont_old
;
1132 KERNINGPAIR
*kern_pair
;
1134 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1138 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1139 * which may render this test unusable, so we're trying to avoid that.
1141 SetLastError(0xdeadbeef);
1142 GetKerningPairsW(hdc
, 0, NULL
);
1143 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1145 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1150 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1152 OUTLINETEXTMETRICW otm
;
1154 if (!is_font_installed(kd
[i
].face_name
))
1156 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1160 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1162 memset(&lf
, 0, sizeof(lf
));
1163 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1164 lf
.lfHeight
= kd
[i
].height
;
1165 hfont
= CreateFontIndirect(&lf
);
1168 hfont_old
= SelectObject(hdc
, hfont
);
1170 SetLastError(0xdeadbeef);
1171 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1172 ok(GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
) == sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1174 ok(match_off_by_1(kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
), "expected %d, got %d\n",
1175 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1176 ok(match_off_by_1(kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
), "expected %d, got %d\n",
1177 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1178 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1179 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1181 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1182 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1183 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1184 kd
[i
].otmAscent
, otm
.otmAscent
);
1185 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1186 kd
[i
].otmDescent
, otm
.otmDescent
);
1187 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1188 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1189 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1190 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1191 ok(near_match(kd
[i
].otmMacAscent
, otm
.otmMacAscent
), "expected %d, got %d\n",
1192 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1194 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1195 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1196 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1197 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1198 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1199 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1200 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1201 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1202 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1205 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1206 trace("total_kern_pairs %u\n", total_kern_pairs
);
1207 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1209 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1210 SetLastError(0xdeadbeef);
1211 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1212 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1213 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1214 ok(ret
== 0, "got %lu, expected 0\n", ret
);
1217 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1218 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1220 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1221 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1223 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1224 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1228 for (n
= 0; n
< ret
; n
++)
1232 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1233 trace("{'%c','%c',%d},\n",
1234 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1236 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1238 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1239 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1241 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1242 "pair %d:%d got %d, expected %d\n",
1243 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1244 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1250 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1251 matches
, kd
[i
].total_kern_pairs
);
1253 HeapFree(GetProcessHeap(), 0, kern_pair
);
1255 SelectObject(hdc
, hfont_old
);
1256 DeleteObject(hfont
);
1262 static void test_height_selection(void)
1264 static const struct font_data
1266 const char face_name
[LF_FACESIZE
];
1267 int requested_height
;
1268 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
, dpi
;
1271 {"Tahoma", -12, FW_NORMAL
, 14, 12, 2, 2, 0, 96 },
1272 {"Tahoma", -24, FW_NORMAL
, 29, 24, 5, 5, 0, 96 },
1273 {"Tahoma", -48, FW_NORMAL
, 58, 48, 10, 10, 0, 96 },
1274 {"Tahoma", -96, FW_NORMAL
, 116, 96, 20, 20, 0, 96 },
1275 {"Tahoma", -192, FW_NORMAL
, 232, 192, 40, 40, 0, 96 },
1276 {"Tahoma", 12, FW_NORMAL
, 12, 10, 2, 2, 0, 96 },
1277 {"Tahoma", 24, FW_NORMAL
, 24, 20, 4, 4, 0, 96 },
1278 {"Tahoma", 48, FW_NORMAL
, 48, 40, 8, 8, 0, 96 },
1279 {"Tahoma", 96, FW_NORMAL
, 96, 80, 16, 17, 0, 96 },
1280 {"Tahoma", 192, FW_NORMAL
, 192, 159, 33, 33, 0, 96 }
1284 HFONT hfont
, old_hfont
;
1288 hdc
= CreateCompatibleDC(0);
1291 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
1293 if (!is_truetype_font_installed(fd
[i
].face_name
))
1295 skip("%s is not installed\n", fd
[i
].face_name
);
1299 memset(&lf
, 0, sizeof(lf
));
1300 lf
.lfHeight
= fd
[i
].requested_height
;
1301 lf
.lfWeight
= fd
[i
].weight
;
1302 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
1304 hfont
= CreateFontIndirect(&lf
);
1307 old_hfont
= SelectObject(hdc
, hfont
);
1308 ret
= GetTextMetrics(hdc
, &tm
);
1309 ok(ret
, "GetTextMetrics error %d\n", GetLastError());
1310 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
1312 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
1313 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
);
1314 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
);
1315 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
);
1316 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
);
1317 #if 0 /* FIXME: calculation of tmInternalLeading in Wine doesn't match what Windows does */
1318 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
);
1320 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
);
1323 SelectObject(hdc
, old_hfont
);
1324 DeleteObject(hfont
);
1330 static void test_GetOutlineTextMetrics(void)
1332 OUTLINETEXTMETRIC
*otm
;
1334 HFONT hfont
, hfont_old
;
1336 DWORD ret
, otm_size
;
1339 if (!is_font_installed("Arial"))
1341 skip("Arial is not installed\n");
1347 memset(&lf
, 0, sizeof(lf
));
1348 strcpy(lf
.lfFaceName
, "Arial");
1350 lf
.lfWeight
= FW_NORMAL
;
1351 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1352 lf
.lfQuality
= PROOF_QUALITY
;
1353 hfont
= CreateFontIndirect(&lf
);
1356 hfont_old
= SelectObject(hdc
, hfont
);
1357 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1358 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1360 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1362 memset(otm
, 0xAA, otm_size
);
1363 SetLastError(0xdeadbeef);
1364 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1365 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1366 ok(ret
== 1 /* Win9x */ ||
1367 ret
== otm
->otmSize
/* XP*/,
1368 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1369 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1371 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1372 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1373 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1374 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1377 memset(otm
, 0xAA, otm_size
);
1378 SetLastError(0xdeadbeef);
1379 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1380 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1381 ok(ret
== 1 /* Win9x */ ||
1382 ret
== otm
->otmSize
/* XP*/,
1383 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1384 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1386 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1387 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1388 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1389 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1392 /* ask about truncated data */
1393 memset(otm
, 0xAA, otm_size
);
1394 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1395 SetLastError(0xdeadbeef);
1396 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1397 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1398 ok(ret
== 1 /* Win9x */ ||
1399 ret
== otm
->otmSize
/* XP*/,
1400 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1401 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1403 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1404 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1405 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1407 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1409 HeapFree(GetProcessHeap(), 0, otm
);
1411 SelectObject(hdc
, hfont_old
);
1412 DeleteObject(hfont
);
1417 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1421 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
1422 areaWidth
= clientArea
->right
- clientArea
->left
,
1424 BOOL lastExtent
= FALSE
;
1425 PSTR pFirstChar
, pLastChar
;
1431 int GetTextExtentExPointWWidth
;
1434 GetTextMetricsA(hdc
, &tm
);
1435 y
= clientArea
->top
;
1438 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1444 /* if not at the end of the string, ... */
1445 if (*str
== '\0') break;
1446 /* ... add the next word to the current extent */
1447 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1449 SetTextJustification(hdc
, 0, 0);
1450 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1451 } while ((int) size
.cx
< areaWidth
);
1453 /* ignore trailing break chars */
1455 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1461 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1463 SetTextJustification(hdc
, 0, 0);
1464 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1466 /* do not justify the last extent */
1467 if (*str
!= '\0' && breakCount
> 0)
1469 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1470 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1471 justifiedWidth
= size
.cx
;
1473 else lastExtent
= TRUE
;
1475 /* catch errors and report them */
1476 if (!lastExtent
&& (justifiedWidth
!= areaWidth
))
1478 memset(error
[nErrors
].extent
, 0, 100);
1479 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
1480 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
1486 } while (*str
&& y
< clientArea
->bottom
);
1488 for (e
= 0; e
< nErrors
; e
++)
1490 /* The width returned by GetTextExtentPoint32() is exactly the same
1491 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1492 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1493 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1494 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1498 static void test_SetTextJustification(void)
1505 static char testText
[] =
1506 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1507 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1508 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1509 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1510 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1511 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1512 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1514 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1515 GetClientRect( hwnd
, &clientArea
);
1516 hdc
= GetDC( hwnd
);
1518 memset(&lf
, 0, sizeof lf
);
1519 lf
.lfCharSet
= ANSI_CHARSET
;
1520 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1521 lf
.lfWeight
= FW_DONTCARE
;
1523 lf
.lfQuality
= DEFAULT_QUALITY
;
1524 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1525 hfont
= create_font("Times New Roman", &lf
);
1526 SelectObject(hdc
, hfont
);
1528 testJustification(hdc
, testText
, &clientArea
);
1530 DeleteObject(hfont
);
1531 ReleaseDC(hwnd
, hdc
);
1532 DestroyWindow(hwnd
);
1535 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1539 HFONT hfont
, hfont_old
;
1546 assert(count
<= 128);
1548 memset(&lf
, 0, sizeof(lf
));
1550 lf
.lfCharSet
= charset
;
1552 lstrcpyA(lf
.lfFaceName
, "Arial");
1553 SetLastError(0xdeadbeef);
1554 hfont
= CreateFontIndirectA(&lf
);
1555 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1558 hfont_old
= SelectObject(hdc
, hfont
);
1560 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1561 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1563 SetLastError(0xdeadbeef);
1564 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1565 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1567 if (charset
== SYMBOL_CHARSET
)
1569 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1570 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1574 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1575 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1578 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1580 trace("Can't find codepage for charset %d\n", cs
);
1584 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1589 WCHAR unicode_buf
[128];
1591 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1593 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1595 SetLastError(0xdeadbeef);
1596 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1597 ok(ret
== count
, "GetGlyphIndicesW error %u\n", GetLastError());
1603 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1605 SetLastError(0xdeadbeef);
1606 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1607 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1610 SelectObject(hdc
, hfont_old
);
1611 DeleteObject(hfont
);
1618 static void test_font_charset(void)
1620 static struct charset_data
1624 WORD font_idxA
[128], font_idxW
[128];
1627 { ANSI_CHARSET
, 1252 },
1628 { RUSSIAN_CHARSET
, 1251 },
1629 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1633 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1635 win_skip("Skipping the font charset test on a Win9x platform\n");
1639 if (!is_font_installed("Arial"))
1641 skip("Arial is not installed\n");
1645 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1647 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1649 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1651 skip("Symbol or Wingdings is not installed\n");
1655 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
);
1656 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
);
1657 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1660 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1663 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1664 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1667 skip("Symbol or Wingdings is not installed\n");
1670 static void test_GetFontUnicodeRanges(void)
1674 HFONT hfont
, hfont_old
;
1678 if (!pGetFontUnicodeRanges
)
1680 win_skip("GetFontUnicodeRanges not available before W2K\n");
1684 memset(&lf
, 0, sizeof(lf
));
1685 lstrcpyA(lf
.lfFaceName
, "Arial");
1686 hfont
= create_font("Arial", &lf
);
1689 hfont_old
= SelectObject(hdc
, hfont
);
1691 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1692 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1694 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1695 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1697 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1699 size
= pGetFontUnicodeRanges(hdc
, gs
);
1700 ok(size
, "GetFontUnicodeRanges failed\n");
1702 for (i
= 0; i
< gs
->cRanges
; i
++)
1703 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1705 trace("found %u ranges\n", gs
->cRanges
);
1707 HeapFree(GetProcessHeap(), 0, gs
);
1709 SelectObject(hdc
, hfont_old
);
1710 DeleteObject(hfont
);
1711 ReleaseDC(NULL
, hdc
);
1714 #define MAX_ENUM_FONTS 4096
1716 struct enum_font_data
1719 LOGFONT lf
[MAX_ENUM_FONTS
];
1722 struct enum_font_dataW
1725 LOGFONTW lf
[MAX_ENUM_FONTS
];
1728 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1730 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1732 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1734 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1736 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1737 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1739 if (efd
->total
< MAX_ENUM_FONTS
)
1740 efd
->lf
[efd
->total
++] = *lf
;
1742 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1747 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
1749 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
1751 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1753 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1755 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1756 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1758 if (efd
->total
< MAX_ENUM_FONTS
)
1759 efd
->lf
[efd
->total
++] = *lf
;
1761 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1766 static void get_charset_stats(struct enum_font_data
*efd
,
1767 int *ansi_charset
, int *symbol_charset
,
1768 int *russian_charset
)
1773 *symbol_charset
= 0;
1774 *russian_charset
= 0;
1776 for (i
= 0; i
< efd
->total
; i
++)
1778 switch (efd
->lf
[i
].lfCharSet
)
1783 case SYMBOL_CHARSET
:
1784 (*symbol_charset
)++;
1786 case RUSSIAN_CHARSET
:
1787 (*russian_charset
)++;
1793 static void get_charset_statsW(struct enum_font_dataW
*efd
,
1794 int *ansi_charset
, int *symbol_charset
,
1795 int *russian_charset
)
1800 *symbol_charset
= 0;
1801 *russian_charset
= 0;
1803 for (i
= 0; i
< efd
->total
; i
++)
1805 switch (efd
->lf
[i
].lfCharSet
)
1810 case SYMBOL_CHARSET
:
1811 (*symbol_charset
)++;
1813 case RUSSIAN_CHARSET
:
1814 (*russian_charset
)++;
1820 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1822 struct enum_font_data efd
;
1823 struct enum_font_dataW efdw
;
1826 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1828 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1830 if (*font_name
&& !is_truetype_font_installed(font_name
))
1832 skip("%s is not installed\n", font_name
);
1838 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1839 * while EnumFontFamiliesEx doesn't.
1841 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1844 * Use EnumFontFamiliesW since win98 crashes when the
1845 * second parameter is NULL using EnumFontFamilies
1848 SetLastError(0xdeadbeef);
1849 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
1850 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
1853 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1854 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1855 ansi_charset
, symbol_charset
, russian_charset
);
1856 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
1857 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1858 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1859 ok(russian_charset
> 0 ||
1860 broken(russian_charset
== 0), /* NT4 */
1861 "NULL family should enumerate RUSSIAN_CHARSET\n");
1865 SetLastError(0xdeadbeef);
1866 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
1867 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
1870 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1871 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1872 ansi_charset
, symbol_charset
, russian_charset
);
1873 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
1874 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1875 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1876 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1881 SetLastError(0xdeadbeef);
1882 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
1883 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1884 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1885 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1886 ansi_charset
, symbol_charset
, russian_charset
,
1887 *font_name
? font_name
: "<empty>");
1889 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1891 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
1892 for (i
= 0; i
< efd
.total
; i
++)
1894 /* FIXME: remove completely once Wine is fixed */
1895 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
1898 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1901 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1902 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1903 font_name
, efd
.lf
[i
].lfFaceName
);
1906 memset(&lf
, 0, sizeof(lf
));
1907 lf
.lfCharSet
= ANSI_CHARSET
;
1908 lstrcpy(lf
.lfFaceName
, font_name
);
1910 SetLastError(0xdeadbeef);
1911 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1912 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1913 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1914 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1915 ansi_charset
, symbol_charset
, russian_charset
,
1916 *font_name
? font_name
: "<empty>");
1917 if (font_charset
== SYMBOL_CHARSET
)
1920 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
1922 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1926 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
1927 for (i
= 0; i
< efd
.total
; i
++)
1929 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1931 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1932 font_name
, efd
.lf
[i
].lfFaceName
);
1936 /* DEFAULT_CHARSET should enumerate all available charsets */
1937 memset(&lf
, 0, sizeof(lf
));
1938 lf
.lfCharSet
= DEFAULT_CHARSET
;
1939 lstrcpy(lf
.lfFaceName
, font_name
);
1941 SetLastError(0xdeadbeef);
1942 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1943 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1944 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1945 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1946 ansi_charset
, symbol_charset
, russian_charset
,
1947 *font_name
? font_name
: "<empty>");
1948 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
1949 for (i
= 0; i
< efd
.total
; i
++)
1952 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1953 font_name
, efd
.lf
[i
].lfFaceName
);
1957 switch (font_charset
)
1960 ok(ansi_charset
> 0,
1961 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1963 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
1964 ok(russian_charset
> 0,
1965 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1967 case SYMBOL_CHARSET
:
1969 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
1971 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1972 ok(!russian_charset
,
1973 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1975 case DEFAULT_CHARSET
:
1976 ok(ansi_charset
> 0,
1977 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1978 ok(symbol_charset
> 0,
1979 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1980 ok(russian_charset
> 0,
1981 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1987 ok(ansi_charset
> 0,
1988 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1989 ok(symbol_charset
> 0,
1990 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1991 ok(russian_charset
> 0,
1992 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1995 memset(&lf
, 0, sizeof(lf
));
1996 lf
.lfCharSet
= SYMBOL_CHARSET
;
1997 lstrcpy(lf
.lfFaceName
, font_name
);
1999 SetLastError(0xdeadbeef);
2000 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
2001 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
2002 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
2003 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
2004 ansi_charset
, symbol_charset
, russian_charset
,
2005 *font_name
? font_name
: "<empty>");
2006 if (*font_name
&& font_charset
== ANSI_CHARSET
)
2007 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
2010 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
2011 for (i
= 0; i
< efd
.total
; i
++)
2013 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
2015 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
2016 font_name
, efd
.lf
[i
].lfFaceName
);
2020 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2021 ok(symbol_charset
> 0,
2022 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2023 ok(!russian_charset
,
2024 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
2030 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
2032 HFONT hfont
, hfont_prev
;
2034 GLYPHMETRICS gm1
, gm2
;
2037 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
2039 if(!pGetGlyphIndicesA
)
2042 /* negative widths are handled just as positive ones */
2043 lf2
.lfWidth
= -lf
->lfWidth
;
2045 SetLastError(0xdeadbeef);
2046 hfont
= CreateFontIndirectA(lf
);
2047 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2048 check_font("original", lf
, hfont
);
2050 hfont_prev
= SelectObject(hdc
, hfont
);
2052 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
2053 if (ret
== GDI_ERROR
|| idx
== 0xffff)
2055 SelectObject(hdc
, hfont_prev
);
2056 DeleteObject(hfont
);
2057 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
2061 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
2062 memset(&gm1
, 0xab, sizeof(gm1
));
2063 SetLastError(0xdeadbeef);
2064 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
2065 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2067 SelectObject(hdc
, hfont_prev
);
2068 DeleteObject(hfont
);
2070 SetLastError(0xdeadbeef);
2071 hfont
= CreateFontIndirectA(&lf2
);
2072 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2073 check_font("negative width", &lf2
, hfont
);
2075 hfont_prev
= SelectObject(hdc
, hfont
);
2077 memset(&gm2
, 0xbb, sizeof(gm2
));
2078 SetLastError(0xdeadbeef);
2079 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2080 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2082 SelectObject(hdc
, hfont_prev
);
2083 DeleteObject(hfont
);
2085 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2086 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2087 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2088 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2089 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2090 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2091 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2092 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2093 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2094 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2095 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2098 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2099 #include "pshpack2.h"
2103 SHORT xAvgCharWidth
;
2104 USHORT usWeightClass
;
2105 USHORT usWidthClass
;
2107 SHORT ySubscriptXSize
;
2108 SHORT ySubscriptYSize
;
2109 SHORT ySubscriptXOffset
;
2110 SHORT ySubscriptYOffset
;
2111 SHORT ySuperscriptXSize
;
2112 SHORT ySuperscriptYSize
;
2113 SHORT ySuperscriptXOffset
;
2114 SHORT ySuperscriptYOffset
;
2115 SHORT yStrikeoutSize
;
2116 SHORT yStrikeoutPosition
;
2119 ULONG ulUnicodeRange1
;
2120 ULONG ulUnicodeRange2
;
2121 ULONG ulUnicodeRange3
;
2122 ULONG ulUnicodeRange4
;
2125 USHORT usFirstCharIndex
;
2126 USHORT usLastCharIndex
;
2127 /* According to the Apple spec, original version didn't have the below fields,
2128 * version numbers were taked from the OpenType spec.
2130 /* version 0 (TrueType 1.5) */
2131 USHORT sTypoAscender
;
2132 USHORT sTypoDescender
;
2133 USHORT sTypoLineGap
;
2135 USHORT usWinDescent
;
2136 /* version 1 (TrueType 1.66) */
2137 ULONG ulCodePageRange1
;
2138 ULONG ulCodePageRange2
;
2139 /* version 2 (OpenType 1.2) */
2142 USHORT usDefaultChar
;
2144 USHORT usMaxContext
;
2146 #include "poppack.h"
2148 #ifdef WORDS_BIGENDIAN
2149 #define GET_BE_WORD(x) (x)
2150 #define GET_BE_DWORD(x) (x)
2152 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2153 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2156 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2157 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2158 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2159 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2160 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2173 } cmap_encoding_record
;
2181 BYTE glyph_ids
[256];
2191 USHORT search_range
;
2192 USHORT entry_selector
;
2195 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2198 USHORT start_count[seg_countx2 / 2];
2199 USHORT id_delta[seg_countx2 / 2];
2200 USHORT id_range_offset[seg_countx2 / 2];
2210 USHORT id_range_offset
;
2211 } cmap_format_4_seg
;
2213 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2215 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2216 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2217 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2220 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2223 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2227 for(i
= 0; i
< 256; i
++)
2229 if(cmap
->glyph_ids
[i
] == 0) continue;
2231 if(*first
== 256) *first
= i
;
2233 if(*first
== 256) return FALSE
;
2237 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2239 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2240 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2241 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2242 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2243 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2246 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2249 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2250 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2251 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2255 for(i
= 0; i
< seg_count
; i
++)
2258 cmap_format_4_seg seg
;
2260 get_seg4(cmap
, i
, &seg
);
2261 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2263 if(seg
.id_range_offset
== 0)
2264 index
= (seg
.id_delta
+ code
) & 0xffff;
2267 index
= seg
.id_range_offset
/ 2
2268 + code
- seg
.start_count
2271 /* some fonts have broken last segment */
2272 if ((char *)(glyph_ids
+ index
+ sizeof(*glyph_ids
)) < (char *)ptr
+ limit
)
2273 index
= GET_BE_WORD(glyph_ids
[index
]);
2276 trace("segment %04x/%04x index %04x points to nowhere\n",
2277 seg
.start_count
, seg
.end_count
, index
);
2280 if(index
) index
+= seg
.id_delta
;
2282 if(*first
== 0x10000)
2283 *last
= *first
= code
;
2289 if(*first
== 0x10000) return FALSE
;
2293 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2296 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2298 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2300 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2301 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2314 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2317 cmap_header
*header
;
2322 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2323 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2324 if(size
== GDI_ERROR
) return FALSE
;
2326 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2327 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2328 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2329 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2331 cmap
= get_cmap(header
, 3, 1);
2333 *cmap_type
= cmap_ms_unicode
;
2336 cmap
= get_cmap(header
, 3, 0);
2337 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2341 *cmap_type
= cmap_none
;
2345 format
= GET_BE_WORD(*(WORD
*)cmap
);
2349 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2352 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2355 trace("unhandled cmap format %d\n", format
);
2360 HeapFree(GetProcessHeap(), 0, header
);
2364 static void test_text_metrics(const LOGFONTA
*lf
)
2367 HFONT hfont
, hfont_old
;
2371 const char *font_name
= lf
->lfFaceName
;
2372 DWORD cmap_first
= 0, cmap_last
= 0;
2373 cmap_type cmap_type
;
2377 SetLastError(0xdeadbeef);
2378 hfont
= CreateFontIndirectA(lf
);
2379 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2381 hfont_old
= SelectObject(hdc
, hfont
);
2383 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2384 if (size
== GDI_ERROR
)
2386 trace("OS/2 chunk was not found\n");
2389 if (size
> sizeof(tt_os2
))
2391 trace("got too large OS/2 chunk of size %u\n", size
);
2392 size
= sizeof(tt_os2
);
2395 memset(&tt_os2
, 0, sizeof(tt_os2
));
2396 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2397 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2399 SetLastError(0xdeadbeef);
2400 ret
= GetTextMetricsA(hdc
, &tmA
);
2401 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2403 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
2405 skip("Unable to retrieve first and last glyphs from cmap\n");
2409 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
2410 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
2411 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
2415 version
= GET_BE_WORD(tt_os2
.version
);
2417 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2418 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2419 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2420 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2422 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2423 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
2424 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
2426 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
2431 case 1257: /* Baltic */
2432 expect_last_W
= 0xf8fd;
2435 expect_last_W
= 0xf0ff;
2437 expect_break_W
= 0x20;
2438 expect_default_W
= expect_break_W
- 1;
2439 expect_first_A
= 0x1e;
2440 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
2444 expect_first_W
= cmap_first
;
2445 expect_last_W
= min(cmap_last
, os2_last_char
);
2446 if(os2_first_char
<= 1)
2447 expect_break_W
= os2_first_char
+ 2;
2448 else if(os2_first_char
> 0xff)
2449 expect_break_W
= 0x20;
2451 expect_break_W
= os2_first_char
;
2452 expect_default_W
= expect_break_W
- 1;
2453 expect_first_A
= expect_default_W
- 1;
2454 expect_last_A
= min(expect_last_W
, 0xff);
2456 expect_break_A
= expect_break_W
;
2457 expect_default_A
= expect_default_W
;
2459 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2460 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
2461 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
2462 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2463 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2465 ok(tmA
.tmFirstChar
== expect_first_A
||
2466 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2467 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2468 ok(tmA
.tmLastChar
== expect_last_A
||
2469 tmA
.tmLastChar
== 0xff /* win9x */,
2470 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
2471 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
2472 font_name
, tmA
.tmBreakChar
, expect_break_A
);
2473 ok(tmA
.tmDefaultChar
== expect_default_A
, "A: tmDefaultChar for %s got %02x expected %02x\n",
2474 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
2477 SetLastError(0xdeadbeef);
2478 ret
= GetTextMetricsW(hdc
, &tmW
);
2479 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2480 "GetTextMetricsW error %u\n", GetLastError());
2483 /* Wine uses the os2 first char */
2484 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
2485 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2486 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2488 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2489 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2491 /* Wine uses the os2 last char */
2492 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
2493 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2494 font_name
, tmW
.tmLastChar
, expect_last_W
);
2496 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2497 font_name
, tmW
.tmLastChar
, expect_last_W
);
2498 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
2499 font_name
, tmW
.tmBreakChar
, expect_break_W
);
2500 ok(tmW
.tmDefaultChar
== expect_default_W
, "W: tmDefaultChar for %s got %02x expected %02x\n",
2501 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
2503 /* Test the aspect ratio while we have tmW */
2504 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2505 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2506 tmW
.tmDigitizedAspectX
, ret
);
2507 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2508 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2509 tmW
.tmDigitizedAspectX
, ret
);
2513 /* test FF_ values */
2514 switch(tt_os2
.panose
.bFamilyType
)
2518 case PAN_FAMILY_TEXT_DISPLAY
:
2519 case PAN_FAMILY_PICTORIAL
:
2521 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
2522 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
2524 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
2527 switch(tt_os2
.panose
.bSerifStyle
)
2532 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
2535 case PAN_SERIF_COVE
:
2536 case PAN_SERIF_OBTUSE_COVE
:
2537 case PAN_SERIF_SQUARE_COVE
:
2538 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
2539 case PAN_SERIF_SQUARE
:
2540 case PAN_SERIF_THIN
:
2541 case PAN_SERIF_BONE
:
2542 case PAN_SERIF_EXAGGERATED
:
2543 case PAN_SERIF_TRIANGLE
:
2544 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
2547 case PAN_SERIF_NORMAL_SANS
:
2548 case PAN_SERIF_OBTUSE_SANS
:
2549 case PAN_SERIF_PERP_SANS
:
2550 case PAN_SERIF_FLARED
:
2551 case PAN_SERIF_ROUNDED
:
2552 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
2557 case PAN_FAMILY_SCRIPT
:
2558 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
2561 case PAN_FAMILY_DECORATIVE
:
2562 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
2566 test_negative_width(hdc
, lf
);
2569 SelectObject(hdc
, hfont_old
);
2570 DeleteObject(hfont
);
2575 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2577 INT
*enumed
= (INT
*)lParam
;
2579 if (type
== TRUETYPE_FONTTYPE
)
2582 test_text_metrics(lf
);
2587 static void test_GetTextMetrics(void)
2593 /* Report only once */
2594 if(!pGetGlyphIndicesA
)
2595 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2599 memset(&lf
, 0, sizeof(lf
));
2600 lf
.lfCharSet
= DEFAULT_CHARSET
;
2602 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2603 trace("Tested metrics of %d truetype fonts\n", enumed
);
2608 static void test_nonexistent_font(void)
2616 { "Times New Roman Baltic", 186 },
2617 { "Times New Roman CE", 238 },
2618 { "Times New Roman CYR", 204 },
2619 { "Times New Roman Greek", 161 },
2620 { "Times New Roman TUR", 162 }
2626 INT cs
, expected_cs
, i
;
2627 char buf
[LF_FACESIZE
];
2629 if (!is_truetype_font_installed("Arial") ||
2630 !is_truetype_font_installed("Times New Roman"))
2632 skip("Arial or Times New Roman not installed\n");
2636 expected_cs
= GetACP();
2637 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
2639 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
2642 expected_cs
= csi
.ciCharset
;
2643 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
2647 memset(&lf
, 0, sizeof(lf
));
2649 lf
.lfWeight
= FW_REGULAR
;
2650 lf
.lfCharSet
= ANSI_CHARSET
;
2651 lf
.lfPitchAndFamily
= FF_SWISS
;
2652 strcpy(lf
.lfFaceName
, "Nonexistent font");
2653 hfont
= CreateFontIndirectA(&lf
);
2654 hfont
= SelectObject(hdc
, hfont
);
2655 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2656 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
2657 cs
= GetTextCharset(hdc
);
2658 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2659 DeleteObject(SelectObject(hdc
, hfont
));
2661 memset(&lf
, 0, sizeof(lf
));
2663 lf
.lfWeight
= FW_DONTCARE
;
2664 strcpy(lf
.lfFaceName
, "Nonexistent font");
2665 hfont
= CreateFontIndirectA(&lf
);
2666 hfont
= SelectObject(hdc
, hfont
);
2667 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2668 todo_wine
/* Wine uses Arial for all substitutions */
2669 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
2670 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
2671 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2673 cs
= GetTextCharset(hdc
);
2674 ok(cs
== expected_cs
, "expected %d, got %d\n", expected_cs
, cs
);
2675 DeleteObject(SelectObject(hdc
, hfont
));
2677 memset(&lf
, 0, sizeof(lf
));
2679 lf
.lfWeight
= FW_REGULAR
;
2680 strcpy(lf
.lfFaceName
, "Nonexistent font");
2681 hfont
= CreateFontIndirectA(&lf
);
2682 hfont
= SelectObject(hdc
, hfont
);
2683 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2684 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2685 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
2686 cs
= GetTextCharset(hdc
);
2687 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2688 DeleteObject(SelectObject(hdc
, hfont
));
2690 memset(&lf
, 0, sizeof(lf
));
2692 lf
.lfWeight
= FW_DONTCARE
;
2693 strcpy(lf
.lfFaceName
, "Times New Roman");
2694 hfont
= CreateFontIndirectA(&lf
);
2695 hfont
= SelectObject(hdc
, hfont
);
2696 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2697 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
2698 cs
= GetTextCharset(hdc
);
2699 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2700 DeleteObject(SelectObject(hdc
, hfont
));
2702 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
2704 memset(&lf
, 0, sizeof(lf
));
2706 lf
.lfWeight
= FW_REGULAR
;
2707 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2708 hfont
= CreateFontIndirectA(&lf
);
2709 hfont
= SelectObject(hdc
, hfont
);
2710 cs
= GetTextCharset(hdc
);
2711 if (font_subst
[i
].charset
== expected_cs
)
2713 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2714 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2715 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
2719 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
2720 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2721 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2722 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
2724 DeleteObject(SelectObject(hdc
, hfont
));
2726 memset(&lf
, 0, sizeof(lf
));
2728 lf
.lfWeight
= FW_DONTCARE
;
2729 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2730 hfont
= CreateFontIndirectA(&lf
);
2731 hfont
= SelectObject(hdc
, hfont
);
2732 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2733 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
2734 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
2735 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
2736 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2737 "got %s for font %s\n", buf
, font_subst
[i
].name
);
2738 cs
= GetTextCharset(hdc
);
2739 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2740 DeleteObject(SelectObject(hdc
, hfont
));
2746 static void test_GdiRealizationInfo(void)
2751 HFONT hfont
, hfont_old
;
2754 if(!pGdiRealizationInfo
)
2756 win_skip("GdiRealizationInfo not available\n");
2762 memset(info
, 0xcc, sizeof(info
));
2763 r
= pGdiRealizationInfo(hdc
, info
);
2764 ok(r
!= 0, "ret 0\n");
2765 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
2766 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2768 if (!is_truetype_font_installed("Arial"))
2770 skip("skipping GdiRealizationInfo with truetype font\n");
2774 memset(&lf
, 0, sizeof(lf
));
2775 strcpy(lf
.lfFaceName
, "Arial");
2777 lf
.lfWeight
= FW_NORMAL
;
2778 hfont
= CreateFontIndirectA(&lf
);
2779 hfont_old
= SelectObject(hdc
, hfont
);
2781 memset(info
, 0xcc, sizeof(info
));
2782 r
= pGdiRealizationInfo(hdc
, info
);
2783 ok(r
!= 0, "ret 0\n");
2784 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
2785 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2787 DeleteObject(SelectObject(hdc
, hfont_old
));
2793 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2794 the nul in the count of characters copied when the face name buffer is not
2795 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2796 always includes it. */
2797 static void test_GetTextFace(void)
2799 static const char faceA
[] = "Tahoma";
2800 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
2803 char bufA
[LF_FACESIZE
];
2804 WCHAR bufW
[LF_FACESIZE
];
2809 if(!is_font_installed("Tahoma"))
2811 skip("Tahoma is not installed so skipping this test\n");
2816 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
2817 f
= CreateFontIndirectA(&fA
);
2818 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
2821 g
= SelectObject(dc
, f
);
2822 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
2823 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
2824 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
2826 /* Play with the count arg. */
2828 n
= GetTextFaceA(dc
, 0, bufA
);
2829 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2830 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2833 n
= GetTextFaceA(dc
, 1, bufA
);
2834 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2835 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2837 bufA
[0] = 'x'; bufA
[1] = 'y';
2838 n
= GetTextFaceA(dc
, 2, bufA
);
2839 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
2840 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
2842 n
= GetTextFaceA(dc
, 0, NULL
);
2843 ok(n
== sizeof faceA
||
2844 broken(n
== 0), /* win98, winMe */
2845 "GetTextFaceA returned %d\n", n
);
2847 DeleteObject(SelectObject(dc
, g
));
2848 ReleaseDC(NULL
, dc
);
2851 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
2852 SetLastError(0xdeadbeef);
2853 f
= CreateFontIndirectW(&fW
);
2854 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2856 win_skip("CreateFontIndirectW is not implemented\n");
2859 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
2862 g
= SelectObject(dc
, f
);
2863 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
2864 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2865 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
2867 /* Play with the count arg. */
2869 n
= GetTextFaceW(dc
, 0, bufW
);
2870 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
2871 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2874 n
= GetTextFaceW(dc
, 1, bufW
);
2875 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
2876 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2878 bufW
[0] = 'x'; bufW
[1] = 'y';
2879 n
= GetTextFaceW(dc
, 2, bufW
);
2880 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
2881 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
2883 n
= GetTextFaceW(dc
, 0, NULL
);
2884 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2886 DeleteObject(SelectObject(dc
, g
));
2887 ReleaseDC(NULL
, dc
);
2890 static void test_orientation(void)
2892 static const char test_str
[11] = "Test String";
2895 HFONT hfont
, old_hfont
;
2898 if (!is_truetype_font_installed("Arial"))
2900 skip("Arial is not installed\n");
2904 hdc
= CreateCompatibleDC(0);
2905 memset(&lf
, 0, sizeof(lf
));
2906 lstrcpyA(lf
.lfFaceName
, "Arial");
2908 lf
.lfOrientation
= lf
.lfEscapement
= 900;
2909 hfont
= create_font("orientation", &lf
);
2910 old_hfont
= SelectObject(hdc
, hfont
);
2911 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
2912 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
2913 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
2914 SelectObject(hdc
, old_hfont
);
2915 DeleteObject(hfont
);
2919 static void test_oemcharset(void)
2923 HFONT hfont
, old_hfont
;
2926 hdc
= CreateCompatibleDC(0);
2927 ZeroMemory(&lf
, sizeof(lf
));
2929 lf
.lfCharSet
= OEM_CHARSET
;
2930 lf
.lfPitchAndFamily
= FIXED_PITCH
| FF_MODERN
;
2931 lstrcpyA(lf
.lfFaceName
, "Terminal");
2932 hfont
= CreateFontIndirectA(&lf
);
2933 old_hfont
= SelectObject(hdc
, hfont
);
2934 charset
= GetTextCharset(hdc
);
2936 ok(charset
== OEM_CHARSET
, "expected %d charset, got %d\n", OEM_CHARSET
, charset
);
2937 hfont
= SelectObject(hdc
, old_hfont
);
2938 GetObjectA(hfont
, sizeof(clf
), &clf
);
2939 ok(!lstrcmpA(clf
.lfFaceName
, lf
.lfFaceName
), "expected %s face name, got %s\n", lf
.lfFaceName
, clf
.lfFaceName
);
2940 ok(clf
.lfPitchAndFamily
== lf
.lfPitchAndFamily
, "expected %x family, got %x\n", lf
.lfPitchAndFamily
, clf
.lfPitchAndFamily
);
2941 ok(clf
.lfCharSet
== lf
.lfCharSet
, "expected %d charset, got %d\n", lf
.lfCharSet
, clf
.lfCharSet
);
2942 ok(clf
.lfHeight
== lf
.lfHeight
, "expected %d height, got %d\n", lf
.lfHeight
, clf
.lfHeight
);
2943 DeleteObject(hfont
);
2947 static void test_GetGlyphOutline(void)
2949 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
2953 HFONT hfont
, old_hfont
;
2956 if (!is_truetype_font_installed("Tahoma"))
2958 skip("Tahoma is not installed\n");
2962 hdc
= CreateCompatibleDC(0);
2963 memset(&lf
, 0, sizeof(lf
));
2965 lstrcpyA(lf
.lfFaceName
, "Tahoma");
2966 SetLastError(0xdeadbeef);
2967 hfont
= CreateFontIndirectA(&lf
);
2968 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2969 old_hfont
= SelectObject(hdc
, hfont
);
2971 memset(&gm
, 0, sizeof(gm
));
2972 SetLastError(0xdeadbeef);
2973 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2974 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
2976 memset(&gm
, 0, sizeof(gm
));
2977 SetLastError(0xdeadbeef);
2978 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2979 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
2980 ok(GetLastError() == 0xdeadbeef ||
2981 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
2982 "expected 0xdeadbeef, got %u\n", GetLastError());
2984 memset(&gm
, 0, sizeof(gm
));
2985 SetLastError(0xdeadbeef);
2986 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2987 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2988 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
2990 memset(&gm
, 0, sizeof(gm
));
2991 SetLastError(0xdeadbeef);
2992 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2993 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2995 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
2996 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2999 /* test for needed buffer size request on space char */
3000 memset(&gm
, 0, sizeof(gm
));
3001 SetLastError(0xdeadbeef);
3002 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
3003 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3004 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
3006 /* requesting buffer size for space char + error */
3007 memset(&gm
, 0, sizeof(gm
));
3008 SetLastError(0xdeadbeef);
3009 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
3010 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
3012 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
3013 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
3016 SelectObject(hdc
, old_hfont
);
3017 DeleteObject(hfont
);
3021 /* bug #9995: there is a limit to the character width that can be specified */
3022 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
3028 int ave_width
, height
, width
, ratio
, scale
;
3030 if (!is_truetype_font_installed( fontname
)) {
3031 skip("%s is not installed\n", fontname
);
3034 hdc
= CreateCompatibleDC(0);
3035 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
3036 /* select width = 0 */
3037 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3038 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3039 DEFAULT_QUALITY
, VARIABLE_PITCH
,
3041 ok( hf
!= NULL
, "CreateFontA(%s, %d) failed\n", fontname
, font_height
);
3042 of
= SelectObject( hdc
, hf
);
3043 ret
= GetTextMetricsA( hdc
, &tm
);
3044 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
3045 height
= tm
.tmHeight
;
3046 ave_width
= tm
.tmAveCharWidth
;
3047 SelectObject( hdc
, of
);
3050 trace("height %d, ave width %d\n", height
, ave_width
);
3052 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
3054 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
3055 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
3056 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
3057 ok(hf
!= 0, "CreateFont failed\n");
3058 of
= SelectObject(hdc
, hf
);
3059 ret
= GetTextMetrics(hdc
, &tm
);
3060 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
3061 SelectObject(hdc
, of
);
3064 if (match_off_by_1(tm
.tmAveCharWidth
, ave_width
) || width
/ height
> 200)
3070 ratio
= width
/ height
;
3071 scale
= width
/ ave_width
;
3073 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
3074 width
, height
, ratio
, width
, ave_width
, scale
);
3076 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
3079 static void test_CreateFontIndirect(void)
3081 LOGFONTA lf
, getobj_lf
;
3084 char TestName
[][16] = {"Arial", "Arial Bold", "Arial Italic", "Arial Baltic"};
3086 memset(&lf
, 0, sizeof(lf
));
3087 lf
.lfCharSet
= ANSI_CHARSET
;
3088 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
3091 lf
.lfQuality
= DEFAULT_QUALITY
;
3092 lf
.lfItalic
= FALSE
;
3093 lf
.lfWeight
= FW_DONTCARE
;
3095 for (i
= 0; i
< sizeof(TestName
)/sizeof(TestName
[0]); i
++)
3097 lstrcpyA(lf
.lfFaceName
, TestName
[i
]);
3098 hfont
= CreateFontIndirectA(&lf
);
3099 ok(hfont
!= 0, "CreateFontIndirectA failed\n");
3100 SetLastError(0xdeadbeef);
3101 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
3102 ok(ret
, "GetObject failed: %d\n", GetLastError());
3103 ok(lf
.lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
.lfItalic
, getobj_lf
.lfItalic
);
3104 ok(lf
.lfWeight
== getobj_lf
.lfWeight
||
3105 broken((SHORT
)lf
.lfWeight
== getobj_lf
.lfWeight
), /* win9x */
3106 "lfWeight: expect %08x got %08x\n", lf
.lfWeight
, getobj_lf
.lfWeight
);
3107 ok(!lstrcmpA(lf
.lfFaceName
, getobj_lf
.lfFaceName
) ||
3108 broken(!memcmp(lf
.lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
3109 "font names don't match: %s != %s\n", lf
.lfFaceName
, getobj_lf
.lfFaceName
);
3110 DeleteObject(hfont
);
3114 static void test_CreateFontIndirectEx(void)
3116 ENUMLOGFONTEXDVA lfex
;
3119 if (!pCreateFontIndirectExA
)
3121 win_skip("CreateFontIndirectExA is not available\n");
3125 if (!is_truetype_font_installed("Arial"))
3127 skip("Arial is not installed\n");
3131 SetLastError(0xdeadbeef);
3132 hfont
= pCreateFontIndirectExA(NULL
);
3133 ok(hfont
== NULL
, "got %p\n", hfont
);
3134 ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
3136 memset(&lfex
, 0, sizeof(lfex
));
3137 lstrcpyA(lfex
.elfEnumLogfontEx
.elfLogFont
.lfFaceName
, "Arial");
3138 hfont
= pCreateFontIndirectExA(&lfex
);
3139 ok(hfont
!= 0, "CreateFontIndirectEx failed\n");
3141 check_font("Arial", &lfex
.elfEnumLogfontEx
.elfLogFont
, hfont
);
3142 DeleteObject(hfont
);
3151 test_outline_font();
3152 test_bitmap_font_metrics();
3153 test_GdiGetCharDimensions();
3154 test_GetCharABCWidths();
3155 test_text_extents();
3156 test_GetGlyphIndices();
3157 test_GetKerningPairs();
3158 test_GetOutlineTextMetrics();
3159 test_SetTextJustification();
3160 test_font_charset();
3161 test_GetFontUnicodeRanges();
3162 test_nonexistent_font();
3164 test_height_selection();
3166 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3167 * I'd like to avoid them in this test.
3169 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
3170 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
3171 if (is_truetype_font_installed("Arial Black") &&
3172 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3174 test_EnumFontFamilies("", ANSI_CHARSET
);
3175 test_EnumFontFamilies("", SYMBOL_CHARSET
);
3176 test_EnumFontFamilies("", DEFAULT_CHARSET
);
3179 skip("Arial Black or Symbol/Wingdings is not installed\n");
3180 test_GetTextMetrics();
3181 test_GdiRealizationInfo();
3183 test_GetGlyphOutline();
3184 test_GetTextMetrics2("Tahoma", -11);
3185 test_GetTextMetrics2("Tahoma", -55);
3186 test_GetTextMetrics2("Tahoma", -110);
3187 test_GetTextMetrics2("Arial", -11);
3188 test_GetTextMetrics2("Arial", -55);
3189 test_GetTextMetrics2("Arial", -110);
3190 test_CreateFontIndirect();
3191 test_CreateFontIndirectEx();