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 #define near_match(a, b) (abs((a) - (b)) <= 6)
34 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
36 LONG (WINAPI
*pGdiGetCharDimensions
)(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
);
37 BOOL (WINAPI
*pGetCharABCWidthsI
)(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPABC abc
);
38 BOOL (WINAPI
*pGetCharABCWidthsW
)(HDC hdc
, UINT first
, UINT last
, LPABC abc
);
39 DWORD (WINAPI
*pGetFontUnicodeRanges
)(HDC hdc
, LPGLYPHSET lpgs
);
40 DWORD (WINAPI
*pGetGlyphIndicesA
)(HDC hdc
, LPCSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
41 DWORD (WINAPI
*pGetGlyphIndicesW
)(HDC hdc
, LPCWSTR lpstr
, INT count
, LPWORD pgi
, DWORD flags
);
42 BOOL (WINAPI
*pGdiRealizationInfo
)(HDC hdc
, DWORD
*);
44 static HMODULE hgdi32
= 0;
46 static void init(void)
48 hgdi32
= GetModuleHandleA("gdi32.dll");
50 pGdiGetCharDimensions
= (void *)GetProcAddress(hgdi32
, "GdiGetCharDimensions");
51 pGetCharABCWidthsI
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsI");
52 pGetCharABCWidthsW
= (void *)GetProcAddress(hgdi32
, "GetCharABCWidthsW");
53 pGetFontUnicodeRanges
= (void *)GetProcAddress(hgdi32
, "GetFontUnicodeRanges");
54 pGetGlyphIndicesA
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesA");
55 pGetGlyphIndicesW
= (void *)GetProcAddress(hgdi32
, "GetGlyphIndicesW");
56 pGdiRealizationInfo
= (void *)GetProcAddress(hgdi32
, "GdiRealizationInfo");
59 static INT CALLBACK
is_truetype_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
61 if (type
!= TRUETYPE_FONTTYPE
) return 1;
66 static BOOL
is_truetype_font_installed(const char *name
)
71 if (!EnumFontFamiliesA(hdc
, name
, is_truetype_font_installed_proc
, 0))
78 static INT CALLBACK
is_font_installed_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
83 static BOOL
is_font_installed(const char *name
)
88 if(!EnumFontFamiliesA(hdc
, name
, is_font_installed_proc
, 0))
95 static void check_font(const char* test
, const LOGFONTA
* lf
, HFONT hfont
)
103 ret
= GetObject(hfont
, sizeof(getobj_lf
), &getobj_lf
);
104 /* NT4 tries to be clever and only returns the minimum length */
105 while (lf
->lfFaceName
[minlen
] && minlen
< LF_FACESIZE
-1)
107 minlen
+= FIELD_OFFSET(LOGFONTA
, lfFaceName
) + 1;
108 ok(ret
== sizeof(LOGFONTA
) || ret
== minlen
, "%s: GetObject returned %d\n", test
, ret
);
109 ok(lf
->lfHeight
== getobj_lf
.lfHeight
||
110 broken((SHORT
)lf
->lfHeight
== getobj_lf
.lfHeight
), /* win9x */
111 "lfHeight: expect %08x got %08x\n", lf
->lfHeight
, getobj_lf
.lfHeight
);
112 ok(lf
->lfWidth
== getobj_lf
.lfWidth
||
113 broken((SHORT
)lf
->lfWidth
== getobj_lf
.lfWidth
), /* win9x */
114 "lfWidth: expect %08x got %08x\n", lf
->lfWidth
, getobj_lf
.lfWidth
);
115 ok(lf
->lfEscapement
== getobj_lf
.lfEscapement
||
116 broken((SHORT
)lf
->lfEscapement
== getobj_lf
.lfEscapement
), /* win9x */
117 "lfEscapement: expect %08x got %08x\n", lf
->lfEscapement
, getobj_lf
.lfEscapement
);
118 ok(lf
->lfOrientation
== getobj_lf
.lfOrientation
||
119 broken((SHORT
)lf
->lfOrientation
== getobj_lf
.lfOrientation
), /* win9x */
120 "lfOrientation: expect %08x got %08x\n", lf
->lfOrientation
, getobj_lf
.lfOrientation
);
121 ok(lf
->lfWeight
== getobj_lf
.lfWeight
||
122 broken((SHORT
)lf
->lfWeight
== getobj_lf
.lfWeight
), /* win9x */
123 "lfWeight: expect %08x got %08x\n", lf
->lfWeight
, getobj_lf
.lfWeight
);
124 ok(lf
->lfItalic
== getobj_lf
.lfItalic
, "lfItalic: expect %02x got %02x\n", lf
->lfItalic
, getobj_lf
.lfItalic
);
125 ok(lf
->lfUnderline
== getobj_lf
.lfUnderline
, "lfUnderline: expect %02x got %02x\n", lf
->lfUnderline
, getobj_lf
.lfUnderline
);
126 ok(lf
->lfStrikeOut
== getobj_lf
.lfStrikeOut
, "lfStrikeOut: expect %02x got %02x\n", lf
->lfStrikeOut
, getobj_lf
.lfStrikeOut
);
127 ok(lf
->lfCharSet
== getobj_lf
.lfCharSet
, "lfCharSet: expect %02x got %02x\n", lf
->lfCharSet
, getobj_lf
.lfCharSet
);
128 ok(lf
->lfOutPrecision
== getobj_lf
.lfOutPrecision
, "lfOutPrecision: expect %02x got %02x\n", lf
->lfOutPrecision
, getobj_lf
.lfOutPrecision
);
129 ok(lf
->lfClipPrecision
== getobj_lf
.lfClipPrecision
, "lfClipPrecision: expect %02x got %02x\n", lf
->lfClipPrecision
, getobj_lf
.lfClipPrecision
);
130 ok(lf
->lfQuality
== getobj_lf
.lfQuality
, "lfQuality: expect %02x got %02x\n", lf
->lfQuality
, getobj_lf
.lfQuality
);
131 ok(lf
->lfPitchAndFamily
== getobj_lf
.lfPitchAndFamily
, "lfPitchAndFamily: expect %02x got %02x\n", lf
->lfPitchAndFamily
, getobj_lf
.lfPitchAndFamily
);
132 ok(!lstrcmpA(lf
->lfFaceName
, getobj_lf
.lfFaceName
) ||
133 broken(!memcmp(lf
->lfFaceName
, getobj_lf
.lfFaceName
, LF_FACESIZE
-1)), /* win9x doesn't ensure '\0' termination */
134 "%s: font names don't match: %s != %s\n", test
, lf
->lfFaceName
, getobj_lf
.lfFaceName
);
137 static HFONT
create_font(const char* test
, const LOGFONTA
* lf
)
139 HFONT hfont
= CreateFontIndirectA(lf
);
140 ok(hfont
!= 0, "%s: CreateFontIndirect failed\n", test
);
142 check_font(test
, lf
, hfont
);
146 static void test_logfont(void)
151 memset(&lf
, 0, sizeof lf
);
153 lf
.lfCharSet
= ANSI_CHARSET
;
154 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
155 lf
.lfWeight
= FW_DONTCARE
;
158 lf
.lfQuality
= DEFAULT_QUALITY
;
160 lstrcpyA(lf
.lfFaceName
, "Arial");
161 hfont
= create_font("Arial", &lf
);
164 memset(&lf
, 'A', sizeof(lf
));
165 hfont
= CreateFontIndirectA(&lf
);
166 ok(hfont
!= 0, "CreateFontIndirectA with strange LOGFONT failed\n");
168 lf
.lfFaceName
[LF_FACESIZE
- 1] = 0;
169 check_font("AAA...", &lf
, hfont
);
173 static INT CALLBACK
font_enum_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
175 if (type
& RASTER_FONTTYPE
)
177 LOGFONT
*lf
= (LOGFONT
*)lParam
;
179 return 0; /* stop enumeration */
182 return 1; /* continue enumeration */
185 static void compare_tm(const TEXTMETRICA
*tm
, const TEXTMETRICA
*otm
)
187 ok(tm
->tmHeight
== otm
->tmHeight
, "tmHeight %d != %d\n", tm
->tmHeight
, otm
->tmHeight
);
188 ok(tm
->tmAscent
== otm
->tmAscent
, "tmAscent %d != %d\n", tm
->tmAscent
, otm
->tmAscent
);
189 ok(tm
->tmDescent
== otm
->tmDescent
, "tmDescent %d != %d\n", tm
->tmDescent
, otm
->tmDescent
);
190 ok(tm
->tmInternalLeading
== otm
->tmInternalLeading
, "tmInternalLeading %d != %d\n", tm
->tmInternalLeading
, otm
->tmInternalLeading
);
191 ok(tm
->tmExternalLeading
== otm
->tmExternalLeading
, "tmExternalLeading %d != %d\n", tm
->tmExternalLeading
, otm
->tmExternalLeading
);
192 ok(tm
->tmAveCharWidth
== otm
->tmAveCharWidth
, "tmAveCharWidth %d != %d\n", tm
->tmAveCharWidth
, otm
->tmAveCharWidth
);
193 ok(tm
->tmMaxCharWidth
== otm
->tmMaxCharWidth
, "tmMaxCharWidth %d != %d\n", tm
->tmMaxCharWidth
, otm
->tmMaxCharWidth
);
194 ok(tm
->tmWeight
== otm
->tmWeight
, "tmWeight %d != %d\n", tm
->tmWeight
, otm
->tmWeight
);
195 ok(tm
->tmOverhang
== otm
->tmOverhang
, "tmOverhang %d != %d\n", tm
->tmOverhang
, otm
->tmOverhang
);
196 ok(tm
->tmDigitizedAspectX
== otm
->tmDigitizedAspectX
, "tmDigitizedAspectX %d != %d\n", tm
->tmDigitizedAspectX
, otm
->tmDigitizedAspectX
);
197 ok(tm
->tmDigitizedAspectY
== otm
->tmDigitizedAspectY
, "tmDigitizedAspectY %d != %d\n", tm
->tmDigitizedAspectY
, otm
->tmDigitizedAspectY
);
198 ok(tm
->tmFirstChar
== otm
->tmFirstChar
, "tmFirstChar %d != %d\n", tm
->tmFirstChar
, otm
->tmFirstChar
);
199 ok(tm
->tmLastChar
== otm
->tmLastChar
, "tmLastChar %d != %d\n", tm
->tmLastChar
, otm
->tmLastChar
);
200 ok(tm
->tmDefaultChar
== otm
->tmDefaultChar
, "tmDefaultChar %d != %d\n", tm
->tmDefaultChar
, otm
->tmDefaultChar
);
201 ok(tm
->tmBreakChar
== otm
->tmBreakChar
, "tmBreakChar %d != %d\n", tm
->tmBreakChar
, otm
->tmBreakChar
);
202 ok(tm
->tmItalic
== otm
->tmItalic
, "tmItalic %d != %d\n", tm
->tmItalic
, otm
->tmItalic
);
203 ok(tm
->tmUnderlined
== otm
->tmUnderlined
, "tmUnderlined %d != %d\n", tm
->tmUnderlined
, otm
->tmUnderlined
);
204 ok(tm
->tmStruckOut
== otm
->tmStruckOut
, "tmStruckOut %d != %d\n", tm
->tmStruckOut
, otm
->tmStruckOut
);
205 ok(tm
->tmPitchAndFamily
== otm
->tmPitchAndFamily
, "tmPitchAndFamily %d != %d\n", tm
->tmPitchAndFamily
, otm
->tmPitchAndFamily
);
206 ok(tm
->tmCharSet
== otm
->tmCharSet
, "tmCharSet %d != %d\n", tm
->tmCharSet
, otm
->tmCharSet
);
209 static void test_font_metrics(HDC hdc
, HFONT hfont
, LONG lfHeight
,
210 LONG lfWidth
, const char *test_str
,
211 INT test_str_len
, const TEXTMETRICA
*tm_orig
,
212 const SIZE
*size_orig
, INT width_of_A_orig
,
213 INT scale_x
, INT scale_y
)
216 OUTLINETEXTMETRIC otm
;
219 INT width_of_A
, cx
, cy
;
225 ok(GetCurrentObject(hdc
, OBJ_FONT
) == hfont
, "hfont should be selected\n");
227 GetObjectA(hfont
, sizeof(lf
), &lf
);
229 if (GetOutlineTextMetricsA(hdc
, 0, NULL
))
231 otm
.otmSize
= sizeof(otm
) / 2;
232 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
233 ok(ret
== sizeof(otm
)/2 /* XP */ ||
234 ret
== 1 /* Win9x */, "expected sizeof(otm)/2, got %u\n", ret
);
236 memset(&otm
, 0x1, sizeof(otm
));
237 otm
.otmSize
= sizeof(otm
);
238 ret
= GetOutlineTextMetricsA(hdc
, otm
.otmSize
, &otm
);
239 ok(ret
== sizeof(otm
) /* XP */ ||
240 ret
== 1 /* Win9x */, "expected sizeof(otm), got %u\n", ret
);
242 memset(&tm
, 0x2, sizeof(tm
));
243 ret
= GetTextMetricsA(hdc
, &tm
);
244 ok(ret
, "GetTextMetricsA failed\n");
245 /* the structure size is aligned */
246 if (memcmp(&tm
, &otm
.otmTextMetrics
, FIELD_OFFSET(TEXTMETRICA
, tmCharSet
) + 1))
248 ok(0, "tm != otm\n");
249 compare_tm(&tm
, &otm
.otmTextMetrics
);
252 tm
= otm
.otmTextMetrics
;
253 if (0) /* these metrics are scaled too, but with rounding errors */
255 ok(otm
.otmAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmAscent
, tm
.tmAscent
);
256 ok(otm
.otmDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmDescent
, -tm
.tmDescent
);
258 ok(otm
.otmMacAscent
== tm
.tmAscent
, "ascent %d != %d\n", otm
.otmMacAscent
, tm
.tmAscent
);
259 ok(otm
.otmDescent
< 0, "otm.otmDescent should be < 0\n");
260 ok(otm
.otmMacDescent
< 0, "otm.otmMacDescent should be < 0\n");
261 ok(tm
.tmDescent
> 0, "tm.tmDescent should be > 0\n");
262 ok(otm
.otmMacDescent
== -tm
.tmDescent
, "descent %d != %d\n", otm
.otmMacDescent
, -tm
.tmDescent
);
263 ok(otm
.otmEMSquare
== 2048, "expected 2048, got %d\n", otm
.otmEMSquare
);
267 ret
= GetTextMetricsA(hdc
, &tm
);
268 ok(ret
, "GetTextMetricsA failed\n");
271 cx
= tm
.tmAveCharWidth
/ tm_orig
->tmAveCharWidth
;
272 cy
= tm
.tmHeight
/ tm_orig
->tmHeight
;
273 ok(cx
== scale_x
&& cy
== scale_y
, "height %d: expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
274 lfHeight
, scale_x
, scale_y
, cx
, cy
);
275 ok(tm
.tmHeight
== tm_orig
->tmHeight
* scale_y
, "height %d != %d\n", tm
.tmHeight
, tm_orig
->tmHeight
* scale_y
);
276 ok(tm
.tmAscent
== tm_orig
->tmAscent
* scale_y
, "ascent %d != %d\n", tm
.tmAscent
, tm_orig
->tmAscent
* scale_y
);
277 ok(tm
.tmDescent
== tm_orig
->tmDescent
* scale_y
, "descent %d != %d\n", tm
.tmDescent
, tm_orig
->tmDescent
* scale_y
);
278 ok(near_match(tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
), "ave width %d != %d\n", tm
.tmAveCharWidth
, tm_orig
->tmAveCharWidth
* scale_x
);
279 ok(near_match(tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
), "max width %d != %d\n", tm
.tmMaxCharWidth
, tm_orig
->tmMaxCharWidth
* scale_x
);
281 ok(lf
.lfHeight
== lfHeight
, "lfHeight %d != %d\n", lf
.lfHeight
, lfHeight
);
285 ok(lf
.lfWidth
== tm
.tmAveCharWidth
, "lfWidth %d != tm %d\n", lf
.lfWidth
, tm
.tmAveCharWidth
);
288 ok(lf
.lfWidth
== lfWidth
, "lfWidth %d != %d\n", lf
.lfWidth
, lfWidth
);
290 GetTextExtentPoint32A(hdc
, test_str
, test_str_len
, &size
);
292 ok(near_match(size
.cx
, size_orig
->cx
* scale_x
), "cx %d != %d\n", size
.cx
, size_orig
->cx
* scale_x
);
293 ok(size
.cy
== size_orig
->cy
* scale_y
, "cy %d != %d\n", size
.cy
, size_orig
->cy
* scale_y
);
295 GetCharWidthA(hdc
, 'A', 'A', &width_of_A
);
297 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
);
300 /* Test how GDI scales bitmap font metrics */
301 static void test_bitmap_font(void)
303 static const char test_str
[11] = "Test String";
306 HFONT hfont
, old_hfont
;
309 INT ret
, i
, width_orig
, height_orig
, scale
, lfWidth
;
311 skip("ROS-HACK: Skipping bitmap font tests!\n");
316 /* "System" has only 1 pixel size defined, otherwise the test breaks */
317 ret
= EnumFontFamiliesA(hdc
, "System", font_enum_proc
, (LPARAM
)&bitmap_lf
);
321 trace("no bitmap fonts were found, skipping the test\n");
325 trace("found bitmap font %s, height %d\n", bitmap_lf
.lfFaceName
, bitmap_lf
.lfHeight
);
327 height_orig
= bitmap_lf
.lfHeight
;
328 lfWidth
= bitmap_lf
.lfWidth
;
330 hfont
= create_font("bitmap", &bitmap_lf
);
331 old_hfont
= SelectObject(hdc
, hfont
);
332 ok(GetTextMetricsA(hdc
, &tm_orig
), "GetTextMetricsA failed\n");
333 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
334 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
335 SelectObject(hdc
, old_hfont
);
338 bitmap_lf
.lfHeight
= 0;
339 bitmap_lf
.lfWidth
= 4;
340 hfont
= create_font("bitmap", &bitmap_lf
);
341 old_hfont
= SelectObject(hdc
, hfont
);
342 test_font_metrics(hdc
, hfont
, 0, 4, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, 1);
343 SelectObject(hdc
, old_hfont
);
346 bitmap_lf
.lfHeight
= height_orig
;
347 bitmap_lf
.lfWidth
= lfWidth
;
349 /* test fractional scaling */
350 for (i
= 1; i
<= height_orig
* 6; i
++)
354 bitmap_lf
.lfHeight
= i
;
355 hfont
= create_font("fractional", &bitmap_lf
);
356 scale
= (i
+ height_orig
- 1) / height_orig
;
357 nearest_height
= scale
* height_orig
;
358 /* Only jump to the next height if the difference <= 25% original height */
359 if (scale
> 2 && nearest_height
- i
> height_orig
/ 4) scale
--;
360 /* The jump between unscaled and doubled is delayed by 1 in winnt+ but not in win9x,
361 so we'll not test this particular height. */
362 else if(scale
== 2 && nearest_height
- i
== (height_orig
/ 4)) continue;
363 else if(scale
== 2 && nearest_height
- i
> (height_orig
/ 4 - 1)) scale
--;
364 old_hfont
= SelectObject(hdc
, hfont
);
365 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 1, scale
);
366 SelectObject(hdc
, old_hfont
);
370 /* test integer scaling 3x2 */
371 bitmap_lf
.lfHeight
= height_orig
* 2;
372 bitmap_lf
.lfWidth
*= 3;
373 hfont
= create_font("3x2", &bitmap_lf
);
374 old_hfont
= SelectObject(hdc
, hfont
);
375 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 2);
376 SelectObject(hdc
, old_hfont
);
379 /* test integer scaling 3x3 */
380 bitmap_lf
.lfHeight
= height_orig
* 3;
381 bitmap_lf
.lfWidth
= 0;
382 hfont
= create_font("3x3", &bitmap_lf
);
383 old_hfont
= SelectObject(hdc
, hfont
);
384 test_font_metrics(hdc
, hfont
, bitmap_lf
.lfHeight
, 0, test_str
, sizeof(test_str
), &tm_orig
, &size_orig
, width_orig
, 3, 3);
385 SelectObject(hdc
, old_hfont
);
391 /* Test how GDI scales outline font metrics */
392 static void test_outline_font(void)
394 static const char test_str
[11] = "Test String";
397 HFONT hfont
, old_hfont
, old_hfont_2
;
398 OUTLINETEXTMETRICA otm
;
400 INT width_orig
, height_orig
, lfWidth
;
403 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
404 MAT2 mat2
= { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
408 if (!is_truetype_font_installed("Arial"))
410 skip("Arial is not installed\n");
414 hdc
= CreateCompatibleDC(0);
416 memset(&lf
, 0, sizeof(lf
));
417 strcpy(lf
.lfFaceName
, "Arial");
419 hfont
= create_font("outline", &lf
);
420 old_hfont
= SelectObject(hdc
, hfont
);
421 otm
.otmSize
= sizeof(otm
);
422 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
423 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
424 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
426 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, otm
.otmTextMetrics
.tmAveCharWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
427 SelectObject(hdc
, old_hfont
);
430 /* font of otmEMSquare height helps to avoid a lot of rounding errors */
431 lf
.lfHeight
= otm
.otmEMSquare
;
432 lf
.lfHeight
= -lf
.lfHeight
;
433 hfont
= create_font("outline", &lf
);
434 old_hfont
= SelectObject(hdc
, hfont
);
435 otm
.otmSize
= sizeof(otm
);
436 ok(GetOutlineTextMetricsA(hdc
, sizeof(otm
), &otm
), "GetTextMetricsA failed\n");
437 ok(GetTextExtentPoint32A(hdc
, test_str
, sizeof(test_str
), &size_orig
), "GetTextExtentPoint32A failed\n");
438 ok(GetCharWidthA(hdc
, 'A', 'A', &width_orig
), "GetCharWidthA failed\n");
439 SelectObject(hdc
, old_hfont
);
442 height_orig
= otm
.otmTextMetrics
.tmHeight
;
443 lfWidth
= otm
.otmTextMetrics
.tmAveCharWidth
;
445 /* test integer scaling 3x2 */
446 lf
.lfHeight
= height_orig
* 2;
447 lf
.lfWidth
= lfWidth
* 3;
448 hfont
= create_font("3x2", &lf
);
449 old_hfont
= SelectObject(hdc
, hfont
);
450 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 2);
451 SelectObject(hdc
, old_hfont
);
454 /* test integer scaling 3x3 */
455 lf
.lfHeight
= height_orig
* 3;
456 lf
.lfWidth
= lfWidth
* 3;
457 hfont
= create_font("3x3", &lf
);
458 old_hfont
= SelectObject(hdc
, hfont
);
459 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 3, 3);
460 SelectObject(hdc
, old_hfont
);
463 /* test integer scaling 1x1 */
464 lf
.lfHeight
= height_orig
* 1;
465 lf
.lfWidth
= lfWidth
* 1;
466 hfont
= create_font("1x1", &lf
);
467 old_hfont
= SelectObject(hdc
, hfont
);
468 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
469 SelectObject(hdc
, old_hfont
);
472 /* test integer scaling 1x1 */
473 lf
.lfHeight
= height_orig
;
475 hfont
= create_font("1x1", &lf
);
476 old_hfont
= SelectObject(hdc
, hfont
);
477 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
479 /* with an identity matrix */
480 memset(&gm
, 0, sizeof(gm
));
481 SetLastError(0xdeadbeef);
482 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
483 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
484 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
485 ok(gm
.gmCellIncX
== width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
);
486 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
487 /* with a custom matrix */
488 memset(&gm
, 0, sizeof(gm
));
489 SetLastError(0xdeadbeef);
490 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
491 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
492 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
493 ok(gm
.gmCellIncX
== width_orig
/2, "incX %d != %d\n", gm
.gmCellIncX
, width_orig
/2);
494 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
496 /* Test that changing the DC transformation affects only the font
497 * selected on this DC and doesn't affect the same font selected on
500 hdc_2
= CreateCompatibleDC(0);
501 old_hfont_2
= SelectObject(hdc_2
, hfont
);
502 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
504 SetMapMode(hdc
, MM_ANISOTROPIC
);
506 /* font metrics on another DC should be unchanged */
507 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
509 /* test restrictions of compatibility mode GM_COMPATIBLE */
510 /* part 1: rescaling only X should not change font scaling on screen.
511 So compressing the X axis by 2 is not done, and this
512 appears as X scaling of 2 that no one requested. */
513 SetWindowExtEx(hdc
, 100, 100, NULL
);
514 SetViewportExtEx(hdc
, 50, 100, NULL
);
515 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
516 /* font metrics on another DC should be unchanged */
517 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
519 /* part 2: rescaling only Y should change font scaling.
520 As also X is scaled by a factor of 2, but this is not
521 requested by the DC transformation, we get a scaling factor
522 of 2 in the X coordinate. */
523 SetViewportExtEx(hdc
, 100, 200, NULL
);
524 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 2, 1);
525 /* font metrics on another DC should be unchanged */
526 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
528 /* restore scaling */
529 SetMapMode(hdc
, MM_TEXT
);
531 /* font metrics on another DC should be unchanged */
532 test_font_metrics(hdc_2
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
534 SelectObject(hdc_2
, old_hfont_2
);
537 if (!SetGraphicsMode(hdc
, GM_ADVANCED
))
539 SelectObject(hdc
, old_hfont
);
542 skip("GM_ADVANCED is not supported on this platform\n");
553 SetLastError(0xdeadbeef);
554 ret
= SetWorldTransform(hdc
, &xform
);
555 ok(ret
, "SetWorldTransform error %u\n", GetLastError());
557 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
559 /* with an identity matrix */
560 memset(&gm
, 0, sizeof(gm
));
561 SetLastError(0xdeadbeef);
562 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
563 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
564 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
565 pt
.x
= width_orig
; pt
.y
= 0;
567 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
568 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
569 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
570 /* with a custom matrix */
571 memset(&gm
, 0, sizeof(gm
));
572 SetLastError(0xdeadbeef);
573 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
574 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
575 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
576 pt
.x
= width_orig
; pt
.y
= 0;
578 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
579 ok(near_match(gm
.gmCellIncX
, 10 * width_orig
), "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
580 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
582 SetLastError(0xdeadbeef);
583 ret
= SetMapMode(hdc
, MM_LOMETRIC
);
584 ok(ret
== MM_TEXT
, "expected MM_TEXT, got %d, error %u\n", ret
, GetLastError());
586 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
588 /* with an identity matrix */
589 memset(&gm
, 0, sizeof(gm
));
590 SetLastError(0xdeadbeef);
591 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
592 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
593 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
594 pt
.x
= width_orig
; pt
.y
= 0;
596 ok(near_match(gm
.gmCellIncX
, pt
.x
), "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
597 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
598 /* with a custom matrix */
599 memset(&gm
, 0, sizeof(gm
));
600 SetLastError(0xdeadbeef);
601 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
602 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
603 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
604 pt
.x
= width_orig
; pt
.y
= 0;
606 ok(near_match(gm
.gmCellIncX
, (pt
.x
+ 1)/2), "incX %d != %d\n", gm
.gmCellIncX
, (pt
.x
+ 1)/2);
607 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
609 SetLastError(0xdeadbeef);
610 ret
= SetMapMode(hdc
, MM_TEXT
);
611 ok(ret
== MM_LOMETRIC
, "expected MM_LOMETRIC, got %d, error %u\n", ret
, GetLastError());
613 test_font_metrics(hdc
, hfont
, lf
.lfHeight
, lf
.lfWidth
, test_str
, sizeof(test_str
), &otm
.otmTextMetrics
, &size_orig
, width_orig
, 1, 1);
615 /* with an identity matrix */
616 memset(&gm
, 0, sizeof(gm
));
617 SetLastError(0xdeadbeef);
618 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
619 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
620 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
621 pt
.x
= width_orig
; pt
.y
= 0;
623 ok(gm
.gmCellIncX
== pt
.x
, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
);
624 ok(gm
.gmCellIncX
== 20 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 20 * width_orig
);
625 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
626 /* with a custom matrix */
627 memset(&gm
, 0, sizeof(gm
));
628 SetLastError(0xdeadbeef);
629 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat2
);
630 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %d\n", GetLastError());
631 trace("gm.gmCellIncX %d, width_orig %d\n", gm
.gmCellIncX
, width_orig
);
632 pt
.x
= width_orig
; pt
.y
= 0;
634 ok(gm
.gmCellIncX
== pt
.x
/2, "incX %d != %d\n", gm
.gmCellIncX
, pt
.x
/2);
635 ok(gm
.gmCellIncX
== 10 * width_orig
, "incX %d != %d\n", gm
.gmCellIncX
, 10 * width_orig
);
636 ok(gm
.gmCellIncY
== 0, "incY %d != 0\n", gm
.gmCellIncY
);
638 SelectObject(hdc
, old_hfont
);
643 static INT CALLBACK
find_font_proc(const LOGFONT
*elf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
645 LOGFONT
*lf
= (LOGFONT
*)lParam
;
647 if (elf
->lfHeight
== lf
->lfHeight
&& !strcmp(elf
->lfFaceName
, lf
->lfFaceName
))
650 return 0; /* stop enumeration */
652 return 1; /* continue enumeration */
655 static void test_bitmap_font_metrics(void)
657 static const struct font_data
659 const char face_name
[LF_FACESIZE
];
660 int weight
, height
, ascent
, descent
, int_leading
, ext_leading
;
661 int ave_char_width
, max_char_width
, dpi
;
665 { "MS Sans Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
666 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
667 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 16, 96, FS_LATIN1
| FS_CYRILLIC
},
668 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 96, FS_LATIN2
},
669 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 19, 96, FS_LATIN1
},
670 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 24, 96, FS_LATIN2
},
671 { "MS Sans Serif", FW_NORMAL
, 24, 19, 5, 6, 0, 9, 20, 96, FS_CYRILLIC
},
672 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 96, FS_LATIN1
},
673 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 96, FS_LATIN2
},
674 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 25, 96, FS_CYRILLIC
},
675 { "MS Sans Serif", FW_NORMAL
, 37, 29, 8, 5, 0, 16, 32, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
677 { "MS Sans Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 7, 14, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
678 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_LATIN2
},
679 { "MS Sans Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 17, 120, FS_CYRILLIC
},
680 { "MS Sans Serif", FW_NORMAL
, 25, 20, 5, 5, 0, 10, 21, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
681 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 6, 0, 12, 24, 120, FS_LATIN1
| FS_LATIN2
},
682 { "MS Sans Serif", FW_NORMAL
, 29, 23, 6, 5, 0, 12, 24, 120, FS_CYRILLIC
},
683 { "MS Sans Serif", FW_NORMAL
, 36, 29, 7, 6, 0, 15, 30, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
684 { "MS Sans Serif", FW_NORMAL
, 46, 37, 9, 6, 0, 20, 40, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
686 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
687 { "MS Serif", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
688 { "MS Serif", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
689 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 11, 96, FS_LATIN1
},
690 { "MS Serif", FW_NORMAL
, 13, 11, 2, 2, 0, 5, 12, 96, FS_LATIN2
| FS_CYRILLIC
},
691 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 96, FS_LATIN1
| FS_LATIN2
},
692 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 16, 96, FS_CYRILLIC
},
693 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 18, 96, FS_LATIN1
| FS_LATIN2
},
694 { "MS Serif", FW_NORMAL
, 19, 15, 4, 3, 0, 8, 19, 96, FS_CYRILLIC
},
695 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 17, 96, FS_LATIN1
},
696 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 22, 96, FS_LATIN2
},
697 { "MS Serif", FW_NORMAL
, 21, 16, 5, 3, 0, 9, 23, 96, FS_CYRILLIC
},
698 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 23, 96, FS_LATIN1
},
699 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 26, 96, FS_LATIN2
},
700 { "MS Serif", FW_NORMAL
, 27, 21, 6, 3, 0, 12, 27, 96, FS_CYRILLIC
},
701 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 33, 96, FS_LATIN1
| FS_LATIN2
},
702 { "MS Serif", FW_NORMAL
, 35, 27, 8, 3, 0, 16, 34, 96, FS_CYRILLIC
},
704 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 14, 120, FS_LATIN1
| FS_CYRILLIC
},
705 { "MS Serif", FW_NORMAL
, 16, 13, 3, 3, 0, 6, 13, 120, FS_LATIN2
},
706 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 18, 120, FS_LATIN1
| FS_CYRILLIC
},
707 { "MS Serif", FW_NORMAL
, 20, 16, 4, 4, 0, 8, 15, 120, FS_LATIN2
},
708 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 21, 120, FS_LATIN1
| FS_CYRILLIC
},
709 { "MS Serif", FW_NORMAL
, 23, 18, 5, 3, 0, 10, 19, 120, FS_LATIN2
},
710 { "MS Serif", FW_NORMAL
, 27, 21, 6, 4, 0, 12, 23, 120, FS_LATIN1
| FS_LATIN2
},
711 { "MS Serif", FW_MEDIUM
, 27, 22, 5, 2, 0, 12, 30, 120, FS_CYRILLIC
},
712 { "MS Serif", FW_NORMAL
, 33, 26, 7, 3, 0, 14, 30, 120, FS_LATIN1
| FS_LATIN2
},
713 { "MS Serif", FW_MEDIUM
, 32, 25, 7, 2, 0, 14, 32, 120, FS_CYRILLIC
},
714 { "MS Serif", FW_NORMAL
, 43, 34, 9, 3, 0, 19, 39, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
716 { "Courier", FW_NORMAL
, 13, 11, 2, 0, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
717 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
718 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
720 { "Courier", FW_NORMAL
, 16, 13, 3, 0, 0, 9, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
721 { "Courier", FW_NORMAL
, 20, 16, 4, 0, 0, 12, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
722 { "Courier", FW_NORMAL
, 25, 20, 5, 0, 0, 15, 15, 120, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
724 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 14, 96, FS_LATIN1
},
725 { "System", FW_BOLD
, 16, 13, 3, 3, 0, 7, 15, 96, FS_LATIN2
| FS_CYRILLIC
},
727 * TODO: the system for CP932 should be NORMAL, not BOLD. However that would
728 * require a new system.sfd for that font
730 { "System", FW_BOLD
, 18, 16, 2, 0, 2, 8, 16, 96, FS_JISJAPAN
},
732 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 14, 120, FS_LATIN1
},
733 { "System", FW_BOLD
, 20, 16, 4, 4, 0, 9, 17, 120, FS_LATIN2
| FS_CYRILLIC
},
735 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 96, FS_LATIN1
},
736 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
737 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 2, 4, 96, FS_JISJAPAN
},
738 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 3, 4, 96, FS_LATIN1
},
739 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 1, 0, 2, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
740 { "Small Fonts", FW_NORMAL
, 5, 4, 1, 0, 0, 3, 6, 96, FS_JISJAPAN
},
741 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 13, 96, FS_LATIN1
},
742 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
743 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 0, 0, 4, 8, 96, FS_JISJAPAN
},
744 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 96, FS_LATIN1
},
745 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 96, FS_LATIN2
| FS_CYRILLIC
},
746 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 0, 0, 5, 10, 96, FS_JISJAPAN
},
747 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 4, 8, 96, FS_LATIN1
| FS_LATIN2
},
748 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 96, FS_CYRILLIC
},
749 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 0, 0, 6, 12, 96, FS_JISJAPAN
},
750 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 2, 0, 5, 9, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
},
751 { "Small Fonts", FW_NORMAL
, 11, 9, 2, 0, 0, 7, 14, 96, FS_JISJAPAN
},
753 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 2, 120, FS_LATIN1
| FS_JISJAPAN
},
754 { "Small Fonts", FW_NORMAL
, 3, 2, 1, 0, 0, 1, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
755 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 5, 120, FS_LATIN1
| FS_JISJAPAN
},
756 { "Small Fonts", FW_NORMAL
, 6, 5, 1, 1, 0, 3, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
757 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 7, 120, FS_LATIN1
| FS_JISJAPAN
},
758 { "Small Fonts", FW_NORMAL
, 8, 7, 1, 1, 0, 4, 8, 120, FS_LATIN2
| FS_CYRILLIC
},
759 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 9, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
760 { "Small Fonts", FW_NORMAL
, 10, 8, 2, 2, 0, 5, 8, 120, FS_CYRILLIC
},
761 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 5, 10, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
762 { "Small Fonts", FW_NORMAL
, 12, 10, 2, 2, 0, 6, 10, 120, FS_CYRILLIC
},
763 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 12, 120, FS_LATIN1
| FS_LATIN2
| FS_JISJAPAN
},
764 { "Small Fonts", FW_NORMAL
, 13, 11, 2, 2, 0, 6, 11, 120, FS_CYRILLIC
},
766 { "Fixedsys", FW_NORMAL
, 15, 12, 3, 3, 0, 8, 8, 96, FS_LATIN1
| FS_LATIN2
},
767 { "Fixedsys", FW_NORMAL
, 16, 12, 4, 3, 0, 8, 8, 96, FS_CYRILLIC
},
768 { "FixedSys", FW_NORMAL
, 18, 16, 2, 0, 0, 8, 16, 96, FS_JISJAPAN
},
770 /* The 120dpi version still has its dpi marked as 96 */
771 { "Fixedsys", FW_NORMAL
, 20, 16, 4, 2, 0, 10, 10, 96, FS_LATIN1
| FS_LATIN2
| FS_CYRILLIC
}
773 /* FIXME: add "Terminal" */
777 HFONT hfont
, old_hfont
;
781 hdc
= CreateCompatibleDC(0);
784 for (i
= 0; i
< sizeof(fd
)/sizeof(fd
[0]); i
++)
788 memset(&lf
, 0, sizeof(lf
));
790 lf
.lfHeight
= fd
[i
].height
;
791 strcpy(lf
.lfFaceName
, fd
[i
].face_name
);
793 for(bit
= 0; bit
< 32; bit
++)
800 if((fd
[i
].ansi_bitfield
& fs
[0]) == 0) continue;
801 if(!TranslateCharsetInfo( fs
, &csi
, TCI_SRCFONTSIG
)) continue;
803 lf
.lfCharSet
= csi
.ciCharset
;
804 ret
= EnumFontFamiliesEx(hdc
, &lf
, find_font_proc
, (LPARAM
)&lf
, 0);
807 hfont
= create_font(lf
.lfFaceName
, &lf
);
808 old_hfont
= SelectObject(hdc
, hfont
);
809 ok(GetTextMetrics(hdc
, &tm
), "GetTextMetrics error %d\n", GetLastError());
810 if(fd
[i
].dpi
== tm
.tmDigitizedAspectX
)
812 trace("found font %s, height %d charset %x dpi %d\n", lf
.lfFaceName
, lf
.lfHeight
, lf
.lfCharSet
, fd
[i
].dpi
);
813 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
);
814 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
);
815 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
);
816 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
);
817 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
);
818 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
);
819 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
);
821 /* Don't run the max char width test on System/ANSI_CHARSET. We have extra characters in our font
822 that make the max width bigger */
823 if(strcmp(lf
.lfFaceName
, "System") || lf
.lfCharSet
!= ANSI_CHARSET
)
824 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
);
826 SelectObject(hdc
, old_hfont
);
834 static void test_GdiGetCharDimensions(void)
840 LONG avgwidth
, height
;
841 static const char szAlphabet
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
843 if (!pGdiGetCharDimensions
)
845 win_skip("GdiGetCharDimensions not available on this platform\n");
849 hdc
= CreateCompatibleDC(NULL
);
851 GetTextExtentPoint(hdc
, szAlphabet
, strlen(szAlphabet
), &size
);
852 avgwidth
= ((size
.cx
/ 26) + 1) / 2;
854 ret
= pGdiGetCharDimensions(hdc
, &tm
, &height
);
855 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
856 ok(height
== tm
.tmHeight
, "GdiGetCharDimensions should have set height to %d instead of %d\n", tm
.tmHeight
, height
);
858 ret
= pGdiGetCharDimensions(hdc
, &tm
, NULL
);
859 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
861 ret
= pGdiGetCharDimensions(hdc
, NULL
, NULL
);
862 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
865 ret
= pGdiGetCharDimensions(hdc
, NULL
, &height
);
866 ok(ret
== avgwidth
, "GdiGetCharDimensions should have returned width of %d instead of %d\n", avgwidth
, ret
);
867 ok(height
== size
.cy
, "GdiGetCharDimensions should have set height to %d instead of %d\n", size
.cy
, height
);
872 static void test_GetCharABCWidths(void)
874 static const WCHAR str
[] = {'a',0};
883 if (!pGetCharABCWidthsW
|| !pGetCharABCWidthsI
)
885 win_skip("GetCharABCWidthsW/I not available on this platform\n");
889 memset(&lf
, 0, sizeof(lf
));
890 strcpy(lf
.lfFaceName
, "System");
893 hfont
= CreateFontIndirectA(&lf
);
895 hfont
= SelectObject(hdc
, hfont
);
897 nb
= pGetGlyphIndicesW(hdc
, str
, 1, glyphs
, 0);
898 ok(nb
== 1, "GetGlyphIndicesW should have returned 1\n");
900 ret
= pGetCharABCWidthsI(NULL
, 0, 1, glyphs
, abc
);
901 ok(!ret
, "GetCharABCWidthsI should have failed\n");
903 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, NULL
);
904 ok(!ret
, "GetCharABCWidthsI should have failed\n");
906 ret
= pGetCharABCWidthsI(hdc
, 0, 1, glyphs
, abc
);
907 ok(ret
, "GetCharABCWidthsI should have succeeded\n");
909 ret
= pGetCharABCWidthsW(NULL
, 'a', 'a', abc
);
910 ok(!ret
, "GetCharABCWidthsW should have failed\n");
912 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', NULL
);
913 ok(!ret
, "GetCharABCWidthsW should have failed\n");
915 ret
= pGetCharABCWidthsW(hdc
, 'a', 'a', abc
);
916 ok(!ret
, "GetCharABCWidthsW should have failed\n");
918 hfont
= SelectObject(hdc
, hfont
);
920 ReleaseDC(NULL
, hdc
);
923 static void test_text_extents(void)
925 static const WCHAR wt
[] = {'O','n','e','\n','t','w','o',' ','3',0};
927 INT i
, len
, fit1
, fit2
;
935 memset(&lf
, 0, sizeof(lf
));
936 strcpy(lf
.lfFaceName
, "Arial");
939 hfont
= CreateFontIndirectA(&lf
);
941 hfont
= SelectObject(hdc
, hfont
);
942 GetTextMetricsA(hdc
, &tm
);
943 GetTextExtentPointA(hdc
, "o", 1, &sz
);
944 ok(sz
.cy
== tm
.tmHeight
, "cy %d tmHeight %d\n", sz
.cy
, tm
.tmHeight
);
946 SetLastError(0xdeadbeef);
947 GetTextExtentExPointW(hdc
, wt
, 1, 1, &fit1
, &fit2
, &sz1
);
948 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
950 win_skip("Skipping remainder of text extents test on a Win9x platform\n");
951 hfont
= SelectObject(hdc
, hfont
);
958 extents
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
* sizeof extents
[0]);
959 extents
[0] = 1; /* So that the increasing sequence test will fail
960 if the extents array is untouched. */
961 GetTextExtentExPointW(hdc
, wt
, len
, 32767, &fit1
, extents
, &sz1
);
962 GetTextExtentPointW(hdc
, wt
, len
, &sz2
);
964 "cy from GetTextExtentExPointW (%d) and GetTextExtentPointW (%d) differ\n", sz1
.cy
, sz2
.cy
);
965 /* Because of the '\n' in the string GetTextExtentExPoint and
966 GetTextExtentPoint return different widths under Win2k, but
967 under WinXP they return the same width. So we don't test that
970 for (i
= 1; i
< len
; ++i
)
971 ok(extents
[i
-1] <= extents
[i
],
972 "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
974 ok(extents
[len
-1] == sz1
.cx
, "GetTextExtentExPointW extents and size don't match\n");
975 ok(0 <= fit1
&& fit1
<= len
, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1
);
976 ok(0 < fit1
, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
977 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2], &fit2
, NULL
, &sz2
);
978 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
, "GetTextExtentExPointW returned different sizes for the same string\n");
979 ok(fit2
== 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
980 GetTextExtentExPointW(hdc
, wt
, len
, extents
[2]-1, &fit2
, NULL
, &sz2
);
981 ok(fit2
== 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
982 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, extents
+ 2, &sz2
);
983 ok(extents
[0] == extents
[2] && extents
[1] == extents
[3],
984 "GetTextExtentExPointW with lpnFit == NULL returns incorrect results\n");
985 GetTextExtentExPointW(hdc
, wt
, 2, 0, NULL
, NULL
, &sz1
);
986 ok(sz1
.cx
== sz2
.cx
&& sz1
.cy
== sz2
.cy
,
987 "GetTextExtentExPointW with lpnFit and alpDx both NULL returns incorrect results\n");
988 HeapFree(GetProcessHeap(), 0, extents
);
990 hfont
= SelectObject(hdc
, hfont
);
992 ReleaseDC(NULL
, hdc
);
995 static void test_GetGlyphIndices(void)
1002 WCHAR testtext
[] = {'T','e','s','t',0xffff,0};
1003 WORD glyphs
[(sizeof(testtext
)/2)-1];
1007 if (!pGetGlyphIndicesW
) {
1008 win_skip("GetGlyphIndicesW not available on platform\n");
1014 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1015 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1016 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1017 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1018 ok((glyphs
[4] == 0x001f || glyphs
[4] == 0xffff /* Vista */), "GetGlyphIndicesW should have returned a nonexistent char not %04x\n", glyphs
[4]);
1020 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1021 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1022 ok(glyphs
[4] == textm
.tmDefaultChar
, "GetGlyphIndicesW should have returned a %04x not %04x\n",
1023 textm
.tmDefaultChar
, glyphs
[4]);
1025 if(!is_font_installed("Tahoma"))
1027 skip("Tahoma is not installed so skipping this test\n");
1030 memset(&lf
, 0, sizeof(lf
));
1031 strcpy(lf
.lfFaceName
, "Tahoma");
1034 hfont
= CreateFontIndirectA(&lf
);
1035 hOldFont
= SelectObject(hdc
, hfont
);
1036 ok(GetTextMetrics(hdc
, &textm
), "GetTextMetric failed\n");
1037 flags
|= GGI_MARK_NONEXISTING_GLYPHS
;
1038 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1039 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1040 ok(glyphs
[4] == 0xffff, "GetGlyphIndicesW should have returned 0xffff char not %04x\n", glyphs
[4]);
1042 testtext
[0] = textm
.tmDefaultChar
;
1043 charcount
= pGetGlyphIndicesW(hdc
, testtext
, (sizeof(testtext
)/2)-1, glyphs
, flags
);
1044 ok(charcount
== 5, "GetGlyphIndicesW count of glyphs should = 5 not %d\n", charcount
);
1045 ok(glyphs
[0] == 0, "GetGlyphIndicesW for tmDefaultChar should be 0 not %04x\n", glyphs
[0]);
1046 ok(glyphs
[4] == 0, "GetGlyphIndicesW should have returned 0 not %04x\n", glyphs
[4]);
1047 DeleteObject(SelectObject(hdc
, hOldFont
));
1050 static void test_GetKerningPairs(void)
1052 static const struct kerning_data
1054 const char face_name
[LF_FACESIZE
];
1056 /* some interesting fields from OUTLINETEXTMETRIC */
1057 LONG tmHeight
, tmAscent
, tmDescent
;
1062 UINT otmsCapEmHeight
;
1067 UINT otmusMinimumPPEM
;
1068 /* small subset of kerning pairs to test */
1069 DWORD total_kern_pairs
;
1070 const KERNINGPAIR kern_pair
[26];
1073 {"Arial", 12, 12, 9, 3,
1074 2048, 7, -2, 1, 5, 2, 8, -2, 0, 9,
1077 {' ','A',-1},{' ','T',0},{' ','Y',0},{'1','1',-1},
1078 {'A',' ',-1},{'A','T',-1},{'A','V',-1},{'A','W',0},
1079 {'A','Y',-1},{'A','v',0},{'A','w',0},{'A','y',0},
1080 {'F',',',-1},{'F','.',-1},{'F','A',-1},{'L',' ',0},
1081 {'L','T',-1},{'L','V',-1},{'L','W',-1},{'L','Y',-1},
1082 {915,912,+1},{915,913,-1},{910,912,+1},{910,913,-1},
1083 {933,970,+1},{933,972,-1}
1086 {"Arial", -34, 39, 32, 7,
1087 2048, 25, -7, 5, 17, 9, 31, -7, 1, 9,
1090 {' ','A',-2},{' ','T',-1},{' ','Y',-1},{'1','1',-3},
1091 {'A',' ',-2},{'A','T',-3},{'A','V',-3},{'A','W',-1},
1092 {'A','Y',-3},{'A','v',-1},{'A','w',-1},{'A','y',-1},
1093 {'F',',',-4},{'F','.',-4},{'F','A',-2},{'L',' ',-1},
1094 {'L','T',-3},{'L','V',-3},{'L','W',-3},{'L','Y',-3},
1095 {915,912,+3},{915,913,-3},{910,912,+3},{910,913,-3},
1096 {933,970,+2},{933,972,-3}
1099 { "Arial", 120, 120, 97, 23,
1100 2048, 79, -23, 16, 54, 27, 98, -23, 4, 9,
1103 {' ','A',-6},{' ','T',-2},{' ','Y',-2},{'1','1',-8},
1104 {'A',' ',-6},{'A','T',-8},{'A','V',-8},{'A','W',-4},
1105 {'A','Y',-8},{'A','v',-2},{'A','w',-2},{'A','y',-2},
1106 {'F',',',-12},{'F','.',-12},{'F','A',-6},{'L',' ',-4},
1107 {'L','T',-8},{'L','V',-8},{'L','W',-8},{'L','Y',-8},
1108 {915,912,+9},{915,913,-10},{910,912,+9},{910,913,-8},
1109 {933,970,+6},{933,972,-10}
1112 #if 0 /* this set fails due to +1/-1 errors (rounding bug?), needs investigation. */
1113 { "Arial", 1024 /* usually 1/2 of EM Square */, 1024, 830, 194,
1114 2048, 668, -193, 137, 459, 229, 830, -194, 30, 9,
1117 {' ','A',-51},{' ','T',-17},{' ','Y',-17},{'1','1',-68},
1118 {'A',' ',-51},{'A','T',-68},{'A','V',-68},{'A','W',-34},
1119 {'A','Y',-68},{'A','v',-17},{'A','w',-17},{'A','y',-17},
1120 {'F',',',-102},{'F','.',-102},{'F','A',-51},{'L',' ',-34},
1121 {'L','T',-68},{'L','V',-68},{'L','W',-68},{'L','Y',-68},
1122 {915,912,+73},{915,913,-84},{910,912,+76},{910,913,-68},
1123 {933,970,+54},{933,972,-83}
1129 HFONT hfont
, hfont_old
;
1130 KERNINGPAIR
*kern_pair
;
1132 DWORD total_kern_pairs
, ret
, i
, n
, matches
;
1136 /* GetKerningPairsA maps unicode set of kerning pairs to current code page
1137 * which may render this test unusable, so we're trying to avoid that.
1139 SetLastError(0xdeadbeef);
1140 GetKerningPairsW(hdc
, 0, NULL
);
1141 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1143 win_skip("Skipping the GetKerningPairs test on a Win9x platform\n");
1148 for (i
= 0; i
< sizeof(kd
)/sizeof(kd
[0]); i
++)
1150 OUTLINETEXTMETRICW otm
;
1152 if (!is_font_installed(kd
[i
].face_name
))
1154 trace("%s is not installed so skipping this test\n", kd
[i
].face_name
);
1158 trace("testing font %s, height %d\n", kd
[i
].face_name
, kd
[i
].height
);
1160 memset(&lf
, 0, sizeof(lf
));
1161 strcpy(lf
.lfFaceName
, kd
[i
].face_name
);
1162 lf
.lfHeight
= kd
[i
].height
;
1163 hfont
= CreateFontIndirect(&lf
);
1166 hfont_old
= SelectObject(hdc
, hfont
);
1168 SetLastError(0xdeadbeef);
1169 otm
.otmSize
= sizeof(otm
); /* just in case for Win9x compatibility */
1170 ok(GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
) == sizeof(otm
), "GetOutlineTextMetricsW error %d\n", GetLastError());
1172 ok(kd
[i
].tmHeight
== otm
.otmTextMetrics
.tmHeight
, "expected %d, got %d\n",
1173 kd
[i
].tmHeight
, otm
.otmTextMetrics
.tmHeight
);
1174 ok(kd
[i
].tmAscent
== otm
.otmTextMetrics
.tmAscent
, "expected %d, got %d\n",
1175 kd
[i
].tmAscent
, otm
.otmTextMetrics
.tmAscent
);
1176 ok(kd
[i
].tmDescent
== otm
.otmTextMetrics
.tmDescent
, "expected %d, got %d\n",
1177 kd
[i
].tmDescent
, otm
.otmTextMetrics
.tmDescent
);
1179 ok(kd
[i
].otmEMSquare
== otm
.otmEMSquare
, "expected %u, got %u\n",
1180 kd
[i
].otmEMSquare
, otm
.otmEMSquare
);
1181 ok(kd
[i
].otmAscent
== otm
.otmAscent
, "expected %d, got %d\n",
1182 kd
[i
].otmAscent
, otm
.otmAscent
);
1183 ok(kd
[i
].otmDescent
== otm
.otmDescent
, "expected %d, got %d\n",
1184 kd
[i
].otmDescent
, otm
.otmDescent
);
1185 ok(kd
[i
].otmLineGap
== otm
.otmLineGap
, "expected %u, got %u\n",
1186 kd
[i
].otmLineGap
, otm
.otmLineGap
);
1187 ok(near_match(kd
[i
].otmMacDescent
, otm
.otmMacDescent
), "expected %d, got %d\n",
1188 kd
[i
].otmMacDescent
, otm
.otmMacDescent
);
1190 ok(kd
[i
].otmsCapEmHeight
== otm
.otmsCapEmHeight
, "expected %u, got %u\n",
1191 kd
[i
].otmsCapEmHeight
, otm
.otmsCapEmHeight
);
1192 ok(kd
[i
].otmsXHeight
== otm
.otmsXHeight
, "expected %u, got %u\n",
1193 kd
[i
].otmsXHeight
, otm
.otmsXHeight
);
1194 ok(kd
[i
].otmMacAscent
== otm
.otmMacAscent
, "expected %d, got %d\n",
1195 kd
[i
].otmMacAscent
, otm
.otmMacAscent
);
1196 /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
1197 if (0) ok(kd
[i
].otmMacLineGap
== otm
.otmMacLineGap
, "expected %u, got %u\n",
1198 kd
[i
].otmMacLineGap
, otm
.otmMacLineGap
);
1199 ok(kd
[i
].otmusMinimumPPEM
== otm
.otmusMinimumPPEM
, "expected %u, got %u\n",
1200 kd
[i
].otmusMinimumPPEM
, otm
.otmusMinimumPPEM
);
1203 total_kern_pairs
= GetKerningPairsW(hdc
, 0, NULL
);
1204 trace("total_kern_pairs %u\n", total_kern_pairs
);
1205 kern_pair
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pair
));
1207 #if 0 /* Win98 (GetKerningPairsA) and XP behave differently here, the test passes on XP */
1208 SetLastError(0xdeadbeef);
1209 ret
= GetKerningPairsW(hdc
, 0, kern_pair
);
1210 ok(GetLastError() == ERROR_INVALID_PARAMETER
,
1211 "got error %ld, expected ERROR_INVALID_PARAMETER\n", GetLastError());
1212 ok(ret
== 0, "got %lu, expected 0\n", ret
);
1215 ret
= GetKerningPairsW(hdc
, 100, NULL
);
1216 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1218 ret
= GetKerningPairsW(hdc
, total_kern_pairs
/2, kern_pair
);
1219 ok(ret
== total_kern_pairs
/2, "got %u, expected %u\n", ret
, total_kern_pairs
/2);
1221 ret
= GetKerningPairsW(hdc
, total_kern_pairs
, kern_pair
);
1222 ok(ret
== total_kern_pairs
, "got %u, expected %u\n", ret
, total_kern_pairs
);
1226 for (n
= 0; n
< ret
; n
++)
1230 if (kern_pair
[n
].wFirst
< 127 && kern_pair
[n
].wSecond
< 127)
1231 trace("{'%c','%c',%d},\n",
1232 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
, kern_pair
[n
].iKernAmount
);
1234 for (j
= 0; j
< kd
[i
].total_kern_pairs
; j
++)
1236 if (kern_pair
[n
].wFirst
== kd
[i
].kern_pair
[j
].wFirst
&&
1237 kern_pair
[n
].wSecond
== kd
[i
].kern_pair
[j
].wSecond
)
1239 ok(kern_pair
[n
].iKernAmount
== kd
[i
].kern_pair
[j
].iKernAmount
,
1240 "pair %d:%d got %d, expected %d\n",
1241 kern_pair
[n
].wFirst
, kern_pair
[n
].wSecond
,
1242 kern_pair
[n
].iKernAmount
, kd
[i
].kern_pair
[j
].iKernAmount
);
1248 ok(matches
== kd
[i
].total_kern_pairs
, "got matches %u, expected %u\n",
1249 matches
, kd
[i
].total_kern_pairs
);
1251 HeapFree(GetProcessHeap(), 0, kern_pair
);
1253 SelectObject(hdc
, hfont_old
);
1254 DeleteObject(hfont
);
1260 static void test_GetOutlineTextMetrics(void)
1262 OUTLINETEXTMETRIC
*otm
;
1264 HFONT hfont
, hfont_old
;
1266 DWORD ret
, otm_size
;
1269 if (!is_font_installed("Arial"))
1271 skip("Arial is not installed\n");
1277 memset(&lf
, 0, sizeof(lf
));
1278 strcpy(lf
.lfFaceName
, "Arial");
1280 lf
.lfWeight
= FW_NORMAL
;
1281 lf
.lfPitchAndFamily
= DEFAULT_PITCH
;
1282 lf
.lfQuality
= PROOF_QUALITY
;
1283 hfont
= CreateFontIndirect(&lf
);
1286 hfont_old
= SelectObject(hdc
, hfont
);
1287 otm_size
= GetOutlineTextMetrics(hdc
, 0, NULL
);
1288 trace("otm buffer size %u (0x%x)\n", otm_size
, otm_size
);
1290 otm
= HeapAlloc(GetProcessHeap(), 0, otm_size
);
1292 memset(otm
, 0xAA, otm_size
);
1293 SetLastError(0xdeadbeef);
1294 otm
->otmSize
= sizeof(*otm
); /* just in case for Win9x compatibility */
1295 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1296 ok(ret
== 1 /* Win9x */ ||
1297 ret
== otm
->otmSize
/* XP*/,
1298 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1299 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1301 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1302 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1303 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1304 ok(otm
->otmpFullName
== NULL
, "expected NULL got %p\n", otm
->otmpFullName
);
1307 memset(otm
, 0xAA, otm_size
);
1308 SetLastError(0xdeadbeef);
1309 otm
->otmSize
= otm_size
; /* just in case for Win9x compatibility */
1310 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1311 ok(ret
== 1 /* Win9x */ ||
1312 ret
== otm
->otmSize
/* XP*/,
1313 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1314 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1316 ok(otm
->otmpFamilyName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFamilyName
);
1317 ok(otm
->otmpFaceName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFaceName
);
1318 ok(otm
->otmpStyleName
!= NULL
, "expected not NULL got %p\n", otm
->otmpStyleName
);
1319 ok(otm
->otmpFullName
!= NULL
, "expected not NULL got %p\n", otm
->otmpFullName
);
1322 /* ask about truncated data */
1323 memset(otm
, 0xAA, otm_size
);
1324 memset(&unset_ptr
, 0xAA, sizeof(unset_ptr
));
1325 SetLastError(0xdeadbeef);
1326 otm
->otmSize
= sizeof(*otm
) - sizeof(LPSTR
); /* just in case for Win9x compatibility */
1327 ret
= GetOutlineTextMetrics(hdc
, otm
->otmSize
, otm
);
1328 ok(ret
== 1 /* Win9x */ ||
1329 ret
== otm
->otmSize
/* XP*/,
1330 "expected %u, got %u, error %d\n", otm
->otmSize
, ret
, GetLastError());
1331 if (ret
!= 1) /* Win9x doesn't care about pointing beyond of the buffer */
1333 ok(otm
->otmpFamilyName
== NULL
, "expected NULL got %p\n", otm
->otmpFamilyName
);
1334 ok(otm
->otmpFaceName
== NULL
, "expected NULL got %p\n", otm
->otmpFaceName
);
1335 ok(otm
->otmpStyleName
== NULL
, "expected NULL got %p\n", otm
->otmpStyleName
);
1337 ok(otm
->otmpFullName
== unset_ptr
, "expected %p got %p\n", unset_ptr
, otm
->otmpFullName
);
1339 HeapFree(GetProcessHeap(), 0, otm
);
1341 SelectObject(hdc
, hfont_old
);
1342 DeleteObject(hfont
);
1347 static void testJustification(HDC hdc
, PSTR str
, RECT
*clientArea
)
1351 justifiedWidth
= 0, /* to test GetTextExtentExPointW() */
1352 areaWidth
= clientArea
->right
- clientArea
->left
,
1354 BOOL lastExtent
= FALSE
;
1355 PSTR pFirstChar
, pLastChar
;
1361 int GetTextExtentExPointWWidth
;
1364 GetTextMetricsA(hdc
, &tm
);
1365 y
= clientArea
->top
;
1368 while (*str
== tm
.tmBreakChar
) str
++; /* skip leading break chars */
1374 /* if not at the end of the string, ... */
1375 if (*str
== '\0') break;
1376 /* ... add the next word to the current extent */
1377 while (*str
!= '\0' && *str
++ != tm
.tmBreakChar
);
1379 SetTextJustification(hdc
, 0, 0);
1380 GetTextExtentPoint32(hdc
, pFirstChar
, str
- pFirstChar
- 1, &size
);
1381 } while ((int) size
.cx
< areaWidth
);
1383 /* ignore trailing break chars */
1385 while (*(pLastChar
- 1) == tm
.tmBreakChar
)
1391 if (*str
== '\0' || breakCount
<= 0) pLastChar
= str
;
1393 SetTextJustification(hdc
, 0, 0);
1394 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1396 /* do not justify the last extent */
1397 if (*str
!= '\0' && breakCount
> 0)
1399 SetTextJustification(hdc
, areaWidth
- size
.cx
, breakCount
);
1400 GetTextExtentPoint32(hdc
, pFirstChar
, pLastChar
- pFirstChar
, &size
);
1401 justifiedWidth
= size
.cx
;
1403 else lastExtent
= TRUE
;
1405 x
= clientArea
->left
;
1407 /* catch errors and report them */
1408 if (!lastExtent
&& (justifiedWidth
!= areaWidth
))
1410 memset(error
[nErrors
].extent
, 0, 100);
1411 memcpy(error
[nErrors
].extent
, pFirstChar
, pLastChar
- pFirstChar
);
1412 error
[nErrors
].GetTextExtentExPointWWidth
= justifiedWidth
;
1418 } while (*str
&& y
< clientArea
->bottom
);
1420 for (e
= 0; e
< nErrors
; e
++)
1422 /* The width returned by GetTextExtentPoint32() is exactly the same
1423 returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
1424 ok(error
[e
].GetTextExtentExPointWWidth
== areaWidth
,
1425 "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
1426 error
[e
].extent
, areaWidth
, error
[e
].GetTextExtentExPointWWidth
);
1430 static void test_SetTextJustification(void)
1437 static char testText
[] =
1438 "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
1439 "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
1440 "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
1441 "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
1442 "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
1443 "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
1444 "sunt in culpa qui officia deserunt mollit anim id est laborum.";
1446 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0, 400,400, 0, 0, 0, NULL
);
1447 GetClientRect( hwnd
, &clientArea
);
1448 hdc
= GetDC( hwnd
);
1450 memset(&lf
, 0, sizeof lf
);
1451 lf
.lfCharSet
= ANSI_CHARSET
;
1452 lf
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1453 lf
.lfWeight
= FW_DONTCARE
;
1455 lf
.lfQuality
= DEFAULT_QUALITY
;
1456 lstrcpyA(lf
.lfFaceName
, "Times New Roman");
1457 hfont
= create_font("Times New Roman", &lf
);
1458 SelectObject(hdc
, hfont
);
1460 testJustification(hdc
, testText
, &clientArea
);
1462 DeleteObject(hfont
);
1463 ReleaseDC(hwnd
, hdc
);
1464 DestroyWindow(hwnd
);
1467 static BOOL
get_glyph_indices(INT charset
, UINT code_page
, WORD
*idx
, UINT count
, BOOL unicode
)
1471 HFONT hfont
, hfont_old
;
1478 assert(count
<= 128);
1480 memset(&lf
, 0, sizeof(lf
));
1482 lf
.lfCharSet
= charset
;
1484 lstrcpyA(lf
.lfFaceName
, "Arial");
1485 SetLastError(0xdeadbeef);
1486 hfont
= CreateFontIndirectA(&lf
);
1487 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
1490 hfont_old
= SelectObject(hdc
, hfont
);
1492 cs
= GetTextCharsetInfo(hdc
, &fs
, 0);
1493 ok(cs
== charset
, "expected %d, got %d\n", charset
, cs
);
1495 SetLastError(0xdeadbeef);
1496 ret
= GetTextFaceA(hdc
, sizeof(name
), name
);
1497 ok(ret
, "GetTextFaceA error %u\n", GetLastError());
1499 if (charset
== SYMBOL_CHARSET
)
1501 ok(strcmp("Arial", name
), "face name should NOT be Arial\n");
1502 ok(fs
.fsCsb
[0] & (1 << 31), "symbol encoding should be available\n");
1506 ok(!strcmp("Arial", name
), "face name should be Arial, not %s\n", name
);
1507 ok(!(fs
.fsCsb
[0] & (1 << 31)), "symbol encoding should NOT be available\n");
1510 if (!TranslateCharsetInfo((DWORD
*)(INT_PTR
)cs
, &csi
, TCI_SRCCHARSET
))
1512 trace("Can't find codepage for charset %d\n", cs
);
1516 ok(csi
.ciACP
== code_page
, "expected %d, got %d\n", code_page
, csi
.ciACP
);
1521 WCHAR unicode_buf
[128];
1523 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1525 MultiByteToWideChar(code_page
, 0, ansi_buf
, count
, unicode_buf
, count
);
1527 SetLastError(0xdeadbeef);
1528 ret
= pGetGlyphIndicesW(hdc
, unicode_buf
, count
, idx
, 0);
1529 ok(ret
== count
, "GetGlyphIndicesW error %u\n", GetLastError());
1535 for (i
= 0; i
< count
; i
++) ansi_buf
[i
] = (BYTE
)(i
+ 128);
1537 SetLastError(0xdeadbeef);
1538 ret
= pGetGlyphIndicesA(hdc
, ansi_buf
, count
, idx
, 0);
1539 ok(ret
== count
, "GetGlyphIndicesA error %u\n", GetLastError());
1542 SelectObject(hdc
, hfont_old
);
1543 DeleteObject(hfont
);
1550 static void test_font_charset(void)
1552 static struct charset_data
1556 WORD font_idxA
[128], font_idxW
[128];
1559 { ANSI_CHARSET
, 1252 },
1560 { RUSSIAN_CHARSET
, 1251 },
1561 { SYMBOL_CHARSET
, CP_SYMBOL
} /* keep it as the last one */
1565 if (!pGetGlyphIndicesA
|| !pGetGlyphIndicesW
)
1567 win_skip("Skipping the font charset test on a Win9x platform\n");
1571 if (!is_font_installed("Arial"))
1573 skip("Arial is not installed\n");
1577 for (i
= 0; i
< sizeof(cd
)/sizeof(cd
[0]); i
++)
1579 if (cd
[i
].charset
== SYMBOL_CHARSET
)
1581 if (!is_font_installed("Symbol") && !is_font_installed("Wingdings"))
1583 skip("Symbol or Wingdings is not installed\n");
1587 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxA
, 128, FALSE
);
1588 get_glyph_indices(cd
[i
].charset
, cd
[i
].code_page
, cd
[i
].font_idxW
, 128, TRUE
);
1589 ok(!memcmp(cd
[i
].font_idxA
, cd
[i
].font_idxW
, 128*sizeof(WORD
)), "%d: indices don't match\n", i
);
1592 ok(memcmp(cd
[0].font_idxW
, cd
[1].font_idxW
, 128*sizeof(WORD
)), "0 vs 1: indices shouldn't match\n");
1595 ok(memcmp(cd
[0].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "0 vs 2: indices shouldn't match\n");
1596 ok(memcmp(cd
[1].font_idxW
, cd
[2].font_idxW
, 128*sizeof(WORD
)), "1 vs 2: indices shouldn't match\n");
1599 skip("Symbol or Wingdings is not installed\n");
1602 static void test_GetFontUnicodeRanges(void)
1606 HFONT hfont
, hfont_old
;
1610 if (!pGetFontUnicodeRanges
)
1612 win_skip("GetFontUnicodeRanges not available before W2K\n");
1616 memset(&lf
, 0, sizeof(lf
));
1617 lstrcpyA(lf
.lfFaceName
, "Arial");
1618 hfont
= create_font("Arial", &lf
);
1621 hfont_old
= SelectObject(hdc
, hfont
);
1623 size
= pGetFontUnicodeRanges(NULL
, NULL
);
1624 ok(!size
, "GetFontUnicodeRanges succeeded unexpectedly\n");
1626 size
= pGetFontUnicodeRanges(hdc
, NULL
);
1627 ok(size
, "GetFontUnicodeRanges failed unexpectedly\n");
1629 gs
= HeapAlloc(GetProcessHeap(), 0, size
);
1631 size
= pGetFontUnicodeRanges(hdc
, gs
);
1632 ok(size
, "GetFontUnicodeRanges failed\n");
1634 for (i
= 0; i
< gs
->cRanges
; i
++)
1635 trace("%03d wcLow %04x cGlyphs %u\n", i
, gs
->ranges
[i
].wcLow
, gs
->ranges
[i
].cGlyphs
);
1637 trace("found %u ranges\n", gs
->cRanges
);
1639 HeapFree(GetProcessHeap(), 0, gs
);
1641 SelectObject(hdc
, hfont_old
);
1642 DeleteObject(hfont
);
1643 ReleaseDC(NULL
, hdc
);
1646 #define MAX_ENUM_FONTS 4096
1648 struct enum_font_data
1651 LOGFONT lf
[MAX_ENUM_FONTS
];
1654 struct enum_font_dataW
1657 LOGFONTW lf
[MAX_ENUM_FONTS
];
1660 static INT CALLBACK
arial_enum_proc(const LOGFONT
*lf
, const TEXTMETRIC
*tm
, DWORD type
, LPARAM lParam
)
1662 struct enum_font_data
*efd
= (struct enum_font_data
*)lParam
;
1664 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1666 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1668 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1669 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1671 if (efd
->total
< MAX_ENUM_FONTS
)
1672 efd
->lf
[efd
->total
++] = *lf
;
1674 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1679 static INT CALLBACK
arial_enum_procw(const LOGFONTW
*lf
, const TEXTMETRICW
*tm
, DWORD type
, LPARAM lParam
)
1681 struct enum_font_dataW
*efd
= (struct enum_font_dataW
*)lParam
;
1683 ok(lf
->lfHeight
== tm
->tmHeight
, "lfHeight %d != tmHeight %d\n", lf
->lfHeight
, tm
->tmHeight
);
1685 if (type
!= TRUETYPE_FONTTYPE
) return 1;
1687 trace("enumed font \"%s\", charset %d, height %d, weight %d, italic %d\n",
1688 lf
->lfFaceName
, lf
->lfCharSet
, lf
->lfHeight
, lf
->lfWeight
, lf
->lfItalic
);
1690 if (efd
->total
< MAX_ENUM_FONTS
)
1691 efd
->lf
[efd
->total
++] = *lf
;
1693 trace("enum tests invalid; you have more than %d fonts\n", MAX_ENUM_FONTS
);
1698 static void get_charset_stats(struct enum_font_data
*efd
,
1699 int *ansi_charset
, int *symbol_charset
,
1700 int *russian_charset
)
1705 *symbol_charset
= 0;
1706 *russian_charset
= 0;
1708 for (i
= 0; i
< efd
->total
; i
++)
1710 switch (efd
->lf
[i
].lfCharSet
)
1715 case SYMBOL_CHARSET
:
1716 (*symbol_charset
)++;
1718 case RUSSIAN_CHARSET
:
1719 (*russian_charset
)++;
1725 static void get_charset_statsW(struct enum_font_dataW
*efd
,
1726 int *ansi_charset
, int *symbol_charset
,
1727 int *russian_charset
)
1732 *symbol_charset
= 0;
1733 *russian_charset
= 0;
1735 for (i
= 0; i
< efd
->total
; i
++)
1737 switch (efd
->lf
[i
].lfCharSet
)
1742 case SYMBOL_CHARSET
:
1743 (*symbol_charset
)++;
1745 case RUSSIAN_CHARSET
:
1746 (*russian_charset
)++;
1752 static void test_EnumFontFamilies(const char *font_name
, INT font_charset
)
1754 struct enum_font_data efd
;
1755 struct enum_font_dataW efdw
;
1758 int i
, ret
, ansi_charset
, symbol_charset
, russian_charset
;
1760 trace("Testing font %s, charset %d\n", *font_name
? font_name
: "<empty>", font_charset
);
1762 if (*font_name
&& !is_truetype_font_installed(font_name
))
1764 skip("%s is not installed\n", font_name
);
1770 /* Observed behaviour: EnumFontFamilies enumerates aliases like "Arial Cyr"
1771 * while EnumFontFamiliesEx doesn't.
1773 if (!*font_name
&& font_charset
== DEFAULT_CHARSET
) /* do it only once */
1776 * Use EnumFontFamiliesW since win98 crashes when the
1777 * second parameter is NULL using EnumFontFamilies
1780 SetLastError(0xdeadbeef);
1781 ret
= EnumFontFamiliesW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
);
1782 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesW error %u\n", GetLastError());
1785 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1786 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1787 ansi_charset
, symbol_charset
, russian_charset
);
1788 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
1789 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1790 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1791 ok(russian_charset
> 0 ||
1792 broken(russian_charset
== 0), /* NT4 */
1793 "NULL family should enumerate RUSSIAN_CHARSET\n");
1797 SetLastError(0xdeadbeef);
1798 ret
= EnumFontFamiliesExW(hdc
, NULL
, arial_enum_procw
, (LPARAM
)&efdw
, 0);
1799 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
, "EnumFontFamiliesExW error %u\n", GetLastError());
1802 get_charset_statsW(&efdw
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1803 trace("enumerated ansi %d, symbol %d, russian %d fonts for NULL\n",
1804 ansi_charset
, symbol_charset
, russian_charset
);
1805 ok(efdw
.total
> 0, "fonts enumerated: NULL\n");
1806 ok(ansi_charset
> 0, "NULL family should enumerate ANSI_CHARSET\n");
1807 ok(symbol_charset
> 0, "NULL family should enumerate SYMBOL_CHARSET\n");
1808 ok(russian_charset
> 0, "NULL family should enumerate RUSSIAN_CHARSET\n");
1813 SetLastError(0xdeadbeef);
1814 ret
= EnumFontFamilies(hdc
, font_name
, arial_enum_proc
, (LPARAM
)&efd
);
1815 ok(ret
, "EnumFontFamilies error %u\n", GetLastError());
1816 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1817 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s\n",
1818 ansi_charset
, symbol_charset
, russian_charset
,
1819 *font_name
? font_name
: "<empty>");
1821 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1823 ok(!efd
.total
, "no fonts should be enumerated for empty font_name\n");
1824 for (i
= 0; i
< efd
.total
; i
++)
1826 /* FIXME: remove completely once Wine is fixed */
1827 if (efd
.lf
[i
].lfCharSet
!= font_charset
)
1830 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1833 ok(efd
.lf
[i
].lfCharSet
== font_charset
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1834 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1835 font_name
, efd
.lf
[i
].lfFaceName
);
1838 memset(&lf
, 0, sizeof(lf
));
1839 lf
.lfCharSet
= ANSI_CHARSET
;
1840 lstrcpy(lf
.lfFaceName
, font_name
);
1842 SetLastError(0xdeadbeef);
1843 ret
= EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1844 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1845 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1846 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s ANSI_CHARSET\n",
1847 ansi_charset
, symbol_charset
, russian_charset
,
1848 *font_name
? font_name
: "<empty>");
1849 if (font_charset
== SYMBOL_CHARSET
)
1852 ok(efd
.total
== 0, "no fonts should be enumerated: %s ANSI_CHARSET\n", font_name
);
1854 ok(efd
.total
> 0, "no fonts enumerated: %s\n", font_name
);
1858 ok(efd
.total
> 0, "no fonts enumerated: %s ANSI_CHARSET\n", font_name
);
1859 for (i
= 0; i
< efd
.total
; i
++)
1861 ok(efd
.lf
[i
].lfCharSet
== ANSI_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1863 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1864 font_name
, efd
.lf
[i
].lfFaceName
);
1868 /* DEFAULT_CHARSET should enumerate all available charsets */
1869 memset(&lf
, 0, sizeof(lf
));
1870 lf
.lfCharSet
= DEFAULT_CHARSET
;
1871 lstrcpy(lf
.lfFaceName
, font_name
);
1873 SetLastError(0xdeadbeef);
1874 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1875 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1876 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1877 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s DEFAULT_CHARSET\n",
1878 ansi_charset
, symbol_charset
, russian_charset
,
1879 *font_name
? font_name
: "<empty>");
1880 ok(efd
.total
> 0, "no fonts enumerated: %s DEFAULT_CHARSET\n", font_name
);
1881 for (i
= 0; i
< efd
.total
; i
++)
1884 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1885 font_name
, efd
.lf
[i
].lfFaceName
);
1889 switch (font_charset
)
1892 ok(ansi_charset
> 0,
1893 "ANSI_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1895 "ANSI_CHARSET should NOT enumerate SYMBOL_CHARSET for %s\n", font_name
);
1896 ok(russian_charset
> 0,
1897 "ANSI_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1899 case SYMBOL_CHARSET
:
1901 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", font_name
);
1903 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1904 ok(!russian_charset
,
1905 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1907 case DEFAULT_CHARSET
:
1908 ok(ansi_charset
> 0,
1909 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", font_name
);
1910 ok(symbol_charset
> 0,
1911 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", font_name
);
1912 ok(russian_charset
> 0,
1913 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", font_name
);
1919 ok(ansi_charset
> 0,
1920 "DEFAULT_CHARSET should enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1921 ok(symbol_charset
> 0,
1922 "DEFAULT_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1923 ok(russian_charset
> 0,
1924 "DEFAULT_CHARSET should enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1927 memset(&lf
, 0, sizeof(lf
));
1928 lf
.lfCharSet
= SYMBOL_CHARSET
;
1929 lstrcpy(lf
.lfFaceName
, font_name
);
1931 SetLastError(0xdeadbeef);
1932 EnumFontFamiliesEx(hdc
, &lf
, arial_enum_proc
, (LPARAM
)&efd
, 0);
1933 ok(ret
, "EnumFontFamiliesEx error %u\n", GetLastError());
1934 get_charset_stats(&efd
, &ansi_charset
, &symbol_charset
, &russian_charset
);
1935 trace("enumerated ansi %d, symbol %d, russian %d fonts for %s SYMBOL_CHARSET\n",
1936 ansi_charset
, symbol_charset
, russian_charset
,
1937 *font_name
? font_name
: "<empty>");
1938 if (*font_name
&& font_charset
== ANSI_CHARSET
)
1939 ok(efd
.total
== 0, "no fonts should be enumerated: %s SYMBOL_CHARSET\n", font_name
);
1942 ok(efd
.total
> 0, "no fonts enumerated: %s SYMBOL_CHARSET\n", font_name
);
1943 for (i
= 0; i
< efd
.total
; i
++)
1945 ok(efd
.lf
[i
].lfCharSet
== SYMBOL_CHARSET
, "%d: got charset %d\n", i
, efd
.lf
[i
].lfCharSet
);
1947 ok(!lstrcmp(efd
.lf
[i
].lfFaceName
, font_name
), "expected %s, got %s\n",
1948 font_name
, efd
.lf
[i
].lfFaceName
);
1952 "SYMBOL_CHARSET should NOT enumerate ANSI_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1953 ok(symbol_charset
> 0,
1954 "SYMBOL_CHARSET should enumerate SYMBOL_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1955 ok(!russian_charset
,
1956 "SYMBOL_CHARSET should NOT enumerate RUSSIAN_CHARSET for %s\n", *font_name
? font_name
: "<empty>");
1962 static void test_negative_width(HDC hdc
, const LOGFONTA
*lf
)
1964 HFONT hfont
, hfont_prev
;
1966 GLYPHMETRICS gm1
, gm2
;
1969 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
1971 if(!pGetGlyphIndicesA
)
1974 /* negative widths are handled just as positive ones */
1975 lf2
.lfWidth
= -lf
->lfWidth
;
1977 SetLastError(0xdeadbeef);
1978 hfont
= CreateFontIndirectA(lf
);
1979 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
1980 check_font("original", lf
, hfont
);
1982 hfont_prev
= SelectObject(hdc
, hfont
);
1984 ret
= pGetGlyphIndicesA(hdc
, "x", 1, &idx
, GGI_MARK_NONEXISTING_GLYPHS
);
1985 if (ret
== GDI_ERROR
|| idx
== 0xffff)
1987 SelectObject(hdc
, hfont_prev
);
1988 DeleteObject(hfont
);
1989 skip("Font %s doesn't contain 'x', skipping the test\n", lf
->lfFaceName
);
1993 /* filling with 0xaa causes false pass under WINEDEBUG=warn+heap */
1994 memset(&gm1
, 0xab, sizeof(gm1
));
1995 SetLastError(0xdeadbeef);
1996 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm1
, 0, NULL
, &mat
);
1997 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
1999 SelectObject(hdc
, hfont_prev
);
2000 DeleteObject(hfont
);
2002 SetLastError(0xdeadbeef);
2003 hfont
= CreateFontIndirectA(&lf2
);
2004 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2005 check_font("negative width", &lf2
, hfont
);
2007 hfont_prev
= SelectObject(hdc
, hfont
);
2009 memset(&gm2
, 0xbb, sizeof(gm2
));
2010 SetLastError(0xdeadbeef);
2011 ret
= GetGlyphOutlineA(hdc
, 'x', GGO_METRICS
, &gm2
, 0, NULL
, &mat
);
2012 ok(ret
!= GDI_ERROR
, "GetGlyphOutline error 0x%x\n", GetLastError());
2014 SelectObject(hdc
, hfont_prev
);
2015 DeleteObject(hfont
);
2017 ok(gm1
.gmBlackBoxX
== gm2
.gmBlackBoxX
&&
2018 gm1
.gmBlackBoxY
== gm2
.gmBlackBoxY
&&
2019 gm1
.gmptGlyphOrigin
.x
== gm2
.gmptGlyphOrigin
.x
&&
2020 gm1
.gmptGlyphOrigin
.y
== gm2
.gmptGlyphOrigin
.y
&&
2021 gm1
.gmCellIncX
== gm2
.gmCellIncX
&&
2022 gm1
.gmCellIncY
== gm2
.gmCellIncY
,
2023 "gm1=%d,%d,%d,%d,%d,%d gm2=%d,%d,%d,%d,%d,%d\n",
2024 gm1
.gmBlackBoxX
, gm1
.gmBlackBoxY
, gm1
.gmptGlyphOrigin
.x
,
2025 gm1
.gmptGlyphOrigin
.y
, gm1
.gmCellIncX
, gm1
.gmCellIncY
,
2026 gm2
.gmBlackBoxX
, gm2
.gmBlackBoxY
, gm2
.gmptGlyphOrigin
.x
,
2027 gm2
.gmptGlyphOrigin
.y
, gm2
.gmCellIncX
, gm2
.gmCellIncY
);
2030 /* PANOSE is 10 bytes in size, need to pack the structure properly */
2031 #include "pshpack2.h"
2035 SHORT xAvgCharWidth
;
2036 USHORT usWeightClass
;
2037 USHORT usWidthClass
;
2039 SHORT ySubscriptXSize
;
2040 SHORT ySubscriptYSize
;
2041 SHORT ySubscriptXOffset
;
2042 SHORT ySubscriptYOffset
;
2043 SHORT ySuperscriptXSize
;
2044 SHORT ySuperscriptYSize
;
2045 SHORT ySuperscriptXOffset
;
2046 SHORT ySuperscriptYOffset
;
2047 SHORT yStrikeoutSize
;
2048 SHORT yStrikeoutPosition
;
2051 ULONG ulUnicodeRange1
;
2052 ULONG ulUnicodeRange2
;
2053 ULONG ulUnicodeRange3
;
2054 ULONG ulUnicodeRange4
;
2057 USHORT usFirstCharIndex
;
2058 USHORT usLastCharIndex
;
2059 /* According to the Apple spec, original version didn't have the below fields,
2060 * version numbers were taked from the OpenType spec.
2062 /* version 0 (TrueType 1.5) */
2063 USHORT sTypoAscender
;
2064 USHORT sTypoDescender
;
2065 USHORT sTypoLineGap
;
2067 USHORT usWinDescent
;
2068 /* version 1 (TrueType 1.66) */
2069 ULONG ulCodePageRange1
;
2070 ULONG ulCodePageRange2
;
2071 /* version 2 (OpenType 1.2) */
2074 USHORT usDefaultChar
;
2076 USHORT usMaxContext
;
2078 #include "poppack.h"
2080 #ifdef WORDS_BIGENDIAN
2081 #define GET_BE_WORD(x) (x)
2082 #define GET_BE_DWORD(x) (x)
2084 #define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
2085 #define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x)));
2088 #define MS_MAKE_TAG(ch0, ch1, ch2, ch3) \
2089 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
2090 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24))
2091 #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
2092 #define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
2105 } cmap_encoding_record
;
2113 BYTE glyph_ids
[256];
2123 USHORT search_range
;
2124 USHORT entry_selector
;
2127 USHORT end_count
[1]; /* this is a variable-sized array of length seg_countx2 / 2 */
2130 USHORT start_count[seg_countx2 / 2];
2131 USHORT id_delta[seg_countx2 / 2];
2132 USHORT id_range_offset[seg_countx2 / 2];
2142 USHORT id_range_offset
;
2143 } cmap_format_4_seg
;
2145 static void expect_ff(const TEXTMETRICA
*tmA
, const TT_OS2_V2
*os2
, WORD family
, const char *name
)
2147 ok((tmA
->tmPitchAndFamily
& 0xf0) == family
, "%s: expected family %02x got %02x. panose %d-%d-%d-%d-...\n",
2148 name
, family
, tmA
->tmPitchAndFamily
, os2
->panose
.bFamilyType
, os2
->panose
.bSerifStyle
,
2149 os2
->panose
.bWeight
, os2
->panose
.bProportion
);
2152 static BOOL
get_first_last_from_cmap0(void *ptr
, DWORD
*first
, DWORD
*last
)
2155 cmap_format_0
*cmap
= (cmap_format_0
*)ptr
;
2159 for(i
= 0; i
< 256; i
++)
2161 if(cmap
->glyph_ids
[i
] == 0) continue;
2163 if(*first
== 256) *first
= i
;
2165 if(*first
== 256) return FALSE
;
2169 static void get_seg4(cmap_format_4
*cmap
, USHORT seg_num
, cmap_format_4_seg
*seg
)
2171 USHORT segs
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2172 seg
->end_count
= GET_BE_WORD(cmap
->end_count
[seg_num
]);
2173 seg
->start_count
= GET_BE_WORD(cmap
->end_count
[segs
+ 1 + seg_num
]);
2174 seg
->id_delta
= GET_BE_WORD(cmap
->end_count
[2 * segs
+ 1 + seg_num
]);
2175 seg
->id_range_offset
= GET_BE_WORD(cmap
->end_count
[3 * segs
+ 1 + seg_num
]);
2178 static BOOL
get_first_last_from_cmap4(void *ptr
, DWORD
*first
, DWORD
*last
, DWORD limit
)
2181 cmap_format_4
*cmap
= (cmap_format_4
*)ptr
;
2182 USHORT seg_count
= GET_BE_WORD(cmap
->seg_countx2
) / 2;
2183 USHORT
const *glyph_ids
= cmap
->end_count
+ 4 * seg_count
+ 1;
2187 for(i
= 0; i
< seg_count
; i
++)
2190 cmap_format_4_seg seg
;
2192 get_seg4(cmap
, i
, &seg
);
2193 for(code
= seg
.start_count
; code
<= seg
.end_count
; code
++)
2195 if(seg
.id_range_offset
== 0)
2196 index
= (seg
.id_delta
+ code
) & 0xffff;
2199 index
= seg
.id_range_offset
/ 2
2200 + code
- seg
.start_count
2203 /* some fonts have broken last segment */
2204 if ((char *)(glyph_ids
+ index
+ sizeof(*glyph_ids
)) < (char *)ptr
+ limit
)
2205 index
= GET_BE_WORD(glyph_ids
[index
]);
2208 trace("segment %04x/%04x index %04x points to nowhere\n",
2209 seg
.start_count
, seg
.end_count
, index
);
2212 if(index
) index
+= seg
.id_delta
;
2214 if(*first
== 0x10000)
2215 *last
= *first
= code
;
2221 if(*first
== 0x10000) return FALSE
;
2225 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2228 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2230 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2232 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2233 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2246 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2249 cmap_header
*header
;
2254 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2255 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2256 if(size
== GDI_ERROR
) return FALSE
;
2258 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2259 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2260 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2261 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2263 cmap
= get_cmap(header
, 3, 1);
2265 *cmap_type
= cmap_ms_unicode
;
2268 cmap
= get_cmap(header
, 3, 0);
2269 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2273 *cmap_type
= cmap_none
;
2277 format
= GET_BE_WORD(*(WORD
*)cmap
);
2281 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2284 r
= get_first_last_from_cmap4(cmap
, first
, last
, size
);
2287 trace("unhandled cmap format %d\n", format
);
2292 HeapFree(GetProcessHeap(), 0, header
);
2296 static void test_text_metrics(const LOGFONTA
*lf
)
2299 HFONT hfont
, hfont_old
;
2303 const char *font_name
= lf
->lfFaceName
;
2304 DWORD cmap_first
= 0, cmap_last
= 0;
2305 cmap_type cmap_type
;
2309 SetLastError(0xdeadbeef);
2310 hfont
= CreateFontIndirectA(lf
);
2311 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2313 hfont_old
= SelectObject(hdc
, hfont
);
2315 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2316 if (size
== GDI_ERROR
)
2318 trace("OS/2 chunk was not found\n");
2321 if (size
> sizeof(tt_os2
))
2323 trace("got too large OS/2 chunk of size %u\n", size
);
2324 size
= sizeof(tt_os2
);
2327 memset(&tt_os2
, 0, sizeof(tt_os2
));
2328 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2329 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2331 SetLastError(0xdeadbeef);
2332 ret
= GetTextMetricsA(hdc
, &tmA
);
2333 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2335 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
2337 skip("Unable to retrieve first and last glyphs from cmap\n");
2341 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
2342 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
2343 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
2347 version
= GET_BE_WORD(tt_os2
.version
);
2349 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2350 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2351 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2352 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2354 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2355 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
2356 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
2358 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
2363 case 1257: /* Baltic */
2364 expect_last_W
= 0xf8fd;
2367 expect_last_W
= 0xf0ff;
2369 expect_break_W
= 0x20;
2370 expect_default_W
= expect_break_W
- 1;
2371 expect_first_A
= 0x1e;
2372 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
2376 expect_first_W
= cmap_first
;
2377 expect_last_W
= min(cmap_last
, os2_last_char
);
2378 if(os2_first_char
<= 1)
2379 expect_break_W
= os2_first_char
+ 2;
2380 else if(os2_first_char
> 0xff)
2381 expect_break_W
= 0x20;
2383 expect_break_W
= os2_first_char
;
2384 expect_default_W
= expect_break_W
- 1;
2385 expect_first_A
= expect_default_W
- 1;
2386 expect_last_A
= min(expect_last_W
, 0xff);
2388 expect_break_A
= expect_break_W
;
2389 expect_default_A
= expect_default_W
;
2391 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2392 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
2393 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
2394 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2395 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2397 ok(tmA
.tmFirstChar
== expect_first_A
||
2398 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2399 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2400 ok(tmA
.tmLastChar
== expect_last_A
||
2401 tmA
.tmLastChar
== 0xff /* win9x */,
2402 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
2403 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
2404 font_name
, tmA
.tmBreakChar
, expect_break_A
);
2405 ok(tmA
.tmDefaultChar
== expect_default_A
, "A: tmDefaultChar for %s got %02x expected %02x\n",
2406 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
2409 SetLastError(0xdeadbeef);
2410 ret
= GetTextMetricsW(hdc
, &tmW
);
2411 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2412 "GetTextMetricsW error %u\n", GetLastError());
2415 /* Wine uses the os2 first char */
2416 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
2417 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2418 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2420 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2421 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2423 /* Wine uses the os2 last char */
2424 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
2425 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2426 font_name
, tmW
.tmLastChar
, expect_last_W
);
2428 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2429 font_name
, tmW
.tmLastChar
, expect_last_W
);
2430 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
2431 font_name
, tmW
.tmBreakChar
, expect_break_W
);
2432 ok(tmW
.tmDefaultChar
== expect_default_W
, "W: tmDefaultChar for %s got %02x expected %02x\n",
2433 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
2435 /* Test the aspect ratio while we have tmW */
2436 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2437 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2438 tmW
.tmDigitizedAspectX
, ret
);
2439 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2440 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2441 tmW
.tmDigitizedAspectX
, ret
);
2445 /* test FF_ values */
2446 switch(tt_os2
.panose
.bFamilyType
)
2450 case PAN_FAMILY_TEXT_DISPLAY
:
2451 case PAN_FAMILY_PICTORIAL
:
2453 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
2454 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
2456 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
2459 switch(tt_os2
.panose
.bSerifStyle
)
2464 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
2467 case PAN_SERIF_COVE
:
2468 case PAN_SERIF_OBTUSE_COVE
:
2469 case PAN_SERIF_SQUARE_COVE
:
2470 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
2471 case PAN_SERIF_SQUARE
:
2472 case PAN_SERIF_THIN
:
2473 case PAN_SERIF_BONE
:
2474 case PAN_SERIF_EXAGGERATED
:
2475 case PAN_SERIF_TRIANGLE
:
2476 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
2479 case PAN_SERIF_NORMAL_SANS
:
2480 case PAN_SERIF_OBTUSE_SANS
:
2481 case PAN_SERIF_PERP_SANS
:
2482 case PAN_SERIF_FLARED
:
2483 case PAN_SERIF_ROUNDED
:
2484 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
2489 case PAN_FAMILY_SCRIPT
:
2490 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
2493 case PAN_FAMILY_DECORATIVE
:
2494 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
2498 test_negative_width(hdc
, lf
);
2501 SelectObject(hdc
, hfont_old
);
2502 DeleteObject(hfont
);
2507 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2509 INT
*enumed
= (INT
*)lParam
;
2511 if (type
== TRUETYPE_FONTTYPE
)
2514 test_text_metrics(lf
);
2519 static void test_GetTextMetrics(void)
2525 /* Report only once */
2526 if(!pGetGlyphIndicesA
)
2527 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2531 memset(&lf
, 0, sizeof(lf
));
2532 lf
.lfCharSet
= DEFAULT_CHARSET
;
2534 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2535 trace("Tested metrics of %d truetype fonts\n", enumed
);
2540 static void test_nonexistent_font(void)
2548 { "Times New Roman Baltic", 186 },
2549 { "Times New Roman CE", 238 },
2550 { "Times New Roman CYR", 204 },
2551 { "Times New Roman Greek", 161 },
2552 { "Times New Roman TUR", 162 }
2558 INT cs
, expected_cs
, i
;
2559 char buf
[LF_FACESIZE
];
2561 if (!is_truetype_font_installed("Arial") ||
2562 !is_truetype_font_installed("Times New Roman"))
2564 skip("Arial or Times New Roman not installed\n");
2568 expected_cs
= GetACP();
2569 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
2571 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
2574 expected_cs
= csi
.ciCharset
;
2575 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
2579 memset(&lf
, 0, sizeof(lf
));
2581 lf
.lfWeight
= FW_REGULAR
;
2582 lf
.lfCharSet
= ANSI_CHARSET
;
2583 lf
.lfPitchAndFamily
= FF_SWISS
;
2584 strcpy(lf
.lfFaceName
, "Nonexistent font");
2585 hfont
= CreateFontIndirectA(&lf
);
2586 hfont
= SelectObject(hdc
, hfont
);
2587 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2588 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
2589 cs
= GetTextCharset(hdc
);
2590 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2591 DeleteObject(SelectObject(hdc
, hfont
));
2593 memset(&lf
, 0, sizeof(lf
));
2595 lf
.lfWeight
= FW_DONTCARE
;
2596 strcpy(lf
.lfFaceName
, "Nonexistent font");
2597 hfont
= CreateFontIndirectA(&lf
);
2598 hfont
= SelectObject(hdc
, hfont
);
2599 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2600 todo_wine
/* Wine uses Arial for all substitutions */
2601 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
2602 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
2603 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2605 cs
= GetTextCharset(hdc
);
2606 ok(cs
== expected_cs
, "expected %d, got %d\n", expected_cs
, cs
);
2607 DeleteObject(SelectObject(hdc
, hfont
));
2609 memset(&lf
, 0, sizeof(lf
));
2611 lf
.lfWeight
= FW_REGULAR
;
2612 strcpy(lf
.lfFaceName
, "Nonexistent font");
2613 hfont
= CreateFontIndirectA(&lf
);
2614 hfont
= SelectObject(hdc
, hfont
);
2615 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2616 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2617 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
2618 cs
= GetTextCharset(hdc
);
2619 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2620 DeleteObject(SelectObject(hdc
, hfont
));
2622 memset(&lf
, 0, sizeof(lf
));
2624 lf
.lfWeight
= FW_DONTCARE
;
2625 strcpy(lf
.lfFaceName
, "Times New Roman");
2626 hfont
= CreateFontIndirectA(&lf
);
2627 hfont
= SelectObject(hdc
, hfont
);
2628 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2629 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
2630 cs
= GetTextCharset(hdc
);
2631 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2632 DeleteObject(SelectObject(hdc
, hfont
));
2634 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
2636 memset(&lf
, 0, sizeof(lf
));
2638 lf
.lfWeight
= FW_REGULAR
;
2639 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2640 hfont
= CreateFontIndirectA(&lf
);
2641 hfont
= SelectObject(hdc
, hfont
);
2642 cs
= GetTextCharset(hdc
);
2643 if (font_subst
[i
].charset
== expected_cs
)
2645 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2646 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2647 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
2651 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
2652 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2653 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2654 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
2656 DeleteObject(SelectObject(hdc
, hfont
));
2658 memset(&lf
, 0, sizeof(lf
));
2660 lf
.lfWeight
= FW_DONTCARE
;
2661 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2662 hfont
= CreateFontIndirectA(&lf
);
2663 hfont
= SelectObject(hdc
, hfont
);
2664 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2665 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
2666 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
2667 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
2668 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2669 "got %s for font %s\n", buf
, font_subst
[i
].name
);
2670 cs
= GetTextCharset(hdc
);
2671 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2672 DeleteObject(SelectObject(hdc
, hfont
));
2678 static void test_GdiRealizationInfo(void)
2683 HFONT hfont
, hfont_old
;
2686 if(!pGdiRealizationInfo
)
2688 win_skip("GdiRealizationInfo not available\n");
2694 memset(info
, 0xcc, sizeof(info
));
2695 r
= pGdiRealizationInfo(hdc
, info
);
2696 ok(r
!= 0, "ret 0\n");
2697 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
2698 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2700 if (!is_truetype_font_installed("Arial"))
2702 skip("skipping GdiRealizationInfo with truetype font\n");
2706 memset(&lf
, 0, sizeof(lf
));
2707 strcpy(lf
.lfFaceName
, "Arial");
2709 lf
.lfWeight
= FW_NORMAL
;
2710 hfont
= CreateFontIndirectA(&lf
);
2711 hfont_old
= SelectObject(hdc
, hfont
);
2713 memset(info
, 0xcc, sizeof(info
));
2714 r
= pGdiRealizationInfo(hdc
, info
);
2715 ok(r
!= 0, "ret 0\n");
2716 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
2717 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2719 DeleteObject(SelectObject(hdc
, hfont_old
));
2725 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2726 the nul in the count of characters copied when the face name buffer is not
2727 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2728 always includes it. */
2729 static void test_GetTextFace(void)
2731 static const char faceA
[] = "Tahoma";
2732 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
2735 char bufA
[LF_FACESIZE
];
2736 WCHAR bufW
[LF_FACESIZE
];
2741 if(!is_font_installed("Tahoma"))
2743 skip("Tahoma is not installed so skipping this test\n");
2748 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
2749 f
= CreateFontIndirectA(&fA
);
2750 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
2753 g
= SelectObject(dc
, f
);
2754 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
2755 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
2756 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
2758 /* Play with the count arg. */
2760 n
= GetTextFaceA(dc
, 0, bufA
);
2761 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2762 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2765 n
= GetTextFaceA(dc
, 1, bufA
);
2766 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2767 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2769 bufA
[0] = 'x'; bufA
[1] = 'y';
2770 n
= GetTextFaceA(dc
, 2, bufA
);
2771 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
2772 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
2774 n
= GetTextFaceA(dc
, 0, NULL
);
2775 ok(n
== sizeof faceA
||
2776 broken(n
== 0), /* win98, winMe */
2777 "GetTextFaceA returned %d\n", n
);
2779 DeleteObject(SelectObject(dc
, g
));
2780 ReleaseDC(NULL
, dc
);
2783 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
2784 SetLastError(0xdeadbeef);
2785 f
= CreateFontIndirectW(&fW
);
2786 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2788 win_skip("CreateFontIndirectW is not implemented\n");
2791 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
2794 g
= SelectObject(dc
, f
);
2795 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
2796 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2797 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
2799 /* Play with the count arg. */
2801 n
= GetTextFaceW(dc
, 0, bufW
);
2802 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
2803 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2806 n
= GetTextFaceW(dc
, 1, bufW
);
2807 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
2808 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2810 bufW
[0] = 'x'; bufW
[1] = 'y';
2811 n
= GetTextFaceW(dc
, 2, bufW
);
2812 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
2813 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
2815 n
= GetTextFaceW(dc
, 0, NULL
);
2816 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2818 DeleteObject(SelectObject(dc
, g
));
2819 ReleaseDC(NULL
, dc
);
2822 static void test_orientation(void)
2824 static const char test_str
[11] = "Test String";
2827 HFONT hfont
, old_hfont
;
2830 if (!is_truetype_font_installed("Arial"))
2832 skip("Arial is not installed\n");
2836 hdc
= CreateCompatibleDC(0);
2837 memset(&lf
, 0, sizeof(lf
));
2838 lstrcpyA(lf
.lfFaceName
, "Arial");
2840 lf
.lfOrientation
= lf
.lfEscapement
= 900;
2841 hfont
= create_font("orientation", &lf
);
2842 old_hfont
= SelectObject(hdc
, hfont
);
2843 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
2844 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
2845 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
2846 SelectObject(hdc
, old_hfont
);
2847 DeleteObject(hfont
);
2851 static void test_GetGlyphOutline(void)
2853 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
2857 HFONT hfont
, old_hfont
;
2860 if (!is_truetype_font_installed("Tahoma"))
2862 skip("Tahoma is not installed\n");
2866 hdc
= CreateCompatibleDC(0);
2867 memset(&lf
, 0, sizeof(lf
));
2869 lstrcpyA(lf
.lfFaceName
, "Tahoma");
2870 SetLastError(0xdeadbeef);
2871 hfont
= CreateFontIndirectA(&lf
);
2872 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2873 old_hfont
= SelectObject(hdc
, hfont
);
2875 memset(&gm
, 0, sizeof(gm
));
2876 SetLastError(0xdeadbeef);
2877 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2878 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
2880 memset(&gm
, 0, sizeof(gm
));
2881 SetLastError(0xdeadbeef);
2882 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2883 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
2884 ok(GetLastError() == 0xdeadbeef ||
2885 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
2886 "expected 0xdeadbeef, got %u\n", GetLastError());
2888 memset(&gm
, 0, sizeof(gm
));
2889 SetLastError(0xdeadbeef);
2890 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2891 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2892 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
2894 memset(&gm
, 0, sizeof(gm
));
2895 SetLastError(0xdeadbeef);
2896 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2897 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2899 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
2900 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2903 /* test for needed buffer size request on space char */
2904 memset(&gm
, 0, sizeof(gm
));
2905 SetLastError(0xdeadbeef);
2906 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
2907 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2908 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
2910 /* requesting buffer size for space char + error */
2911 memset(&gm
, 0, sizeof(gm
));
2912 SetLastError(0xdeadbeef);
2913 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
2914 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2916 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
2917 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2920 SelectObject(hdc
, old_hfont
);
2921 DeleteObject(hfont
);
2925 /* bug #9995: there is a limit to the character width that can be specified */
2926 static void test_GetTextMetrics2(const char *fontname
, int font_height
)
2932 int ave_width
, height
, width
, ratio
, scale
;
2934 if (!is_truetype_font_installed( fontname
)) {
2935 skip("%s is not installed\n", fontname
);
2938 hdc
= CreateCompatibleDC(0);
2939 ok( hdc
!= NULL
, "CreateCompatibleDC failed\n");
2940 /* select width = 0 */
2941 hf
= CreateFontA(font_height
, 0, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
2942 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
2943 DEFAULT_QUALITY
, VARIABLE_PITCH
,
2945 ok( hf
!= NULL
, "CreateFontA failed\n");
2946 of
= SelectObject( hdc
, hf
);
2947 ret
= GetTextMetricsA( hdc
, &tm
);
2948 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2949 height
= tm
.tmHeight
;
2950 ave_width
= tm
.tmAveCharWidth
;
2951 SelectObject( hdc
, of
);
2954 trace("height %d, ave width %d\n", height
, ave_width
);
2956 for (width
= ave_width
* 2; /* nothing*/; width
+= ave_width
)
2958 hf
= CreateFont(height
, width
, 0, 0, FW_REGULAR
, FALSE
, FALSE
, FALSE
,
2959 DEFAULT_CHARSET
, OUT_TT_PRECIS
, CLIP_LH_ANGLES
,
2960 DEFAULT_QUALITY
, VARIABLE_PITCH
, fontname
);
2961 ok(hf
!= 0, "CreateFont failed\n");
2962 of
= SelectObject(hdc
, hf
);
2963 ret
= GetTextMetrics(hdc
, &tm
);
2964 ok(ret
, "GetTextMetrics error %u\n", GetLastError());
2965 SelectObject(hdc
, of
);
2968 if (tm
.tmAveCharWidth
== ave_width
|| width
/ height
> 200)
2974 ratio
= width
/ height
;
2975 scale
= width
/ ave_width
;
2977 trace("max width/height ratio (%d / %d) %d, max width scale (%d / %d) %d\n",
2978 width
, height
, ratio
, width
, ave_width
, scale
);
2980 ok(ratio
>= 90 && ratio
<= 110, "expected width/height ratio 90-110, got %d\n", ratio
);
2988 test_outline_font();
2989 test_bitmap_font_metrics();
2990 test_GdiGetCharDimensions();
2991 test_GetCharABCWidths();
2992 test_text_extents();
2993 test_GetGlyphIndices();
2994 test_GetKerningPairs();
2995 test_GetOutlineTextMetrics();
2996 test_SetTextJustification();
2997 test_font_charset();
2998 test_GetFontUnicodeRanges();
2999 test_nonexistent_font();
3002 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
3003 * I'd like to avoid them in this test.
3005 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
3006 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
3007 if (is_truetype_font_installed("Arial Black") &&
3008 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
3010 test_EnumFontFamilies("", ANSI_CHARSET
);
3011 test_EnumFontFamilies("", SYMBOL_CHARSET
);
3012 test_EnumFontFamilies("", DEFAULT_CHARSET
);
3015 skip("Arial Black or Symbol/Wingdings is not installed\n");
3016 test_GetTextMetrics();
3017 test_GdiRealizationInfo();
3019 test_GetGlyphOutline();
3020 test_GetTextMetrics2("Tahoma", -11);
3021 test_GetTextMetrics2("Tahoma", -55);
3022 test_GetTextMetrics2("Tahoma", -110);
3023 test_GetTextMetrics2("Arial", -11);
3024 test_GetTextMetrics2("Arial", -55);
3025 test_GetTextMetrics2("Arial", -110);