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
)
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 index
= GET_BE_WORD(glyph_ids
[index
]);
2204 if(index
) index
+= seg
.id_delta
;
2206 if(*first
== 0x10000)
2207 *last
= *first
= code
;
2213 if(*first
== 0x10000) return FALSE
;
2217 static void *get_cmap(cmap_header
*header
, USHORT plat_id
, USHORT enc_id
)
2220 cmap_encoding_record
*record
= (cmap_encoding_record
*)(header
+ 1);
2222 for(i
= 0; i
< GET_BE_WORD(header
->num_tables
); i
++)
2224 if(GET_BE_WORD(record
->plat_id
) == plat_id
&& GET_BE_WORD(record
->enc_id
) == enc_id
)
2225 return (BYTE
*)header
+ GET_BE_DWORD(record
->offset
);
2238 static BOOL
get_first_last_from_cmap(HDC hdc
, DWORD
*first
, DWORD
*last
, cmap_type
*cmap_type
)
2241 cmap_header
*header
;
2246 size
= GetFontData(hdc
, MS_CMAP_TAG
, 0, NULL
, 0);
2247 ok(size
!= GDI_ERROR
, "no cmap table found\n");
2248 if(size
== GDI_ERROR
) return FALSE
;
2250 header
= HeapAlloc(GetProcessHeap(), 0, size
);
2251 ret
= GetFontData(hdc
, MS_CMAP_TAG
, 0, header
, size
);
2252 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2253 ok(GET_BE_WORD(header
->version
) == 0, "got cmap version %d\n", GET_BE_WORD(header
->version
));
2255 cmap
= get_cmap(header
, 3, 1);
2257 *cmap_type
= cmap_ms_unicode
;
2260 cmap
= get_cmap(header
, 3, 0);
2261 if(cmap
) *cmap_type
= cmap_ms_symbol
;
2265 *cmap_type
= cmap_none
;
2269 format
= GET_BE_WORD(*(WORD
*)cmap
);
2273 r
= get_first_last_from_cmap0(cmap
, first
, last
);
2276 r
= get_first_last_from_cmap4(cmap
, first
, last
);
2279 trace("unhandled cmap format %d\n", format
);
2284 HeapFree(GetProcessHeap(), 0, header
);
2288 static void test_text_metrics(const LOGFONTA
*lf
)
2291 HFONT hfont
, hfont_old
;
2295 const char *font_name
= lf
->lfFaceName
;
2296 DWORD cmap_first
= 0, cmap_last
= 0;
2297 cmap_type cmap_type
;
2301 SetLastError(0xdeadbeef);
2302 hfont
= CreateFontIndirectA(lf
);
2303 ok(hfont
!= 0, "CreateFontIndirect error %u\n", GetLastError());
2305 hfont_old
= SelectObject(hdc
, hfont
);
2307 size
= GetFontData(hdc
, MS_OS2_TAG
, 0, NULL
, 0);
2308 if (size
== GDI_ERROR
)
2310 trace("OS/2 chunk was not found\n");
2313 if (size
> sizeof(tt_os2
))
2315 trace("got too large OS/2 chunk of size %u\n", size
);
2316 size
= sizeof(tt_os2
);
2319 memset(&tt_os2
, 0, sizeof(tt_os2
));
2320 ret
= GetFontData(hdc
, MS_OS2_TAG
, 0, &tt_os2
, size
);
2321 ok(ret
== size
, "GetFontData should return %u not %u\n", size
, ret
);
2323 SetLastError(0xdeadbeef);
2324 ret
= GetTextMetricsA(hdc
, &tmA
);
2325 ok(ret
, "GetTextMetricsA error %u\n", GetLastError());
2327 if(!get_first_last_from_cmap(hdc
, &cmap_first
, &cmap_last
, &cmap_type
))
2329 skip("Unable to retrieve first and last glyphs from cmap\n");
2333 USHORT expect_first_A
, expect_last_A
, expect_break_A
, expect_default_A
;
2334 USHORT expect_first_W
, expect_last_W
, expect_break_W
, expect_default_W
;
2335 UINT os2_first_char
, os2_last_char
, default_char
, break_char
;
2339 version
= GET_BE_WORD(tt_os2
.version
);
2341 os2_first_char
= GET_BE_WORD(tt_os2
.usFirstCharIndex
);
2342 os2_last_char
= GET_BE_WORD(tt_os2
.usLastCharIndex
);
2343 default_char
= GET_BE_WORD(tt_os2
.usDefaultChar
);
2344 break_char
= GET_BE_WORD(tt_os2
.usBreakChar
);
2346 trace("font %s charset %u: %x-%x (%x-%x) default %x break %x OS/2 version %u vendor %4.4s\n",
2347 font_name
, lf
->lfCharSet
, os2_first_char
, os2_last_char
, cmap_first
, cmap_last
,
2348 default_char
, break_char
, version
, (LPCSTR
)&tt_os2
.achVendID
);
2350 if (cmap_type
== cmap_ms_symbol
|| (cmap_first
>= 0xf000 && cmap_first
< 0xf100))
2355 case 1257: /* Baltic */
2356 expect_last_W
= 0xf8fd;
2359 expect_last_W
= 0xf0ff;
2361 expect_break_W
= 0x20;
2362 expect_default_W
= expect_break_W
- 1;
2363 expect_first_A
= 0x1e;
2364 expect_last_A
= min(os2_last_char
- os2_first_char
+ 0x20, 0xff);
2368 expect_first_W
= cmap_first
;
2369 expect_last_W
= min(cmap_last
, os2_last_char
);
2370 if(os2_first_char
<= 1)
2371 expect_break_W
= os2_first_char
+ 2;
2372 else if(os2_first_char
> 0xff)
2373 expect_break_W
= 0x20;
2375 expect_break_W
= os2_first_char
;
2376 expect_default_W
= expect_break_W
- 1;
2377 expect_first_A
= expect_default_W
- 1;
2378 expect_last_A
= min(expect_last_W
, 0xff);
2380 expect_break_A
= expect_break_W
;
2381 expect_default_A
= expect_default_W
;
2383 /* Wine currently uses SYMBOL_CHARSET to identify whether the ANSI metrics need special handling */
2384 if(cmap_type
!= cmap_ms_symbol
&& tmA
.tmCharSet
== SYMBOL_CHARSET
&& expect_first_A
!= 0x1e)
2385 todo_wine
ok(tmA
.tmFirstChar
== expect_first_A
||
2386 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2387 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2389 ok(tmA
.tmFirstChar
== expect_first_A
||
2390 tmA
.tmFirstChar
== expect_first_A
+ 1 /* win9x */,
2391 "A: tmFirstChar for %s got %02x expected %02x\n", font_name
, tmA
.tmFirstChar
, expect_first_A
);
2392 ok(tmA
.tmLastChar
== expect_last_A
||
2393 tmA
.tmLastChar
== 0xff /* win9x */,
2394 "A: tmLastChar for %s got %02x expected %02x\n", font_name
, tmA
.tmLastChar
, expect_last_A
);
2395 ok(tmA
.tmBreakChar
== expect_break_A
, "A: tmBreakChar for %s got %02x expected %02x\n",
2396 font_name
, tmA
.tmBreakChar
, expect_break_A
);
2397 ok(tmA
.tmDefaultChar
== expect_default_A
, "A: tmDefaultChar for %s got %02x expected %02x\n",
2398 font_name
, tmA
.tmDefaultChar
, expect_default_A
);
2401 SetLastError(0xdeadbeef);
2402 ret
= GetTextMetricsW(hdc
, &tmW
);
2403 ok(ret
|| GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
,
2404 "GetTextMetricsW error %u\n", GetLastError());
2407 /* Wine uses the os2 first char */
2408 if(cmap_first
!= os2_first_char
&& cmap_type
!= cmap_ms_symbol
)
2409 todo_wine
ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2410 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2412 ok(tmW
.tmFirstChar
== expect_first_W
, "W: tmFirstChar for %s got %02x expected %02x\n",
2413 font_name
, tmW
.tmFirstChar
, expect_first_W
);
2415 /* Wine uses the os2 last char */
2416 if(expect_last_W
!= os2_last_char
&& cmap_type
!= cmap_ms_symbol
)
2417 todo_wine
ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2418 font_name
, tmW
.tmLastChar
, expect_last_W
);
2420 ok(tmW
.tmLastChar
== expect_last_W
, "W: tmLastChar for %s got %02x expected %02x\n",
2421 font_name
, tmW
.tmLastChar
, expect_last_W
);
2422 ok(tmW
.tmBreakChar
== expect_break_W
, "W: tmBreakChar for %s got %02x expected %02x\n",
2423 font_name
, tmW
.tmBreakChar
, expect_break_W
);
2424 ok(tmW
.tmDefaultChar
== expect_default_W
, "W: tmDefaultChar for %s got %02x expected %02x\n",
2425 font_name
, tmW
.tmDefaultChar
, expect_default_W
);
2427 /* Test the aspect ratio while we have tmW */
2428 ret
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2429 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectX %u != %u\n",
2430 tmW
.tmDigitizedAspectX
, ret
);
2431 ret
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2432 ok(tmW
.tmDigitizedAspectX
== ret
, "W: tmDigitizedAspectY %u != %u\n",
2433 tmW
.tmDigitizedAspectX
, ret
);
2437 /* test FF_ values */
2438 switch(tt_os2
.panose
.bFamilyType
)
2442 case PAN_FAMILY_TEXT_DISPLAY
:
2443 case PAN_FAMILY_PICTORIAL
:
2445 if((tmA
.tmPitchAndFamily
& 1) == 0 || /* fixed */
2446 tt_os2
.panose
.bProportion
== PAN_PROP_MONOSPACED
)
2448 expect_ff(&tmA
, &tt_os2
, FF_MODERN
, font_name
);
2451 switch(tt_os2
.panose
.bSerifStyle
)
2456 expect_ff(&tmA
, &tt_os2
, FF_DONTCARE
, font_name
);
2459 case PAN_SERIF_COVE
:
2460 case PAN_SERIF_OBTUSE_COVE
:
2461 case PAN_SERIF_SQUARE_COVE
:
2462 case PAN_SERIF_OBTUSE_SQUARE_COVE
:
2463 case PAN_SERIF_SQUARE
:
2464 case PAN_SERIF_THIN
:
2465 case PAN_SERIF_BONE
:
2466 case PAN_SERIF_EXAGGERATED
:
2467 case PAN_SERIF_TRIANGLE
:
2468 expect_ff(&tmA
, &tt_os2
, FF_ROMAN
, font_name
);
2471 case PAN_SERIF_NORMAL_SANS
:
2472 case PAN_SERIF_OBTUSE_SANS
:
2473 case PAN_SERIF_PERP_SANS
:
2474 case PAN_SERIF_FLARED
:
2475 case PAN_SERIF_ROUNDED
:
2476 expect_ff(&tmA
, &tt_os2
, FF_SWISS
, font_name
);
2481 case PAN_FAMILY_SCRIPT
:
2482 expect_ff(&tmA
, &tt_os2
, FF_SCRIPT
, font_name
);
2485 case PAN_FAMILY_DECORATIVE
:
2486 expect_ff(&tmA
, &tt_os2
, FF_DECORATIVE
, font_name
);
2490 test_negative_width(hdc
, lf
);
2493 SelectObject(hdc
, hfont_old
);
2494 DeleteObject(hfont
);
2499 static INT CALLBACK
enum_truetype_font_proc(const LOGFONT
*lf
, const TEXTMETRIC
*ntm
, DWORD type
, LPARAM lParam
)
2501 INT
*enumed
= (INT
*)lParam
;
2503 if (type
== TRUETYPE_FONTTYPE
)
2506 test_text_metrics(lf
);
2511 static void test_GetTextMetrics(void)
2517 /* Report only once */
2518 if(!pGetGlyphIndicesA
)
2519 win_skip("GetGlyphIndicesA is unavailable, negative width will not be checked\n");
2523 memset(&lf
, 0, sizeof(lf
));
2524 lf
.lfCharSet
= DEFAULT_CHARSET
;
2526 EnumFontFamiliesExA(hdc
, &lf
, enum_truetype_font_proc
, (LPARAM
)&enumed
, 0);
2527 trace("Tested metrics of %d truetype fonts\n", enumed
);
2532 static void test_nonexistent_font(void)
2540 { "Times New Roman Baltic", 186 },
2541 { "Times New Roman CE", 238 },
2542 { "Times New Roman CYR", 204 },
2543 { "Times New Roman Greek", 161 },
2544 { "Times New Roman TUR", 162 }
2550 INT cs
, expected_cs
, i
;
2551 char buf
[LF_FACESIZE
];
2553 if (!is_truetype_font_installed("Arial") ||
2554 !is_truetype_font_installed("Times New Roman"))
2556 skip("Arial or Times New Roman not installed\n");
2560 expected_cs
= GetACP();
2561 if (!TranslateCharsetInfo(ULongToPtr(expected_cs
), &csi
, TCI_SRCCODEPAGE
))
2563 skip("TranslateCharsetInfo failed for code page %d\n", expected_cs
);
2566 expected_cs
= csi
.ciCharset
;
2567 trace("ACP %d -> charset %d\n", GetACP(), expected_cs
);
2571 memset(&lf
, 0, sizeof(lf
));
2573 lf
.lfWeight
= FW_REGULAR
;
2574 lf
.lfCharSet
= ANSI_CHARSET
;
2575 lf
.lfPitchAndFamily
= FF_SWISS
;
2576 strcpy(lf
.lfFaceName
, "Nonexistent font");
2577 hfont
= CreateFontIndirectA(&lf
);
2578 hfont
= SelectObject(hdc
, hfont
);
2579 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2580 ok(!lstrcmpiA(buf
, "Arial"), "Got %s\n", buf
);
2581 cs
= GetTextCharset(hdc
);
2582 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2583 DeleteObject(SelectObject(hdc
, hfont
));
2585 memset(&lf
, 0, sizeof(lf
));
2587 lf
.lfWeight
= FW_DONTCARE
;
2588 strcpy(lf
.lfFaceName
, "Nonexistent font");
2589 hfont
= CreateFontIndirectA(&lf
);
2590 hfont
= SelectObject(hdc
, hfont
);
2591 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2592 todo_wine
/* Wine uses Arial for all substitutions */
2593 ok(!lstrcmpiA(buf
, "Nonexistent font") /* XP, Vista */ ||
2594 !lstrcmpiA(buf
, "MS Serif") || /* Win9x */
2595 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2597 cs
= GetTextCharset(hdc
);
2598 ok(cs
== expected_cs
, "expected %d, got %d\n", expected_cs
, cs
);
2599 DeleteObject(SelectObject(hdc
, hfont
));
2601 memset(&lf
, 0, sizeof(lf
));
2603 lf
.lfWeight
= FW_REGULAR
;
2604 strcpy(lf
.lfFaceName
, "Nonexistent font");
2605 hfont
= CreateFontIndirectA(&lf
);
2606 hfont
= SelectObject(hdc
, hfont
);
2607 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2608 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2609 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "Got %s\n", buf
);
2610 cs
= GetTextCharset(hdc
);
2611 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2612 DeleteObject(SelectObject(hdc
, hfont
));
2614 memset(&lf
, 0, sizeof(lf
));
2616 lf
.lfWeight
= FW_DONTCARE
;
2617 strcpy(lf
.lfFaceName
, "Times New Roman");
2618 hfont
= CreateFontIndirectA(&lf
);
2619 hfont
= SelectObject(hdc
, hfont
);
2620 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2621 ok(!lstrcmpiA(buf
, "Times New Roman"), "Got %s\n", buf
);
2622 cs
= GetTextCharset(hdc
);
2623 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d\n", cs
);
2624 DeleteObject(SelectObject(hdc
, hfont
));
2626 for (i
= 0; i
< sizeof(font_subst
)/sizeof(font_subst
[0]); i
++)
2628 memset(&lf
, 0, sizeof(lf
));
2630 lf
.lfWeight
= FW_REGULAR
;
2631 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2632 hfont
= CreateFontIndirectA(&lf
);
2633 hfont
= SelectObject(hdc
, hfont
);
2634 cs
= GetTextCharset(hdc
);
2635 if (font_subst
[i
].charset
== expected_cs
)
2637 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2638 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2639 ok(!lstrcmpiA(buf
, font_subst
[i
].name
), "expected %s, got %s\n", font_subst
[i
].name
, buf
);
2643 ok(cs
== ANSI_CHARSET
, "expected ANSI_CHARSET, got %d for font %s\n", cs
, font_subst
[i
].name
);
2644 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2645 ok(!lstrcmpiA(buf
, "Arial") /* XP, Vista */ ||
2646 !lstrcmpiA(buf
, "Times New Roman") /* Win9x */, "got %s for font %s\n", buf
, font_subst
[i
].name
);
2648 DeleteObject(SelectObject(hdc
, hfont
));
2650 memset(&lf
, 0, sizeof(lf
));
2652 lf
.lfWeight
= FW_DONTCARE
;
2653 strcpy(lf
.lfFaceName
, font_subst
[i
].name
);
2654 hfont
= CreateFontIndirectA(&lf
);
2655 hfont
= SelectObject(hdc
, hfont
);
2656 GetTextFaceA(hdc
, sizeof(buf
), buf
);
2657 ok(!lstrcmpiA(buf
, "Arial") /* Wine */ ||
2658 !lstrcmpiA(buf
, font_subst
[i
].name
) /* XP, Vista */ ||
2659 !lstrcmpiA(buf
, "MS Serif") /* Win9x */ ||
2660 !lstrcmpiA(buf
, "MS Sans Serif"), /* win2k3 */
2661 "got %s for font %s\n", buf
, font_subst
[i
].name
);
2662 cs
= GetTextCharset(hdc
);
2663 ok(cs
== expected_cs
, "expected %d, got %d for font %s\n", expected_cs
, cs
, font_subst
[i
].name
);
2664 DeleteObject(SelectObject(hdc
, hfont
));
2670 static void test_GdiRealizationInfo(void)
2675 HFONT hfont
, hfont_old
;
2678 if(!pGdiRealizationInfo
)
2680 win_skip("GdiRealizationInfo not available\n");
2686 memset(info
, 0xcc, sizeof(info
));
2687 r
= pGdiRealizationInfo(hdc
, info
);
2688 ok(r
!= 0, "ret 0\n");
2689 ok((info
[0] & 0xf) == 1, "info[0] = %x for the system font\n", info
[0]);
2690 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2692 if (!is_truetype_font_installed("Arial"))
2694 skip("skipping GdiRealizationInfo with truetype font\n");
2698 memset(&lf
, 0, sizeof(lf
));
2699 strcpy(lf
.lfFaceName
, "Arial");
2701 lf
.lfWeight
= FW_NORMAL
;
2702 hfont
= CreateFontIndirectA(&lf
);
2703 hfont_old
= SelectObject(hdc
, hfont
);
2705 memset(info
, 0xcc, sizeof(info
));
2706 r
= pGdiRealizationInfo(hdc
, info
);
2707 ok(r
!= 0, "ret 0\n");
2708 ok((info
[0] & 0xf) == 3, "info[0] = %x for arial\n", info
[0]);
2709 ok(info
[3] == 0xcccccccc, "structure longer than 3 dwords\n");
2711 DeleteObject(SelectObject(hdc
, hfont_old
));
2717 /* Tests on XP SP2 show that the ANSI version of GetTextFace does NOT include
2718 the nul in the count of characters copied when the face name buffer is not
2719 NULL, whereas it does if the buffer is NULL. Further, the Unicode version
2720 always includes it. */
2721 static void test_GetTextFace(void)
2723 static const char faceA
[] = "Tahoma";
2724 static const WCHAR faceW
[] = {'T','a','h','o','m','a', 0};
2727 char bufA
[LF_FACESIZE
];
2728 WCHAR bufW
[LF_FACESIZE
];
2733 if(!is_font_installed("Tahoma"))
2735 skip("Tahoma is not installed so skipping this test\n");
2740 memcpy(fA
.lfFaceName
, faceA
, sizeof faceA
);
2741 f
= CreateFontIndirectA(&fA
);
2742 ok(f
!= NULL
, "CreateFontIndirectA failed\n");
2745 g
= SelectObject(dc
, f
);
2746 n
= GetTextFaceA(dc
, sizeof bufA
, bufA
);
2747 ok(n
== sizeof faceA
- 1, "GetTextFaceA returned %d\n", n
);
2748 ok(lstrcmpA(faceA
, bufA
) == 0, "GetTextFaceA\n");
2750 /* Play with the count arg. */
2752 n
= GetTextFaceA(dc
, 0, bufA
);
2753 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2754 ok(bufA
[0] == 'x', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2757 n
= GetTextFaceA(dc
, 1, bufA
);
2758 ok(n
== 0, "GetTextFaceA returned %d\n", n
);
2759 ok(bufA
[0] == '\0', "GetTextFaceA buf[0] == %d\n", bufA
[0]);
2761 bufA
[0] = 'x'; bufA
[1] = 'y';
2762 n
= GetTextFaceA(dc
, 2, bufA
);
2763 ok(n
== 1, "GetTextFaceA returned %d\n", n
);
2764 ok(bufA
[0] == faceA
[0] && bufA
[1] == '\0', "GetTextFaceA didn't copy\n");
2766 n
= GetTextFaceA(dc
, 0, NULL
);
2767 ok(n
== sizeof faceA
||
2768 broken(n
== 0), /* win98, winMe */
2769 "GetTextFaceA returned %d\n", n
);
2771 DeleteObject(SelectObject(dc
, g
));
2772 ReleaseDC(NULL
, dc
);
2775 memcpy(fW
.lfFaceName
, faceW
, sizeof faceW
);
2776 SetLastError(0xdeadbeef);
2777 f
= CreateFontIndirectW(&fW
);
2778 if (!f
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2780 win_skip("CreateFontIndirectW is not implemented\n");
2783 ok(f
!= NULL
, "CreateFontIndirectW failed\n");
2786 g
= SelectObject(dc
, f
);
2787 n
= GetTextFaceW(dc
, sizeof bufW
/ sizeof bufW
[0], bufW
);
2788 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2789 ok(lstrcmpW(faceW
, bufW
) == 0, "GetTextFaceW\n");
2791 /* Play with the count arg. */
2793 n
= GetTextFaceW(dc
, 0, bufW
);
2794 ok(n
== 0, "GetTextFaceW returned %d\n", n
);
2795 ok(bufW
[0] == 'x', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2798 n
= GetTextFaceW(dc
, 1, bufW
);
2799 ok(n
== 1, "GetTextFaceW returned %d\n", n
);
2800 ok(bufW
[0] == '\0', "GetTextFaceW buf[0] == %d\n", bufW
[0]);
2802 bufW
[0] = 'x'; bufW
[1] = 'y';
2803 n
= GetTextFaceW(dc
, 2, bufW
);
2804 ok(n
== 2, "GetTextFaceW returned %d\n", n
);
2805 ok(bufW
[0] == faceW
[0] && bufW
[1] == '\0', "GetTextFaceW didn't copy\n");
2807 n
= GetTextFaceW(dc
, 0, NULL
);
2808 ok(n
== sizeof faceW
/ sizeof faceW
[0], "GetTextFaceW returned %d\n", n
);
2810 DeleteObject(SelectObject(dc
, g
));
2811 ReleaseDC(NULL
, dc
);
2814 static void test_orientation(void)
2816 static const char test_str
[11] = "Test String";
2819 HFONT hfont
, old_hfont
;
2822 if (!is_truetype_font_installed("Arial"))
2824 skip("Arial is not installed\n");
2828 hdc
= CreateCompatibleDC(0);
2829 memset(&lf
, 0, sizeof(lf
));
2830 lstrcpyA(lf
.lfFaceName
, "Arial");
2832 lf
.lfOrientation
= lf
.lfEscapement
= 900;
2833 hfont
= create_font("orientation", &lf
);
2834 old_hfont
= SelectObject(hdc
, hfont
);
2835 ok(GetTextExtentExPointA(hdc
, test_str
, sizeof(test_str
), 32767, NULL
, NULL
, &size
), "GetTextExtentExPointA failed\n");
2836 ok(near_match(311, size
.cx
), "cx should be about 311, got %d\n", size
.cx
);
2837 ok(near_match(75, size
.cy
), "cy should be about 75, got %d\n", size
.cy
);
2838 SelectObject(hdc
, old_hfont
);
2839 DeleteObject(hfont
);
2843 static void test_GetGlyphOutline(void)
2845 MAT2 mat
= { {0,1}, {0,0}, {0,0}, {0,1} };
2849 HFONT hfont
, old_hfont
;
2852 if (!is_truetype_font_installed("Tahoma"))
2854 skip("Tahoma is not installed\n");
2858 hdc
= CreateCompatibleDC(0);
2859 memset(&lf
, 0, sizeof(lf
));
2861 lstrcpyA(lf
.lfFaceName
, "Tahoma");
2862 SetLastError(0xdeadbeef);
2863 hfont
= CreateFontIndirectA(&lf
);
2864 ok(hfont
!= 0, "CreateFontIndirectA error %u\n", GetLastError());
2865 old_hfont
= SelectObject(hdc
, hfont
);
2867 memset(&gm
, 0, sizeof(gm
));
2868 SetLastError(0xdeadbeef);
2869 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2870 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineA error %u\n", GetLastError());
2872 memset(&gm
, 0, sizeof(gm
));
2873 SetLastError(0xdeadbeef);
2874 ret
= GetGlyphOutlineA(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2875 ok(ret
== GDI_ERROR
, "GetGlyphOutlineA should fail\n");
2876 ok(GetLastError() == 0xdeadbeef ||
2877 GetLastError() == ERROR_INVALID_PARAMETER
, /* win98, winMe */
2878 "expected 0xdeadbeef, got %u\n", GetLastError());
2880 memset(&gm
, 0, sizeof(gm
));
2881 SetLastError(0xdeadbeef);
2882 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, &mat
);
2883 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2884 ok(ret
!= GDI_ERROR
, "GetGlyphOutlineW error %u\n", GetLastError());
2886 memset(&gm
, 0, sizeof(gm
));
2887 SetLastError(0xdeadbeef);
2888 ret
= GetGlyphOutlineW(hdc
, 'A', GGO_METRICS
, &gm
, 0, NULL
, NULL
);
2889 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2891 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should fail\n");
2892 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2895 /* test for needed buffer size request on space char */
2896 memset(&gm
, 0, sizeof(gm
));
2897 SetLastError(0xdeadbeef);
2898 ret
= GetGlyphOutlineW(hdc
, ' ', GGO_NATIVE
, &gm
, 0, NULL
, &mat
);
2899 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2900 ok(ret
== 0, "GetGlyphOutlineW should return 0 buffer size for space char\n");
2902 /* requesting buffer size for space char + error */
2903 memset(&gm
, 0, sizeof(gm
));
2904 SetLastError(0xdeadbeef);
2905 ret
= GetGlyphOutlineW(0, ' ', GGO_NATIVE
, &gm
, 0, NULL
, NULL
);
2906 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2908 ok(ret
== GDI_ERROR
, "GetGlyphOutlineW should return GDI_ERROR\n");
2909 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
2912 SelectObject(hdc
, old_hfont
);
2913 DeleteObject(hfont
);
2923 test_outline_font();
2924 test_bitmap_font_metrics();
2925 test_GdiGetCharDimensions();
2926 test_GetCharABCWidths();
2927 test_text_extents();
2928 test_GetGlyphIndices();
2929 test_GetKerningPairs();
2930 test_GetOutlineTextMetrics();
2931 test_SetTextJustification();
2932 test_font_charset();
2933 test_GetFontUnicodeRanges();
2934 test_nonexistent_font();
2937 /* On Windows Arial has a lot of default charset aliases such as Arial Cyr,
2938 * I'd like to avoid them in this test.
2940 test_EnumFontFamilies("Arial Black", ANSI_CHARSET
);
2941 test_EnumFontFamilies("Symbol", SYMBOL_CHARSET
);
2942 if (is_truetype_font_installed("Arial Black") &&
2943 (is_truetype_font_installed("Symbol") || is_truetype_font_installed("Wingdings")))
2945 test_EnumFontFamilies("", ANSI_CHARSET
);
2946 test_EnumFontFamilies("", SYMBOL_CHARSET
);
2947 test_EnumFontFamilies("", DEFAULT_CHARSET
);
2950 skip("Arial Black or Symbol/Wingdings is not installed\n");
2951 test_GetTextMetrics();
2952 test_GdiRealizationInfo();
2954 test_GetGlyphOutline();